module Internal.Control.Effects.Basic where
import Internal.Interlude
import Control.Effects
import Database.PostgreSQL.Simple
import qualified Database.PostgreSQL.Simple.Types as PSQL
import Internal.Data.Basic.Types
import Internal.Data.Basic.Sql.Types
import Internal.Data.Basic.Compiler
data Basic
newtype SqlRequest a = SqlRequest { getSqlRequest :: SqlExp } deriving Show
type instance EffectMsg1 Basic = SqlRequest
type instance EffectRes1 Basic = []
type instance EffectCon1 Basic a = FromRow a
handleBasic :: (forall b. FromRow b => SqlRequest b -> m [b])
-> EffectHandler1 Basic m a -> m a
handleBasic = handleEffect1
handleBasicPsql :: MonadIO m => Connection -> EffectHandler1 Basic m a -> m a
handleBasicPsql conn = handleBasic
(liftIO . runQuerySegment . sqlExpToQuery . getSqlRequest)
where
runQuerySegment :: FromRow b => QuerySegment -> IO [b]
runQuerySegment (QuerySegment q as) = query conn q as
type family AllTables tables where
AllTables '[x] = x
AllTables (x ': xs) = x :. AllTables xs
class (FromRow (AllTables ts)) => AllHaveFromRowInstance ts where
compositeToTuple :: proxy ts -> AllTables ts -> DbResult ts
instance (FromRow a) => AllHaveFromRowInstance '[a] where
compositeToTuple _ = Entity
instance (FromRow a, FromRow b) => AllHaveFromRowInstance '[a, b] where
compositeToTuple _ (a :. b) = (Entity a, Entity b)
instance (FromRow a, FromRow b, FromRow c) => AllHaveFromRowInstance '[a, b, c] where
compositeToTuple _ (a :. b :. c) = (Entity a, Entity b, Entity c)
runDbStatement :: forall ts m f.
(AllHaveFromRowInstance ts, MonadEffect1 Basic m)
=> DbStatement f ts -> m [DbResult ts]
runDbStatement = fmap (map (compositeToTuple (Proxy @ts)))
. effect1 (Proxy :: Proxy Basic)
. SqlRequest
. compileToSql
runAggregateStatement ::
forall aggr m.
( MonadEffect1 Basic m
, FromRow (AggregationResult aggr))
=> AggregateStatement aggr 'AM -> m (AggregationResult aggr)
runAggregateStatement =
fmap unsafeHead
. effect1 (Proxy :: Proxy Basic)
. SqlRequest
. aggregateStatementToSql
type family WithoutOnly a where
WithoutOnly (PSQL.Only a) = a
WithoutOnly a = a
class NoOnly a where
noOnly :: a -> WithoutOnly a
instance NoOnly (PSQL.Only a) where
noOnly (PSQL.Only a) = a
instance
WithoutOnly a ~ a
=> NoOnly a where
noOnly = identity
runMapStatement ::
forall res m f.
( MonadEffect1 Basic m
, FromRow res
, NoOnly res )
=> DbStatement f '[res] -> m [WithoutOnly res]
runMapStatement =
fmap (fmap (noOnly @res))
. effect1 (Proxy :: Proxy Basic)
. SqlRequest
. compileToSql
type MonadEffectBasic m = MonadEffect1 Basic m