@@ -36,17 +36,13 @@ module Squeal.PostgreSQL.PQ
38 , withConnection
38 , withConnection
40− , PQ (PQ, runPQ)
41+ , PQ (PQ, unPQ)
42− , pqEmbed
44+ , evalPQ
43− , pqAp
45+ , IndexedMonadTransPQ (..)
50 , MonadPQ (..)
46 , MonadPQ (..)
52 , pqliftWith
48 , pqliftWith
@@ -149,9 +145,15 @@ withConnection
149 -> PQ schema0 schema1 io x
145 -> PQ schema0 schema1 io x
151withConnection connString action = do
147withConnection connString action = do
152− K x <- bracket (connectdb connString) finish (runPQ action)
148+ K x <- bracket (connectdb connString) finish (unPQ action)
151+-- | Safely `lowerConnection` to a smaller schema.
153+ :: K LibPQ.Connection (table ': schema)
154+ -> K LibPQ.Connection schema
155+lowerConnection (K conn) = K conn
155-- | We keep track of the schema via an Atkey indexed state monad transformer,
157-- | We keep track of the schema via an Atkey indexed state monad transformer,
157newtype PQ
159newtype PQ
@@ -159,87 +161,113 @@ newtype PQ
159 (schema1 :: TablesType)
161 (schema1 :: TablesType)
160 (m :: Type -> Type)
162 (m :: Type -> Type)
161 (x :: Type) =
163 (x :: Type) =
162− PQ { runPQ :: K LibPQ.Connection schema0 -> m (K x schema1) }
164+ PQ { unPQ :: K LibPQ.Connection schema0 -> m (K x schema1) }
164instance Monad m => Functor (PQ schema0 schema1 m) where
166instance Monad m => Functor (PQ schema0 schema1 m) where
165 fmap f (PQ pq) = PQ $ \ conn -> do
167 fmap f (PQ pq) = PQ $ \ conn -> do
166 K x <- pq conn
168 K x <- pq conn
167 return $ K (f x)
169 return $ K (f x)
171+-- | Run a `PQ` and keep the result and the `Connection`.
174+ => PQ schema0 schema1 m x
175+ -> K LibPQ.Connection schema0
176+ -> m (x, K LibPQ.Connection schema1)
177+runPQ (PQ pq) conn = (\ x -> (unK x, K (unK conn))) <$> pq conn
179+ -- return (x, K (unK conn))
169−-- | Run a `PQ` and discard the result but keep the `Connection`.
181+-- | Execute a `PQ` and discard the result but keep the `Connection`.
171 :: Functor m
183 :: Functor m
172 => PQ schema0 schema1 m x
184 => PQ schema0 schema1 m x
173 -> K LibPQ.Connection schema0
185 -> K LibPQ.Connection schema0
174 -> m (K LibPQ.Connection schema1)
186 -> m (K LibPQ.Connection schema1)
175−execPQ (PQ pq) conn = fmap (mapKK (\ _ -> unK conn)) $ pq conn
187+execPQ (PQ pq) conn = mapKK (\ _ -> unK conn) <$> pq conn
177−-- | Safely embed a `PQ` computation in a larger schema.
189+-- | Evaluate a `PQ` and discard the `Connection` but keep the result.
179− :: Monad m
191+ :: Functor m
180 => PQ schema0 schema1 m x
192 => PQ schema0 schema1 m x
181− -> PQ (table ': schema0) (table : schema1) m x
193+ -> K LibPQ.Connection schema0
182−pqEmbed (PQ pq) = PQ $ \ (K conn) -> do
194+ -> m x
183− K x <- pq (K conn)
195+evalPQ (PQ pq) conn = unK <$> pq conn
185−
197+-- | An [Atkey indexed monad](https://bentnib.org/paramnotions-jfp.pdf) is a `Functor`
198+-- [enriched category](https://ncatlab.org/nlab/show/enriched+category).
199+-- An indexed monad transformer transforms a `Monad` into an indexed monad.
200+-- And, `IndexedMonadTransPQ` is a class for indexed monad transformers that
201+-- support running `Definition`s using `define` and embedding a computation
202+-- in a larger schema using `pqEmbed`.
203+class IndexedMonadTransPQ pq where
205+ -- | Safely embed a computation in a larger schema.
208+ => pq schema0 schema1 m x
209+ -> pq (table ': schema0) (table : schema1) m x
186−-- | indexed analog of `<*>`
211+ -- | indexed analog of `<*>`
188− :: Monad m
213+ :: Monad m
189− => PQ schema0 schema1 m (x -> y)
214+ => pq schema0 schema1 m (x -> y)
190− -> PQ schema1 schema2 m x
215+ -> pq schema1 schema2 m x
191− -> PQ schema0 schema2 m y
216+ -> pq schema0 schema2 m y
192−pqAp (PQ f) (PQ x) = PQ $ \ conn -> do
217+
194− K x' <- x (K (unK conn))
197−-- | indexed analog of `join`
218+ -- | indexed analog of `join`
199− :: Monad m
220+ :: Monad m
200− => PQ schema0 schema1 m (PQ schema1 schema2 m y)
221+ => pq schema0 schema1 m (pq schema1 schema2 m y)
201− -> PQ schema0 schema2 m y
222+ -> pq schema0 schema2 m y
202−pqJoin pq = pq & pqBind id
223+
204−-- | indexed analog of `=<<`
224+ -- | indexed analog of `=<<`
206− :: Monad m
226+ :: Monad m
207− => (x -> PQ schema1 schema2 m y)
227+ => (x -> pq schema1 schema2 m y)
208− -> PQ schema0 schema1 m x
228+ -> pq schema0 schema1 m x
209− -> PQ schema0 schema2 m y
229+ -> pq schema0 schema2 m y
210−pqBind f (PQ x) = PQ $ \ conn -> do
230+
212− runPQ (f x') (K (unK conn))
214−-- | indexed analog of flipped `>>`
231+ -- | indexed analog of flipped `>>`
216− :: Monad m
233+ :: Monad m
217− => PQ schema1 schema2 m y
234+ => pq schema1 schema2 m y
218− -> PQ schema0 schema1 m x
235+ -> pq schema0 schema1 m x
219− -> PQ schema0 schema2 m y
236+ -> pq schema0 schema2 m y
220−pqThen pq2 pq1 = pq1 & pqBind (\ _ -> pq2)
237+
222−-- | Run a `Definition` with `LibPQ.exec`, we expect that libpq obeys the law
238+ -- | Run a `Definition` with `LibPQ.exec`, we expect that libpq obeys the law
224−-- @define statement1 & thenDefine statement2 = define (statement1 >>> statement2)@
240+ -- @define statement1 & pqThen (define statement2) = define (statement1 >>> statement2)@
226− :: MonadBase IO io
242+ :: MonadBase IO io
227− => Definition schema0 schema1
243+ => Definition schema0 schema1
228− -> PQ schema0 schema1 io (K LibPQ.Result '[])
244+ -> pq schema0 schema1 io (K LibPQ.Result '[])
246+instance IndexedMonadTransPQ PQ where
248+ pqEmbed (PQ pq) = PQ $ \ (K conn) -> do
252+ pqAp (PQ f) (PQ x) = PQ $ \ conn -> do
254+ K x' <- x (K (unK conn))
257+ pqJoin pq = pq & pqBind id
259+ pqBind f (PQ x) = PQ $ \ conn -> do
261+ unPQ (f x') (K (unK conn))
263+ pqThen pq2 pq1 = pq1 & pqBind (\ _ -> pq2)
229−define (UnsafeDefinition q) = PQ $ \ (K conn) -> do
265+ define (UnsafeDefinition q) = PQ $ \ (K conn) -> do
230− resultMaybe <- liftBase $ LibPQ.exec conn q
266+ resultMaybe <- liftBase $ LibPQ.exec conn q
231− case resultMaybe of
267+ case resultMaybe of
232− Nothing -> error
268+ Nothing -> error
233− "define: LibPQ.exec returned no results"
269+ "define: LibPQ.exec returned no results"
234− Just result -> return $ K (K result)
270+ Just result -> return $ K (K result)
236−-- | Chain together `define` actions.
239− => Definition schema1 schema2
240− -> PQ schema0 schema1 io x
241− -> PQ schema0 schema2 io (K LibPQ.Result '[])
242−thenDefine = pqThen . define
244{- | `MonadPQ` is an `mtl` style constraint, similar to
272{- | `MonadPQ` is an `mtl` style constraint, similar to
245`Control.Monad.State.Class.MonadState`, for using `LibPQ` to
273`Control.Monad.State.Class.MonadState`, for using `LibPQ` to
@@ -468,7 +496,7 @@ type PQRun schema =
468-- | Helper function in defining `MonadBaseControl` instance for `PQ`.
496-- | Helper function in defining `MonadBaseControl` instance for `PQ`.
469pqliftWith :: Functor m => (PQRun schema -> m a) -> PQ schema schema m a
497pqliftWith :: Functor m => (PQRun schema -> m a) -> PQ schema schema m a
470pqliftWith f = PQ $ \ conn ->
498pqliftWith f = PQ $ \ conn ->
471− fmap K (f $ \ pq -> runPQ pq conn)
499+ fmap K (f $ \ pq -> unPQ pq conn)
473instance MonadBaseControl b m => MonadBaseControl b (PQ schema schema m) where
501instance MonadBaseControl b m => MonadBaseControl b (PQ schema schema m) where
474 type StM (PQ schema schema m) x = StM m (K x schema)
502 type StM (PQ schema schema m) x = StM m (K x schema)