module Database.PostgreSQL.Query.Entity.Functions
(
pgInsertEntity
, pgInsertManyEntities
, pgInsertManyEntitiesId
, pgSelectEntities
, pgSelectJustEntities
, pgSelectEntitiesBy
, pgGetEntity
, pgGetEntityBy
, pgQueryEntities
, pgDeleteEntity
, pgUpdateEntity
, pgSelectCount
) where
import Data.Int ( Int64 )
import Database.PostgreSQL.Query.Entity.Class
import Database.PostgreSQL.Query.Entity.Internal
import Database.PostgreSQL.Query.Functions
import Database.PostgreSQL.Query.Import
import Database.PostgreSQL.Query.SqlBuilder
import Database.PostgreSQL.Query.TH
( sqlExp )
import Database.PostgreSQL.Query.Types
import Database.PostgreSQL.Simple
import Database.PostgreSQL.Simple.FromField
import Database.PostgreSQL.Simple.ToField
import qualified Control.Monad.Fail as F
import qualified Data.List as L
import qualified Data.List.NonEmpty as NL
pgInsertEntity
:: forall a m
. ( MonadPostgres m, MonadLogger m, Entity a
, ToRow a, FromField (EntityId a), F.MonadFail m )
=> a
-> m (EntityId a)
pgInsertEntity :: a -> m (EntityId a)
pgInsertEntity a
a = do
SqlBuilder -> m [Only (EntityId a)]
forall (m :: * -> *) q r.
(MonadPostgres m, ToSqlBuilder q, FromRow r, HasCallStack) =>
q -> m [r]
pgQuery [sqlExp|^{insertEntity a} RETURNING id|] m [Only (EntityId a)]
-> ([Only (EntityId a)] -> m (EntityId a)) -> m (EntityId a)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
((Only EntityId a
ret):[Only (EntityId a)]
_) -> EntityId a -> m (EntityId a)
forall (m :: * -> *) a. Monad m => a -> m a
return EntityId a
ret
[Only (EntityId a)]
_ -> String -> m (EntityId a)
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Query did not return any response"
pgSelectEntities
:: forall m a q
. ( Functor m, MonadPostgres m, MonadLogger m, Entity a
, FromRow a, ToSqlBuilder q, FromField (EntityId a) )
=> (FN -> FN)
-> q
-> m [Ent a]
pgSelectEntities :: (FN -> FN) -> q -> m [Ent a]
pgSelectEntities FN -> FN
fpref q
q = do
let p :: Proxy a
p = Proxy a
forall k (t :: k). Proxy t
Proxy :: Proxy a
SqlBuilder -> m [Ent a]
forall q (m :: * -> *) a.
(ToSqlBuilder q, MonadPostgres m, MonadLogger m, Entity a,
FromRow a, FromField (EntityId a)) =>
q -> m [Ent a]
pgQueryEntities [sqlExp|^{selectEntity (entityFieldsId fpref) p} ^{q}|]
pgSelectJustEntities
:: forall m a q
. ( Functor m, MonadPostgres m, MonadLogger m, Entity a
, FromRow a, ToSqlBuilder q )
=> (FN -> FN)
-> q
-> m [a]
pgSelectJustEntities :: (FN -> FN) -> q -> m [a]
pgSelectJustEntities FN -> FN
fpref q
q = do
let p :: Proxy a
p = Proxy a
forall k (t :: k). Proxy t
Proxy :: Proxy a
SqlBuilder -> m [a]
forall (m :: * -> *) q r.
(MonadPostgres m, ToSqlBuilder q, FromRow r, HasCallStack) =>
q -> m [r]
pgQuery [sqlExp|^{selectEntity (entityFields id fpref) p} ^{q}|]
pgSelectEntitiesBy
:: forall a m b
. ( Functor m, MonadPostgres m, MonadLogger m, Entity a, ToMarkedRow b
, FromRow a, FromField (EntityId a) )
=> b
-> m [Ent a]
pgSelectEntitiesBy :: b -> m [Ent a]
pgSelectEntitiesBy b
b =
let p :: Proxy a
p = Proxy a
forall k (t :: k). Proxy t
Proxy :: Proxy a
in SqlBuilder -> m [Ent a]
forall q (m :: * -> *) a.
(ToSqlBuilder q, MonadPostgres m, MonadLogger m, Entity a,
FromRow a, FromField (EntityId a)) =>
q -> m [Ent a]
pgQueryEntities (SqlBuilder -> m [Ent a]) -> SqlBuilder -> m [Ent a]
forall a b. (a -> b) -> a -> b
$ ([FN] -> [FN]) -> Proxy a -> b -> SqlBuilder
forall a b.
(Entity a, ToMarkedRow b) =>
([FN] -> [FN]) -> Proxy a -> b -> SqlBuilder
selectEntitiesBy (FN
"id"FN -> [FN] -> [FN]
forall a. a -> [a] -> [a]
:) Proxy a
p b
b
pgGetEntity
:: forall m a
. ( ToField (EntityId a), Entity a, FromRow a
, MonadPostgres m, MonadLogger m, Functor m)
=> EntityId a
-> m (Maybe a)
pgGetEntity :: EntityId a -> m (Maybe a)
pgGetEntity EntityId a
eid = do
[a] -> Maybe a
forall a. [a] -> Maybe a
listToMaybe ([a] -> Maybe a) -> m [a] -> m (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (FN -> FN) -> SqlBuilder -> m [a]
forall (m :: * -> *) a q.
(Functor m, MonadPostgres m, MonadLogger m, Entity a, FromRow a,
ToSqlBuilder q) =>
(FN -> FN) -> q -> m [a]
pgSelectJustEntities FN -> FN
forall a. a -> a
id [sqlExp|WHERE id = #{eid} LIMIT 1|]
pgGetEntityBy
:: forall m a b
. ( Entity a, MonadPostgres m, MonadLogger m, ToMarkedRow b
, FromField (EntityId a), FromRow a, Functor m )
=> b
-> m (Maybe (Ent a))
pgGetEntityBy :: b -> m (Maybe (Ent a))
pgGetEntityBy b
b =
let p :: Proxy a
p = Proxy a
forall k (t :: k). Proxy t
Proxy :: Proxy a
in ([Ent a] -> Maybe (Ent a)) -> m [Ent a] -> m (Maybe (Ent a))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Ent a] -> Maybe (Ent a)
forall a. [a] -> Maybe a
listToMaybe
(m [Ent a] -> m (Maybe (Ent a))) -> m [Ent a] -> m (Maybe (Ent a))
forall a b. (a -> b) -> a -> b
$ SqlBuilder -> m [Ent a]
forall q (m :: * -> *) a.
(ToSqlBuilder q, MonadPostgres m, MonadLogger m, Entity a,
FromRow a, FromField (EntityId a)) =>
q -> m [Ent a]
pgQueryEntities
[sqlExp|^{selectEntitiesBy ("id":) p b} LIMIT 1|]
pgInsertManyEntitiesId
:: forall a m
. ( Entity a, MonadPostgres m, MonadLogger m
, ToRow a, FromField (EntityId a))
=> [a]
-> m [EntityId a]
pgInsertManyEntitiesId :: [a] -> m [EntityId a]
pgInsertManyEntitiesId [] = [EntityId a] -> m [EntityId a]
forall (m :: * -> *) a. Monad m => a -> m a
return []
pgInsertManyEntitiesId [a]
ents' =
let ents :: NonEmpty a
ents = [a] -> NonEmpty a
forall a. [a] -> NonEmpty a
NL.fromList [a]
ents'
q :: SqlBuilder
q = [sqlExp|^{insertManyEntities ents} RETURNING id|]
in (Only (EntityId a) -> EntityId a)
-> [Only (EntityId a)] -> [EntityId a]
forall a b. (a -> b) -> [a] -> [b]
map Only (EntityId a) -> EntityId a
forall a. Only a -> a
fromOnly ([Only (EntityId a)] -> [EntityId a])
-> m [Only (EntityId a)] -> m [EntityId a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> SqlBuilder -> m [Only (EntityId a)]
forall (m :: * -> *) q r.
(MonadPostgres m, ToSqlBuilder q, FromRow r, HasCallStack) =>
q -> m [r]
pgQuery SqlBuilder
q
pgInsertManyEntities
:: forall a m
. (Entity a, MonadPostgres m, MonadLogger m, ToRow a)
=> [a]
-> m Int64
pgInsertManyEntities :: [a] -> m Int64
pgInsertManyEntities [] = Int64 -> m Int64
forall (m :: * -> *) a. Monad m => a -> m a
return Int64
0
pgInsertManyEntities [a]
ents' =
let ents :: NonEmpty a
ents = [a] -> NonEmpty a
forall a. [a] -> NonEmpty a
NL.fromList [a]
ents'
in SqlBuilder -> m Int64
forall (m :: * -> *) q.
(MonadPostgres m, ToSqlBuilder q, HasCallStack) =>
q -> m Int64
pgExecute (SqlBuilder -> m Int64) -> SqlBuilder -> m Int64
forall a b. (a -> b) -> a -> b
$ NonEmpty a -> SqlBuilder
forall a. (Entity a, ToRow a) => NonEmpty a -> SqlBuilder
insertManyEntities NonEmpty a
ents
pgDeleteEntity
:: forall a m
. (Entity a, MonadPostgres m, MonadLogger m, ToField (EntityId a), Functor m)
=> EntityId a
-> m Bool
pgDeleteEntity :: EntityId a -> m Bool
pgDeleteEntity EntityId a
eid =
let p :: Proxy a
p = Proxy a
forall k (t :: k). Proxy t
Proxy :: Proxy a
in (Int64 -> Bool) -> m Int64 -> m Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int64
1 Int64 -> Int64 -> Bool
forall a. Eq a => a -> a -> Bool
==)
(m Int64 -> m Bool) -> m Int64 -> m Bool
forall a b. (a -> b) -> a -> b
$ SqlBuilder -> m Int64
forall (m :: * -> *) q.
(MonadPostgres m, ToSqlBuilder q, HasCallStack) =>
q -> m Int64
pgExecute [sqlExp|DELETE FROM ^{tableName p}
WHERE id = #{eid}|]
pgUpdateEntity
:: forall a b m
. ( ToMarkedRow b, Entity a, MonadPostgres m, MonadLogger m
, ToField (EntityId a), Functor m, Typeable a, Typeable b)
=> EntityId a
-> b
-> m Bool
pgUpdateEntity :: EntityId a -> b -> m Bool
pgUpdateEntity EntityId a
eid b
b =
let p :: Proxy a
p = Proxy a
forall k (t :: k). Proxy t
Proxy :: Proxy a
mr :: MarkedRow
mr = b -> MarkedRow
forall a. ToMarkedRow a => a -> MarkedRow
toMarkedRow b
b
in if [(FN, SqlBuilder)] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
L.null ([(FN, SqlBuilder)] -> Bool) -> [(FN, SqlBuilder)] -> Bool
forall a b. (a -> b) -> a -> b
$ MarkedRow -> [(FN, SqlBuilder)]
unMR MarkedRow
mr
then Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
else (Int64 -> Bool) -> m Int64 -> m Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int64
1 Int64 -> Int64 -> Bool
forall a. Eq a => a -> a -> Bool
==)
(m Int64 -> m Bool) -> m Int64 -> m Bool
forall a b. (a -> b) -> a -> b
$ SqlBuilder -> m Int64
forall (m :: * -> *) q.
(MonadPostgres m, ToSqlBuilder q, HasCallStack) =>
q -> m Int64
pgExecute [sqlExp|UPDATE ^{tableName p}
SET ^{mrToBuilder ", " mr}
WHERE id = #{eid}|]
pgQueryEntities
:: ( ToSqlBuilder q, MonadPostgres m, MonadLogger m, Entity a
, FromRow a, FromField (EntityId a))
=> q
-> m [Ent a]
pgQueryEntities :: q -> m [Ent a]
pgQueryEntities q
q =
((Only (EntityId a) :. a) -> Ent a)
-> [Only (EntityId a) :. a] -> [Ent a]
forall a b. (a -> b) -> [a] -> [b]
map (Only (EntityId a) :. a) -> Ent a
forall a b. (Only a :. b) -> (a, b)
toTuples ([Only (EntityId a) :. a] -> [Ent a])
-> m [Only (EntityId a) :. a] -> m [Ent a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> q -> m [Only (EntityId a) :. a]
forall (m :: * -> *) q r.
(MonadPostgres m, ToSqlBuilder q, FromRow r, HasCallStack) =>
q -> m [r]
pgQuery q
q
where
toTuples :: (Only a :. b) -> (a, b)
toTuples ((Only a
eid) :. b
entity) = (a
eid, b
entity)
pgSelectCount
:: forall m a q
. ( Entity a, MonadPostgres m, MonadLogger m, ToSqlBuilder q )
=> Proxy a
-> q
-> m Integer
pgSelectCount :: Proxy a -> q -> m Integer
pgSelectCount Proxy a
p q
q = do
[[Integer]]
r <- SqlBuilder -> m [[Integer]]
forall (m :: * -> *) q r.
(MonadPostgres m, ToSqlBuilder q, FromRow r, HasCallStack) =>
q -> m [r]
pgQuery [sqlExp|SELECT count(id) FROM ^{tableName p} ^{q}|]
case [[Integer]]
r of
[[Integer
c]] -> Integer -> m Integer
forall (m :: * -> *) a. Monad m => a -> m a
return Integer
c
[[Integer]]
_ -> String -> m Integer
forall a. HasCallStack => String -> a
error String
"this should not happen"