-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | High-level SQLite client. -- -- High-level SQLite client. @package sq @version 0.0.1 -- | High-level SQLite client library -- -- ⚠️ This is an early preview release of this library. Use at your -- own risk. -- --
--   import qualified Sq
--   
-- -- Things currently supported: -- -- -- -- Things not supported yet: -- -- -- -- If you have questions or suggestions, just say so at -- https://github.com/k0001/hs-sq/issues. -- -- ⚠️ This is an early preview release of this library. Use at your -- own risk. module Sq -- | data Statement (s :: Mode) i o -- | Construct a Read-only Statement. -- -- WARNING: This library doesn't yet provide a safe way to -- construct Statements. You can potentially write anything in -- your SQL string. Don't do that. -- -- readStatement :: Input i -> Output o -> SQL -> Statement 'Read i o -- | Construct a Statement that can only be executed as part of a -- Write Transaction. -- -- WARNING: This library doesn't yet provide a safe way to -- construct Statements. You can potentially write anything in -- your SQL string. Don't do that. -- -- writeStatement :: Input i -> Output o -> SQL -> Statement 'Write i o -- | Raw SQL string. Completely unchecked. data SQL -- | A QuasiQuoter for raw SQL strings. -- -- WARNING: This doesn't check the validity of the SQL. It is -- offered simply because writing multi-line strings in Haskell is -- otherwise very annoying. sql :: QuasiQuoter -- | How to encode all the input to a single Statement. -- -- data Input i -- | Encode a single input parameter. The value will be reachable from the -- SQL query through the specified Name, with a -- $ prefix. -- --
--   writeStatement
--           (encode "foo" encodeDefault)
--           mempty
--           "INSERT INTO t (a) VALUES ($foo)"
--      :: (EncodeDefault x)
--      => Statement Write x ()
--   
-- -- Note that by design, this library doesn't support positional -- Input parameters. You must always pick a Name. -- -- Multiple Inputs can be composed with Contravariant, -- Divisible, Decidable and Monoid tools. -- --
--   writeStatement
--           (divided (encode "foo" encodeDefault)
--                    (encode "bar" encodeDefault))
--           mempty
--           "INSERT INTO t (a, b) VALUES ($foo, $bar)"
--      :: (EncodeDefault x, EncodeDefault y)
--      => Statement Write (x, y) ()
--   
-- -- Pro-tip: Consider using the IsString instance for Input. -- For example, "foo" means encode "foo" -- encodeDefault. That is, the last example could be written -- as follows: -- --
--   writeStatement
--           (divided "foo" "bar")
--           mempty
--           "INSERT INTO t (a, b) VALUES ($foo, $bar)"
--      :: (EncodeDefault x, EncodeDefault y)
--      => Statement Write (x, y) ()
--   
encode :: Name -> Encode i -> Input i -- | Add a prefix Name to parameters names in the given -- Input, separated by __ -- -- This is useful for making reusable Inputs. For example, -- consider the following. -- --
--   data Point = Point { x :: Int, y :: Int }
--   
--   pointInput :: Input Point
--   pointInput = contramap (\case Point x _ -> x) "x" <>
--                contramap (\case Point _ y -> y) "y"
--   
-- -- After input: -- --
--   writeStatement
--           (divided (input "p1" pointInput)
--                    (input "p2" pointInput))
--           mempty
--           [sql|
--             INSERT INTO vectors (ax, ay, bx, by)
--             VALUES ($p1__x, $p1__y, $p2__x, $p2__y) |]
--      :: Statement Write (Point, Point) ()
--   
input :: Name -> Input i -> Input i -- | How to encode a single Haskell value of type a into a SQLite -- value. newtype Encode a -- | Encode a value of type a as SQLData. -- -- Ideally, the type a should be small enough that this function -- always returns Right. However, that can sometimes be annoying, -- so we allow this function to fail with ErrEncode if necessary, -- in which case an ErrInput exception will be eventually thrown -- while trying to bind the relevant Input to a Statement. -- Why? Because for example, not all Strings can be safely encoded -- as a SQLText seeing as some non-unicode characters will -- silently be lost in the conversion. So, we could either not have an -- Encoder for String at all, which would be annoying, or -- we could have ErrEncode as we do here in order to safely deal -- with those obscure corner cases. Encode :: (a -> Either ErrEncode SQLData) -> Encode a -- | A convenience function for refining an Encoder through a -- function that may fail with a String error message. The -- CallStack is preserved. -- -- If you need a more sophisticated refinement, use the Encode -- constructor. encodeRefine :: HasCallStack => (a -> Either String b) -> Encode b -> Encode a -- | Default way to encode a Haskell value of type a into a single -- SQLite column value. -- -- If there there exist also a DecodeDefault instance for -- a, then it must roundtrip with the EncodeDefault -- instance for a. class EncodeDefault a -- | Default way to encode a Haskell value of type a into a single -- SQLite column value. encodeDefault :: EncodeDefault a => Encode a -- | a's ColumnType if Just, otherwise -- NullColumn. encodeMaybe :: Encode a -> Encode (Maybe a) -- | a's ColumnType if Left, otherwise b's -- ColumnType. encodeEither :: Encode a -> Encode b -> Encode (Either a b) -- | IntegerColumn if it fits in Int64, otherwise -- TextColumn. encodeSizedIntegral :: (Integral a, Bits a, HasCallStack) => Encode a -- | Encodes as TextColumn. encodeAeson :: (a -> Value) -> Encode a -- | BlobColumn. encodeBinary :: (a -> Put) -> Encode a -- | TextColumn. encodeShow :: Show a => Encode a -- | How to decode an output row from a single Statement. -- -- data Output o -- | Decode the column with the given Name. -- --
--   readStatement
--           mempty
--           (decode "foo" decodeDefault)
--           "SELECT foo FROM t"
--      :: (DecodeDefault x)
--      => Statement Read () x
--   
-- -- Note that by design, this library doesn't support positional -- Output parameters. You must always pick a Name. In the -- raw SQL, you can use AS to rename your output columns as -- necessary. -- --
--   readStatement
--           mempty
--           (decode "abc" decodeDefault)
--           "SELECT foo AS abc FROM t"
--      :: (DecodeDefault x)
--      => Statement Read () x
--   
-- -- Multiple Outputss can be composed with Monoid, -- Functor, Applicative, Alternative, Monad, -- MonadPlus, MonadFail and MonadThrow tools. -- --
--   readStatement
--           mempty
--           (do foo <- decode "foo" decodeDefault
--               when (foo > 10) do
--                  fail "Oh no!"
--               bar <- decode "bar" decodeDefault
--               pure (foo, bar))
--           "SELECT foo, bar FROM t"
--      :: (DecodeDefault y)
--      => Statement Read () (Int, y)
--   
-- -- Pro-tip: Consider using the IsString instance for -- Output, where for example "foo" means -- decode "foo" decodeDefault: -- --
--   readStatement
--           (liftA2 (,) "foo" "bar")
--           mempty
--           "SELECT foo, bar FROM t"
--      :: (DecodeDefault x, DecodeDefault y)
--      => Statement Read () (x, y)
--   
decode :: Name -> Decode o -> Output o -- | Add a prefix Name to column names in the given Output, -- separated by __ -- -- This is useful for making reusable Outputs. For example, -- consider the following. -- --
--   data Point = Point { x :: Int, y :: Int }
--   
--   pointOutput :: Output Point
--   pointOutput = Point <$> "x" <*> "y"
--   
-- -- After using output: -- --
--   readStatement
--           mempty
--           (liftA2 (output "p1" pointInput)
--                   (output "p2" pointInput))
--           [sql|
--             SELECT ax AS p1__x, ay AS p1__y,
--                    bx AS p2__x, by AS p2__y
--             FROM vectors|]
--      :: Statement Read () (Point, Point)
--   
output :: Name -> Output o -> Output o -- | How to decode a single SQLite column value into a Haskell value of -- type a. newtype Decode a -- | Decode a SQLData value into a value of type a. Decode :: (SQLData -> Either ErrDecode a) -> Decode a -- | A convenience function for refining a Decoder through a -- function that may fail with a String error message. The -- CallStack is preserved. -- -- If you need a more sophisticated refinement, use the Decode -- constructor. decodeRefine :: HasCallStack => (a -> Either String b) -> Decode a -> Decode b -- | Default way to decode a SQLite value into a Haskell value of type -- a. -- -- If there there exist also a EncodeDefault instance for -- a, then it must roundtrip with the DecodeDefault -- instance for a. class DecodeDefault a -- | Default way to decode a SQLite value into a Haskell value of type -- a. decodeDefault :: DecodeDefault a => Decode a -- | Attempt to decode a first, otherwise attempt decode a -- NullColumn as Nothing. decodeMaybe :: Decode a -> Decode (Maybe a) -- |
--   decodeEither da db = fmap Left da <|> fmap Right db
--   
decodeEither :: Decode a -> Decode b -> Decode (Either a b) -- | IntegerColumn. decodeSizedIntegral :: (Integral a, Bits a) => Decode a -- | TextColumn. decodeAeson :: (Value -> Parser a) -> Decode a -- | BlobColumn. decodeBinary :: Get a -> Decode a -- | TextColumn. decodeRead :: Read a => Decode a -- | Part of a binding name suitable to use with encode, -- decode, input and output. -- -- Construct with name or IsString. data Name -- | name :: Text -> Either String Name -- | Transactional g r t a groups together multiple -- interactions with a same Transaction t that finally -- produce a value of type a. Think of Transactional as -- if it was STM. -- -- -- -- To execute a Transactional you will normally use one of -- read or commit (or rollback or embed, but -- those are less common). -- --
--   -- We are using commit to execute the Transactional. This means
--   -- that the Transactional will have read and Write capabilities, that
--   -- it can retry, and that ultimately, unless there are unhandled
--   -- exceptions, the changes will be commited to the database.
--   Sq.commit pool do
--   
--      -- We can execute Write Statements:
--      userId1 <- Sq.one insertUser "haskell@example.com"
--   
--      -- And Read Statements:
--      userId2 <- Sq.one getUserIdByEmail "haskell@example.com"
--   
--      -- We have MonadFail too:
--      when (userId1 /= userId2) do
--          fail "Something unexpected happened!"
--   
--      -- We also have Refs, which work just like TVars:
--      ref <- newRef (0 :: Int)
--   
--      -- catch behaves like catchSTM, undoing changes to Refs
--      -- and to the database itself when the original action fails:
--      userId3 <- catch
--          -- Something will fail ...
--          (do modifyRef ref (+ 1)
--              _ <- Sq.one insertUser "sqlite@example.com"
--              throwM FakeException123)
--          -- ... but there is a catch!
--          (\FakeException123 -> do
--              -- The observable universe has been reset to what it
--              -- was before the catch:
--              Sq.zero getUserIdByEmail "sqlite@example.com"
--              modifyRef ref (+ 10))
--   
--      -- Only the effects from the exception handling function were preserved:
--      Sq.zero getUserIdByEmail "sqlite@example.com"
--      10 <- readRef ref
--   
--      -- retry and its synonyms mzero and empty not only discard changes as
--      -- catch does, but they also cause the ongoing Transaction to be
--      -- discarded, and the entire Transactional to be executed again on a
--      -- brand new Transaction observing a new snapshot of the database. For
--      -- example, the following code will keep retrying the whole Transactional
--      -- until the user with the specified email exists.
--      userId4 <- Sq.maybe getUserIdByEmail "nix@example.com" >>= \case
--          Just x -> pure x
--          Nothing -> retry
--   
--      -- Presumably, this example was waiting for a concurrent connection to
--      -- insert said user. If we got here, it is because that happened.
--   
--      -- As usual, mzero and empty can be handled by means of <|> and mplus,
--      -- or its synonym orElse.
--      False <- mplus (writeRef ref 8 >> mzero >> pure True)
--                     (pure False)
--   
--      -- The recent writeRef to 8 on the retryied Transactional was discarded:
--      10 <- readRef ref
--   
--      pure ()
--   
data Transactional (g :: k) (r :: Retry) (t :: Mode) a -- | Execute a Read-only Transactional in a fresh -- Transaction that will be automatically released when done. read :: forall {k} m (p :: Mode) a. (MonadIO m, SubMode p 'Read) => Pool p -> (forall (g :: k). () => Transactional g 'Retry 'Read a) -> m a -- | Execute a read-Write Transactional in a fresh -- Transaction that will be automatically committed when done. commit :: forall {k} m a. MonadIO m => Pool 'Write -> (forall (g :: k). () => Transactional g 'Retry 'Write a) -> m a -- | Execute a read-Write Transactional in a fresh -- Transaction that will be automatically rolled-back when done. -- -- This is mostly useful for testing. rollback :: forall {k} m a. MonadIO m => Pool 'Write -> (forall (g :: k). () => Transactional g 'Retry 'Write a) -> m a -- | Embeds all the actions in a Transactional as part of an ongoing -- Transaction. -- -- embed :: forall {k} m (t :: Mode) a. MonadIO m => Transaction t -> (forall (g :: k). () => Transactional g 'NoRetry t a) -> m a -- | Like TVar, but you can use it inside Transactional -- through the MonadRef and MonadAtomicRef vocabulary. data Ref (g :: k) a -- | retry behaves like STM's retry. It causes the -- current Transaction to be cancelled so that a new one can take -- its place and the entire Transactional is executed again. This -- allows the Transactional to observe a new snapshot of the -- database. -- -- retry :: forall {k} (g :: k) (t :: Mode) a. Transactional g 'Retry t a -- | orElse ma mb behaves like STM's -- orElse ma mb. If ma completes without -- executing retry, then that constitutes the entirety of -- orElse ma mb. Otherwise, if ma executed -- retry, then all the effects from ma are discared and -- mb is tried in its place. -- -- orElse :: forall {k} (g :: k) (r :: Retry) (t :: Mode) a. Transactional g r t a -> Transactional g r t a -> Transactional g r t a -- | Executes a Statement expected to return exactly one row. -- -- one :: forall {k} (t :: Mode) (s :: Mode) i o (g :: k) (r :: Retry). SubMode t s => Statement s i o -> i -> Transactional g r t o -- | Executes a Statement expected to return zero or one -- rows. -- -- maybe :: forall {k} (t :: Mode) (s :: Mode) i o (g :: k) (r :: Retry). SubMode t s => Statement s i o -> i -> Transactional g r t (Maybe o) -- | Executes a Statement expected to return exactly zero -- rows. -- -- zero :: forall {k} (t :: Mode) (s :: Mode) i o (g :: k) (r :: Retry). SubMode t s => Statement s i o -> i -> Transactional g r t () -- | Executes a Statement expected to return one or more -- rows. -- -- some :: forall {k} (t :: Mode) (s :: Mode) i o (g :: k) (r :: Retry). SubMode t s => Statement s i o -> i -> Transactional g r t (Int64, NonEmpty o) -- | Executes a Statement expected to return zero or more -- rows. -- -- list :: forall {k} (t :: Mode) (s :: Mode) i o (g :: k) (r :: Retry). SubMode t s => Statement s i o -> i -> Transactional g r t (Int64, [o]) -- | Purely fold all the output rows. fold :: forall {k} (t :: Mode) (s :: Mode) o z i (g :: k) (r :: Retry). SubMode t s => Fold o z -> Statement s i o -> i -> Transactional g r t z -- | Impurely fold the output rows. -- -- foldM :: forall {k} (t :: Mode) (s :: Mode) (g :: k) (r :: Retry) o z i. SubMode t s => FoldM (Transactional g r t) o z -> Statement s i o -> i -> Transactional g r t z -- | Stream the output rows from a Statement in a way that -- allows interleaving IO actions. -- -- streamIO :: forall (m :: Type -> Type) (t :: Mode) (s :: Mode) i o. (MonadResource m, SubMode t s) => Acquire (Transaction t) -> Statement s i o -> i -> Stream (Of o) m () -- | Fold the output rows from a Statement in a way that -- allows interleaving IO actions. -- -- foldIO :: forall m (t :: Mode) (s :: Mode) o z i. (MonadIO m, MonadMask m, SubMode t s) => FoldM m o z -> Acquire (Transaction t) -> Statement s i o -> i -> m z -- | Pool of connections to a SQLite database. -- -- data Pool (p :: Mode) -- | Acquire a Read-only Pool according to the given -- Settings. -- -- readPool :: Df1 -> Settings -> Acquire (Pool 'Read) -- | Acquire a read-Write Pool according to the given -- Settings. -- -- writePool :: Df1 -> Settings -> Acquire (Pool 'Write) -- | Acquire a read-Write Pool temporarily persisted in the -- file-system. It will be deleted once released. This can be useful for -- testing. -- -- tempPool :: Df1 -> Acquire (Pool 'Write) -- | Use subPool to obtain the Read-only subset from a -- read-Write Pool. -- -- subPool :: Pool 'Write -> Pool 'Read -- | SQLite connection settings. data Settings Settings :: FilePath -> SQLVFS -> Word32 -> Settings -- | Database file path. Not an URI. -- -- Note: To keep things simple, native :memory: SQLite databases -- are not supported. Maybe use poolTemp or tmpfs if you -- need that? [file] :: Settings -> FilePath [vfs] :: Settings -> SQLVFS -- | SQLite busy Timeout in milliseconds. [timeout] :: Settings -> Word32 -- | Default connection settings. settings :: FilePath -> Settings -- | A database transaction handle. -- -- data Transaction (t :: Mode) -- | Acquire a read-only transaction. -- -- readTransaction :: forall (mode :: Mode). Pool mode -> Acquire (Transaction 'Read) -- | Acquire a read-write transaction where changes are finally commited to -- the database unless there is an unhandled exception during the -- transaction, in which case they are rolled back. -- -- commitTransaction :: Pool 'Write -> Acquire (Transaction 'Write) -- | Acquire a read-write transaction where changes are always rolled back. -- This is mostly useful for testing purposes. -- -- rollbackTransaction :: Pool 'Write -> Acquire (Transaction 'Write) -- | Acquire through MonadResource. -- --
--   new = fmap snd . Data.Acquire.allocateAcquire
--   
new :: MonadResource m => Acquire a -> m a -- | Acquire through MonadMask. -- --
--   with = Control.Monad.Trans.Resource.Extra.withAcquire.
--   
with :: (MonadMask m, MonadIO m) => Acquire a -> (a -> m b) -> m b -- | Acquire through MonadUnliftIO. -- --
--   uith = Data.Acquire.with
--   
uith :: MonadUnliftIO m => Acquire a -> (a -> m b) -> m b -- | See savepoint, savepointRollback and -- savepointRelease. -- -- data Savepoint -- | Obtain savepoint to which one can later savepointRollback or -- savepointRelease. savepoint :: MonadIO m => Transaction 'Write -> m Savepoint -- | Disregard all the changes that happened to the Transaction -- related to this Savepoint since the time it was obtained -- through savepoint. -- -- savepointRollback :: MonadIO m => Savepoint -> m () -- | Release a Savepoint so that it, together with any previous -- Savepoints on the same Transaction, become unreachable -- to future uses of savepointRollback or savepointRelease. -- -- savepointRelease :: MonadIO m => Savepoint -> m () -- | Used as the r type-parameter in Transactional g r -- t a. -- -- data Retry NoRetry :: Retry Retry :: Retry -- | A non-empty list of Names that can be rendered as Input -- or Output parameters in a Statement. -- -- As a user of Sq, you never construct a BindingName -- manually. Rather, uses of input and output build one for -- you from its Name constituents. BindingNames are only -- exposed to you through ErrInput, ErrOutput and -- ErrStatement. data BindingName data Mode -- | Read :: Mode -- | Write :: Mode class SubMode (sup :: Mode) (sub :: Mode) -- | The NULL SQL datatype. -- -- Mostly useful if you want to encode or decode a literal NULL -- value through EncodeDefault and DecodeDefault instances. -- -- However, often you can benefit from encodeMaybe and -- decodeMaybe instead. data Null Null :: Null -- | See Encode. newtype ErrEncode ErrEncode :: SomeException -> ErrEncode -- | See Encode. data ErrInput ErrInput :: BindingName -> ErrEncode -> ErrInput -- | See Decode. data ErrDecode -- | Received ColumnType, expected ColumnTypes. ErrDecode_Type :: ColumnType -> [ColumnType] -> ErrDecode ErrDecode_Fail :: SomeException -> ErrDecode data ErrOutput -- | Error from Decode. ErrOutput_ColumnValue :: BindingName -> ErrDecode -> ErrOutput -- | Missing column name in the raw SQL. ErrOutput_ColumnMissing :: BindingName -> ErrOutput -- | Error from MonadThrow. ErrOutput_Fail :: SomeException -> ErrOutput data ErrStatement -- | A same column name appears twice or more in the raw SQL. ErrStatement_DuplicateColumnName :: BindingName -> ErrStatement data ErrRows -- | Fewer rows than requested were available. ErrRows_TooFew :: ErrRows -- | More rows than requested were available. ErrRows_TooMany :: ErrRows data SQLData SQLInteger :: !Int64 -> SQLData SQLFloat :: !Double -> SQLData SQLText :: !Text -> SQLData SQLBlob :: !ByteString -> SQLData SQLNull :: SQLData -- | These VFS names are used when using the open2 function. data SQLVFS SQLVFSDefault :: SQLVFS SQLVFSUnix :: SQLVFS SQLVFSUnixDotFile :: SQLVFS SQLVFSUnixExcl :: SQLVFS SQLVFSUnixNone :: SQLVFS SQLVFSUnixNamedSem :: SQLVFS SQLVFSCustom :: Text -> SQLVFS