{-# language MonoLocalBinds #-}
{-# language ScopedTypeVariables #-}
{-# language TypeApplications #-}

module Rel8.Statement.Select
  ( select
  , selectWithNames
  )
where

-- base
import Control.Exception ( throwIO )
import Prelude

-- hasql
import Hasql.Connection ( Connection )
import qualified Hasql.Decoders as Hasql
import qualified Hasql.Encoders as Hasql
import qualified Hasql.Session as Hasql
import qualified Hasql.Statement as Hasql

-- rel8
import Rel8.Query ( Query )
import Rel8.Query.SQL ( sqlForQuery, sqlForQueryWithNames )
import Rel8.Schema.Name ( Selects )
import Rel8.Table.Serialize ( Serializable, parse )

-- text
import qualified Data.Text as Text
import Data.Text.Encoding ( encodeUtf8 )


-- | Run a @SELECT@ query, returning all rows.
select :: forall exprs a. Serializable exprs a
  => Connection -> Query exprs -> IO [a]
select :: Connection -> Query exprs -> IO [a]
select Connection
c Query exprs
query = case Query exprs -> Maybe String
forall a. Table Expr a => Query a -> Maybe String
sqlForQuery Query exprs
query of
  Maybe String
Nothing -> [a] -> IO [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
  Just String
sql -> Session [a] -> Connection -> IO (Either QueryError [a])
forall a. Session a -> Connection -> IO (Either QueryError a)
Hasql.run Session [a]
session Connection
c IO (Either QueryError [a])
-> (Either QueryError [a] -> IO [a]) -> IO [a]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (QueryError -> IO [a])
-> ([a] -> IO [a]) -> Either QueryError [a] -> IO [a]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either QueryError -> IO [a]
forall e a. Exception e => e -> IO a
throwIO [a] -> IO [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    where
      session :: Session [a]
session = () -> Statement () [a] -> Session [a]
forall params result.
params -> Statement params result -> Session result
Hasql.statement () Statement () [a]
statement
      statement :: Statement () [a]
statement = ByteString -> Params () -> Result [a] -> Bool -> Statement () [a]
forall a b.
ByteString -> Params a -> Result b -> Bool -> Statement a b
Hasql.Statement ByteString
bytes Params ()
params Result [a]
decode Bool
prepare
      bytes :: ByteString
bytes = Text -> ByteString
encodeUtf8 (String -> Text
Text.pack String
sql)
      params :: Params ()
params = Params ()
Hasql.noParams
      decode :: Result [a]
decode = Row a -> Result [a]
forall a. Row a -> Result [a]
Hasql.rowList (Serializable exprs a => Row a
forall exprs a. Serializable exprs a => Row a
parse @exprs @a)
      prepare :: Bool
prepare = Bool
False


selectWithNames :: forall exprs a names.
  ( Selects names exprs
  , Serializable exprs a
  )
  => Connection -> names -> Query exprs -> IO [a]
selectWithNames :: Connection -> names -> Query exprs -> IO [a]
selectWithNames Connection
c names
names Query exprs
query = case names -> Query exprs -> Maybe String
forall names exprs.
Selects names exprs =>
names -> Query exprs -> Maybe String
sqlForQueryWithNames names
names Query exprs
query of
  Maybe String
Nothing -> [a] -> IO [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
  Just String
sql -> Session [a] -> Connection -> IO (Either QueryError [a])
forall a. Session a -> Connection -> IO (Either QueryError a)
Hasql.run Session [a]
session Connection
c IO (Either QueryError [a])
-> (Either QueryError [a] -> IO [a]) -> IO [a]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (QueryError -> IO [a])
-> ([a] -> IO [a]) -> Either QueryError [a] -> IO [a]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either QueryError -> IO [a]
forall e a. Exception e => e -> IO a
throwIO [a] -> IO [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    where
      session :: Session [a]
session = () -> Statement () [a] -> Session [a]
forall params result.
params -> Statement params result -> Session result
Hasql.statement () Statement () [a]
statement
      statement :: Statement () [a]
statement = ByteString -> Params () -> Result [a] -> Bool -> Statement () [a]
forall a b.
ByteString -> Params a -> Result b -> Bool -> Statement a b
Hasql.Statement ByteString
bytes Params ()
params Result [a]
decode Bool
prepare
      bytes :: ByteString
bytes = Text -> ByteString
encodeUtf8 (String -> Text
Text.pack String
sql)
      params :: Params ()
params = Params ()
Hasql.noParams
      decode :: Result [a]
decode = Row a -> Result [a]
forall a. Row a -> Result [a]
Hasql.rowList (Serializable exprs a => Row a
forall exprs a. Serializable exprs a => Row a
parse @exprs @a)
      prepare :: Bool
prepare = Bool
False