packages feed

dani-sqlite-0.1.0.0: lib/Sqlite/Query/Internal.hs

{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE OverloadedStrings #-}

------------------------------------------------------------------------------

------------------------------------------------------------------------------

-- |
-- Internal bits.  This interface is less stable and can change at any time.
-- In particular this means that while the rest of the sqlite-simple
-- package endeavors to follow the package versioning policy,  this module
-- does not.  Also, at the moment there are things in here that aren't
-- particularly internal and are exported elsewhere;  these will eventually
-- disappear from this module.
module Sqlite.Query.Internal where

import Control.Applicative
import Control.Exception (Exception)
import Control.Monad
import Data.ByteString (ByteString)
import Data.ByteString.Char8 ()
import Sqlite qualified as Base
import Sqlite.Query.Ok

-- -- | Connection to an open database.
-- --
-- -- You can use 'connectionHandle' to gain access to the underlying
-- -- <http://hackage.haskell.org/package/direct-sqlite> connection.
-- -- This may be useful if you need to access some direct-sqlite
-- -- functionality that's not exposed in the sqlite-simple API.  This
-- -- should be a safe thing to do although mixing both APIs is
-- -- discouraged.
-- data Connection = Connection
--   { connectionHandle :: {-# UNPACK #-} !Base.Database,
--     connectionTempNameCounter :: {-# UNPACK #-} !(IORef Word64)
--   }

newtype ColumnOutOfBounds = ColumnOutOfBounds {errorColumnIndex :: Int}
  deriving (Eq, Show)

instance Exception ColumnOutOfBounds

-- | A Field represents metadata about a particular field
data Field = Field
  { result :: Base.SqlData,
    column :: {-# UNPACK #-} !Int
  }

-- Named type for holding RowParser read-only state.  Just for making
-- it easier to make sense out of types in FromRow.
newtype RowParserRO = RowParserRO {nColumns :: Int}

type RowParserState = (Int, [Base.SqlData])

newtype RowParser a = RowParser {runRowParser :: RowParserRO -> RowParserState -> Ok (a, RowParserState)}
  deriving (Functor)

instance Applicative RowParser where
  pure a = RowParser $ \_ s -> pure (a, s)
  RowParser pf <*> RowParser pa = RowParser $ \ro s -> do
    (f, s') <- pf ro s
    (a, s'') <- pa ro s'
    pure (f a, s'')

instance Alternative RowParser where
  empty = RowParser $ \_ _ -> empty
  RowParser p1 <|> RowParser p2 = RowParser $ \ro s -> p1 ro s <|> p2 ro s

instance Monad RowParser where
  RowParser pa >>= f = RowParser $ \ro s -> do
    (a, s') <- pa ro s
    runRowParser (f a) ro s'

instance MonadPlus RowParser where
  mzero = empty
  mplus = (<|>)

-- | Get the read-only RowParseRO environment.
asksRowParserRO :: (RowParserRO -> a) -> RowParser a
asksRowParserRO f = RowParser $ \ro s -> pure (f ro, s)

-- | Get the current RowParserState.
getRowParserState :: RowParser RowParserState
getRowParserState = RowParser $ \_ s -> pure (s, s)

-- | Set the RowParserState.
putRowParserState :: RowParserState -> RowParser ()
putRowParserState s = RowParser $ \_ _ -> pure ((), s)

liftOk :: Ok a -> RowParser a
liftOk oka = RowParser $ \_ s -> do
  a <- oka
  pure (a, s)

gettypename :: Base.SqlData -> ByteString
gettypename (Base.SqlInteger _) = "INTEGER"
gettypename (Base.SqlFloat _) = "FLOAT"
gettypename (Base.SqlText _) = "TEXT"
gettypename (Base.SqlBlob _) = "BLOB"
gettypename Base.SqlNull = "NULL"