module Unison.Sqlite.JournalMode
  ( JournalMode (..),
    trySetJournalMode,
    SetJournalModeException (..),
  )
where

import Data.Text qualified as Text
import Database.SQLite.Simple qualified as Sqlite
import Unison.Prelude
import Unison.Sqlite.Connection
import Unison.Sqlite.Exception (SqliteExceptionReason)
import Unison.Sqlite.Sql (Sql (..))

-- | https://www.sqlite.org/pragma.html#pragma_journal_mode
data JournalMode
  = JournalMode'DELETE
  | JournalMode'TRUNCATE
  | JournalMode'PERSIST
  | JournalMode'MEMORY
  | JournalMode'WAL
  | JournalMode'OFF
  deriving stock (JournalMode -> JournalMode -> Bool
(JournalMode -> JournalMode -> Bool)
-> (JournalMode -> JournalMode -> Bool) -> Eq JournalMode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: JournalMode -> JournalMode -> Bool
== :: JournalMode -> JournalMode -> Bool
$c/= :: JournalMode -> JournalMode -> Bool
/= :: JournalMode -> JournalMode -> Bool
Eq, Int -> JournalMode -> ShowS
[JournalMode] -> ShowS
JournalMode -> String
(Int -> JournalMode -> ShowS)
-> (JournalMode -> String)
-> ([JournalMode] -> ShowS)
-> Show JournalMode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> JournalMode -> ShowS
showsPrec :: Int -> JournalMode -> ShowS
$cshow :: JournalMode -> String
show :: JournalMode -> String
$cshowList :: [JournalMode] -> ShowS
showList :: [JournalMode] -> ShowS
Show)

journalModeFromText :: Text -> Maybe JournalMode
journalModeFromText :: Text -> Maybe JournalMode
journalModeFromText = \case
  Text
"delete" -> JournalMode -> Maybe JournalMode
forall a. a -> Maybe a
Just JournalMode
JournalMode'DELETE
  Text
"truncate" -> JournalMode -> Maybe JournalMode
forall a. a -> Maybe a
Just JournalMode
JournalMode'TRUNCATE
  Text
"persist" -> JournalMode -> Maybe JournalMode
forall a. a -> Maybe a
Just JournalMode
JournalMode'PERSIST
  Text
"memory" -> JournalMode -> Maybe JournalMode
forall a. a -> Maybe a
Just JournalMode
JournalMode'MEMORY
  Text
"wal" -> JournalMode -> Maybe JournalMode
forall a. a -> Maybe a
Just JournalMode
JournalMode'WAL
  Text
"off" -> JournalMode -> Maybe JournalMode
forall a. a -> Maybe a
Just JournalMode
JournalMode'OFF
  Text
_ -> Maybe JournalMode
forall a. Maybe a
Nothing

unsafeJournalModeFromText :: (HasCallStack) => Text -> JournalMode
unsafeJournalModeFromText :: HasCallStack => Text -> JournalMode
unsafeJournalModeFromText Text
s =
  JournalMode -> Maybe JournalMode -> JournalMode
forall a. a -> Maybe a -> a
fromMaybe (String -> JournalMode
forall a. HasCallStack => String -> a
error (String
"Unknown journal mode: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Text -> String
Text.unpack Text
s)) (Text -> Maybe JournalMode
journalModeFromText Text
s)

journalModeToText :: JournalMode -> Text
journalModeToText :: JournalMode -> Text
journalModeToText = \case
  JournalMode
JournalMode'DELETE -> Text
"delete"
  JournalMode
JournalMode'TRUNCATE -> Text
"truncate"
  JournalMode
JournalMode'PERSIST -> Text
"persist"
  JournalMode
JournalMode'MEMORY -> Text
"memory"
  JournalMode
JournalMode'WAL -> Text
"wal"
  JournalMode
JournalMode'OFF -> Text
"off"

trySetJournalMode :: (MonadIO m) => Connection -> JournalMode -> m ()
trySetJournalMode :: forall (m :: * -> *).
MonadIO m =>
Connection -> JournalMode -> m ()
trySetJournalMode Connection
conn JournalMode
mode0 = IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO do
  Connection
-> Sql -> (Only Text -> Either SetJournalModeException ()) -> IO ()
forall a e r.
(FromRow a, SqliteExceptionReason e, HasCallStack) =>
Connection -> Sql -> (a -> Either e r) -> IO r
queryOneRowCheck
    Connection
conn
    (Text -> [SQLData] -> Sql
Sql (Text
"PRAGMA journal_mode = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> JournalMode -> Text
journalModeToText JournalMode
mode0) [])
    \(Sqlite.Only Text
mode1s) ->
      let mode1 :: JournalMode
mode1 = HasCallStack => Text -> JournalMode
Text -> JournalMode
unsafeJournalModeFromText Text
mode1s
       in if JournalMode
mode0 JournalMode -> JournalMode -> Bool
forall a. Eq a => a -> a -> Bool
/= JournalMode
mode1
            then
              SetJournalModeException -> Either SetJournalModeException ()
forall a b. a -> Either a b
Left
                SetJournalModeException
                  { $sel:currentJournalMode:SetJournalModeException :: JournalMode
currentJournalMode = JournalMode
mode1,
                    $sel:couldntSetTo:SetJournalModeException :: JournalMode
couldntSetTo = JournalMode
mode0
                  }
            else () -> Either SetJournalModeException ()
forall a b. b -> Either a b
Right ()

data SetJournalModeException = SetJournalModeException
  { SetJournalModeException -> JournalMode
currentJournalMode :: JournalMode,
    SetJournalModeException -> JournalMode
couldntSetTo :: JournalMode
  }
  deriving stock (Int -> SetJournalModeException -> ShowS
[SetJournalModeException] -> ShowS
SetJournalModeException -> String
(Int -> SetJournalModeException -> ShowS)
-> (SetJournalModeException -> String)
-> ([SetJournalModeException] -> ShowS)
-> Show SetJournalModeException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SetJournalModeException -> ShowS
showsPrec :: Int -> SetJournalModeException -> ShowS
$cshow :: SetJournalModeException -> String
show :: SetJournalModeException -> String
$cshowList :: [SetJournalModeException] -> ShowS
showList :: [SetJournalModeException] -> ShowS
Show)
  deriving anyclass (Show SetJournalModeException
Typeable SetJournalModeException
(Show SetJournalModeException, Typeable SetJournalModeException) =>
SqliteExceptionReason SetJournalModeException
forall e. (Show e, Typeable e) => SqliteExceptionReason e
SqliteExceptionReason)