generated from tpl/purs
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
3e9f22397d
|
|||
|
d3be053a8b
|
|||
|
1319a4bce7
|
|||
|
8722e69013
|
|||
|
5dc5912933
|
|||
|
a4d4e6bd75
|
|||
|
f0d2d764fe
|
|||
|
ea3ff9b003
|
|||
|
4832b594dc
|
|||
|
aad6544658
|
|||
|
89dec85a31
|
|||
|
5a99e58062
|
|||
|
02add2653a
|
|||
|
de1aaccfb6
|
|||
|
43ce1354ea
|
|||
|
87614611dd
|
|||
|
2ab53c43b2
|
|||
|
500e67d793
|
|||
|
ca95e0aa94
|
|||
|
bc120b072c
|
90
README.md
90
README.md
@@ -255,59 +255,59 @@ the api of [`node-postgres`]:
|
||||
- release clients with [`Pool.release`] or [`Pool.destroy`]
|
||||
- release with [`Pool.end`]
|
||||
|
||||
[`Pool`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Effect.Aff.Postgres.Pool#t:Pool
|
||||
[`Config`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Effect.Aff.Postgres.Pool#t:Config
|
||||
[`Pool.make`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Effect.Aff.Postgres.Pool#v:make
|
||||
[`Pool.end`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Effect.Aff.Postgres.Pool#v:end
|
||||
[`Pool.connect`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Effect.Aff.Postgres.Pool#v:connect
|
||||
[`Pool.destroy`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Effect.Aff.Postgres.Pool#v:destroy
|
||||
[`Pool.release`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Effect.Aff.Postgres.Pool#v:release
|
||||
[`Pool`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Effect.Aff.Postgres.Pool#t:Pool
|
||||
[`Config`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Effect.Aff.Postgres.Pool#t:Config
|
||||
[`Pool.make`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Effect.Aff.Postgres.Pool#v:make
|
||||
[`Pool.end`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Effect.Aff.Postgres.Pool#v:end
|
||||
[`Pool.connect`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Effect.Aff.Postgres.Pool#v:connect
|
||||
[`Pool.destroy`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Effect.Aff.Postgres.Pool#v:destroy
|
||||
[`Pool.release`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Effect.Aff.Postgres.Pool#v:release
|
||||
|
||||
[`Client`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Effect.Aff.Postgres.Client#t:Client
|
||||
[`Client.end`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Effect.Aff.Postgres.Client#v:end
|
||||
[`Client.make`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Effect.Aff.Postgres.Client#v:make
|
||||
[`Client.connected`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Effect.Aff.Postgres.Client#v:connected
|
||||
[`Client.query`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Effect.Aff.Postgres.Client#v:query
|
||||
[`Client.queryRaw`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Effect.Aff.Postgres.Client#v:queryRaw
|
||||
[`Client.exec`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Effect.Aff.Postgres.Client#v:exec
|
||||
[`Client`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Effect.Aff.Postgres.Client#t:Client
|
||||
[`Client.end`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Effect.Aff.Postgres.Client#v:end
|
||||
[`Client.make`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Effect.Aff.Postgres.Client#v:make
|
||||
[`Client.connected`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Effect.Aff.Postgres.Client#v:connected
|
||||
[`Client.query`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Effect.Aff.Postgres.Client#v:query
|
||||
[`Client.queryRaw`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Effect.Aff.Postgres.Client#v:queryRaw
|
||||
[`Client.exec`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Effect.Aff.Postgres.Client#v:exec
|
||||
|
||||
[`Range`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Range#t:Range
|
||||
[`Range.gt`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Range#v:gt
|
||||
[`Range.gte`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Range#v:gte
|
||||
[`Range.lt`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Range#v:lt
|
||||
[`Range.lte`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Range#v:lte
|
||||
[`Range`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Range#t:Range
|
||||
[`Range.gt`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Range#v:gt
|
||||
[`Range.gte`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Range#v:gte
|
||||
[`Range.lt`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Range#v:lt
|
||||
[`Range.lte`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Range#v:lte
|
||||
|
||||
[`Raw`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Raw#t:Raw
|
||||
[`Null`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Raw#t:Null
|
||||
[`Raw`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Raw#t:Raw
|
||||
[`Null`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Raw#t:Null
|
||||
|
||||
[`Serialize`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres#t:Serialize
|
||||
[`Deserialize`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres#t:Deserialize
|
||||
[`Rep`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres#t:Rep
|
||||
[`modifyPgTypes`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres#v:modifyPgTypes
|
||||
[`Serialize`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres#t:Serialize
|
||||
[`Deserialize`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres#t:Deserialize
|
||||
[`Rep`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres#t:Rep
|
||||
[`modifyPgTypes`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres#v:modifyPgTypes
|
||||
|
||||
[`Result`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Result#t:Result
|
||||
[`FromRow`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Result#t:FromRow
|
||||
[`FromRows`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Result#t:FromRows
|
||||
[`Result`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Result#t:Result
|
||||
[`FromRow`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Result#t:FromRow
|
||||
[`FromRows`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Result#t:FromRows
|
||||
|
||||
[`Query`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Query#t:Query
|
||||
[`AsQuery`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Query#t:AsQuery
|
||||
[`Query`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Query#t:Query
|
||||
[`AsQuery`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Query#t:AsQuery
|
||||
|
||||
[`Query.Builder`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Query.Builder#t:Builder
|
||||
[`Query.Builder.param`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Query.Builder#v:param
|
||||
[`Query.Builder.build`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Data.Postgres.Query.Builder#v:build
|
||||
[`Query.Builder`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Query.Builder#t:Builder
|
||||
[`Query.Builder.param`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Query.Builder#v:param
|
||||
[`Query.Builder.build`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Data.Postgres.Query.Builder#v:build
|
||||
|
||||
[`MonadCursor`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Control.Monad.Postgres#t:MonadCursor
|
||||
[`MonadSession`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Control.Monad.Postgres#t:MonadSession
|
||||
[`CursorT`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Control.Monad.Postgres#t:CursorT
|
||||
[`SessionT`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Control.Monad.Postgres#t:SessionT
|
||||
[`PostgresT`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Control.Monad.Postgres#t:PostgresT
|
||||
[`cursor`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Control.Monad.Postgres#v:cursor
|
||||
[`session`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Control.Monad.Postgres#v:session
|
||||
[`transaction`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Control.Monad.Postgres#v:transaction
|
||||
[`runPostgres`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Control.Monad.Postgres#v:runPostgres
|
||||
[`query`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Control.Monad.Postgres#v:query
|
||||
[`exec`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Control.Monad.Postgres#v:exec
|
||||
[`exec_`]: https://pursuit.purescript.org///////packages/purescript-postgresql/1.1.1/docs/Control.Monad.Postgres#v:exec_
|
||||
[`MonadCursor`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Control.Monad.Postgres#t:MonadCursor
|
||||
[`MonadSession`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Control.Monad.Postgres#t:MonadSession
|
||||
[`CursorT`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Control.Monad.Postgres#t:CursorT
|
||||
[`SessionT`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Control.Monad.Postgres#t:SessionT
|
||||
[`PostgresT`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Control.Monad.Postgres#t:PostgresT
|
||||
[`cursor`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Control.Monad.Postgres#v:cursor
|
||||
[`session`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Control.Monad.Postgres#v:session
|
||||
[`transaction`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Control.Monad.Postgres#v:transaction
|
||||
[`runPostgres`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Control.Monad.Postgres#v:runPostgres
|
||||
[`query`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Control.Monad.Postgres#v:query
|
||||
[`exec`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Control.Monad.Postgres#v:exec
|
||||
[`exec_`]: https://pursuit.purescript.org//////////////////packages/purescript-postgresql/1.3.0/docs/Control.Monad.Postgres#v:exec_
|
||||
|
||||
[`node-postgres`]: https://node-postgres.com/
|
||||
[`pg-types`]: https://github.com/brianc/node-pg-types/
|
||||
|
||||
46
spago.lock
46
spago.lock
@@ -32,9 +32,11 @@ workspace:
|
||||
- record: ">=4.0.0 <5.0.0"
|
||||
- simple-json: ">=9.0.0 <10.0.0"
|
||||
- strings: ">=6.0.1 <7.0.0"
|
||||
- tailrec: ">=6.1.0 <7.0.0"
|
||||
- transformers: ">=6.0.0 <7.0.0"
|
||||
- tuples: ">=7.0.0 <8.0.0"
|
||||
- typelevel-prelude: ">=7.0.0 <8.0.0"
|
||||
- unlift: ">=1.0.1 <2.0.0"
|
||||
- unsafe-coerce: ">=6.0.0 <7.0.0"
|
||||
test_dependencies:
|
||||
- filterable
|
||||
@@ -73,6 +75,7 @@ workspace:
|
||||
- fork
|
||||
- formatters
|
||||
- free
|
||||
- freet
|
||||
- functions
|
||||
- functors
|
||||
- gen
|
||||
@@ -86,6 +89,7 @@ workspace:
|
||||
- lists
|
||||
- maybe
|
||||
- mmorph
|
||||
- monad-control
|
||||
- newtype
|
||||
- node-buffer
|
||||
- node-child-process
|
||||
@@ -126,6 +130,7 @@ workspace:
|
||||
- typelevel-prelude
|
||||
- unfoldable
|
||||
- unicode
|
||||
- unlift
|
||||
- unsafe-coerce
|
||||
- variant
|
||||
package_set:
|
||||
@@ -923,6 +928,21 @@ packages:
|
||||
- transformers
|
||||
- tuples
|
||||
- unsafe-coerce
|
||||
freet:
|
||||
type: registry
|
||||
version: 7.0.0
|
||||
integrity: sha256-zkL6wU4ZPq8xz1kGFxoliWqyhBksepMJTyA68VEBaJo=
|
||||
dependencies:
|
||||
- aff
|
||||
- bifunctors
|
||||
- effect
|
||||
- either
|
||||
- exists
|
||||
- free
|
||||
- prelude
|
||||
- tailrec
|
||||
- transformers
|
||||
- tuples
|
||||
functions:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
@@ -1059,6 +1079,15 @@ packages:
|
||||
- free
|
||||
- functors
|
||||
- transformers
|
||||
monad-control:
|
||||
type: registry
|
||||
version: 5.0.0
|
||||
integrity: sha256-bgfDW30wbIm70NR1Tvvh9P+VFQMDh1wK2sSJXCj/dZc=
|
||||
dependencies:
|
||||
- aff
|
||||
- freet
|
||||
- identity
|
||||
- lists
|
||||
newtype:
|
||||
type: registry
|
||||
version: 5.0.0
|
||||
@@ -1566,6 +1595,23 @@ packages:
|
||||
- foldable-traversable
|
||||
- maybe
|
||||
- strings
|
||||
unlift:
|
||||
type: registry
|
||||
version: 1.0.1
|
||||
integrity: sha256-nbBCVV0fZz/3UHKoW11dcTwBYmQOIgK31ht2BN47RPw=
|
||||
dependencies:
|
||||
- aff
|
||||
- effect
|
||||
- either
|
||||
- freet
|
||||
- identity
|
||||
- lists
|
||||
- maybe
|
||||
- monad-control
|
||||
- prelude
|
||||
- st
|
||||
- transformers
|
||||
- tuples
|
||||
unsafe-coerce:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package:
|
||||
name: postgresql
|
||||
publish:
|
||||
version: '1.1.1'
|
||||
version: '1.3.0'
|
||||
license: 'GPL-3.0-or-later'
|
||||
location:
|
||||
githubOwner: 'cakekindel'
|
||||
@@ -42,9 +42,11 @@ package:
|
||||
- record: ">=4.0.0 <5.0.0"
|
||||
- simple-json: ">=9.0.0 <10.0.0"
|
||||
- strings: ">=6.0.1 <7.0.0"
|
||||
- tailrec: ">=6.1.0 <7.0.0"
|
||||
- transformers: ">=6.0.0 <7.0.0"
|
||||
- tuples: ">=7.0.0 <8.0.0"
|
||||
- typelevel-prelude: ">=7.0.0 <8.0.0"
|
||||
- unlift: ">=1.0.1 <2.0.0"
|
||||
- unsafe-coerce: ">=6.0.0 <7.0.0"
|
||||
test:
|
||||
main: Test.Main
|
||||
|
||||
@@ -7,17 +7,24 @@ import Control.Alternative (class Plus)
|
||||
import Control.Monad.Error.Class (class MonadError, class MonadThrow, catchError, throwError)
|
||||
import Control.Monad.Fork.Class (class MonadBracket, class MonadFork, class MonadKill, bracket, kill, never, uninterruptible)
|
||||
import Control.Monad.Morph (class MFunctor, class MMonad)
|
||||
import Control.Monad.Postgres.Cursor (class MonadCursor, CursorT)
|
||||
import Control.Monad.Postgres.Session (class MonadSession, SessionT, exec, exec_, query)
|
||||
import Control.Monad.Reader (class MonadAsk, class MonadReader, ReaderT, ask, local, runReaderT)
|
||||
import Control.Monad.Rec.Class (class MonadRec)
|
||||
import Control.Monad.Trans.Class (class MonadTrans, lift)
|
||||
import Control.Parallel (class Parallel, parallel, sequential)
|
||||
import Data.Newtype (class Newtype, unwrap, wrap)
|
||||
import Effect.Aff (Fiber)
|
||||
import Data.Postgres (RepT)
|
||||
import Data.Postgres.Query (class AsQuery, asQuery)
|
||||
import Data.Postgres.Raw (Raw)
|
||||
import Data.Postgres.Result (class FromRow, fromRow)
|
||||
import Data.Tuple.Nested ((/\))
|
||||
import Effect.Aff.Class (class MonadAff, liftAff)
|
||||
import Effect.Aff.Postgres.Pool (Pool)
|
||||
import Effect.Aff.Postgres.Pool as Pool
|
||||
import Effect.Aff.Unlift (class MonadUnliftAff)
|
||||
import Effect.Class (class MonadEffect, liftEffect)
|
||||
import Effect.Exception (Error)
|
||||
import Effect.Unlift (class MonadUnliftEffect)
|
||||
import Prim.Row (class Union)
|
||||
|
||||
-- | Monad handling pool resource acquisition & release
|
||||
@@ -57,6 +64,9 @@ derive newtype instance (Bind m) => Bind (PostgresT m)
|
||||
derive newtype instance (Monad m) => Monad (PostgresT m)
|
||||
derive newtype instance (MonadEffect m) => MonadEffect (PostgresT m)
|
||||
derive newtype instance (MonadAff m) => MonadAff (PostgresT m)
|
||||
derive newtype instance (MonadUnliftEffect m) => MonadUnliftEffect (PostgresT m)
|
||||
derive newtype instance (MonadUnliftAff m) => MonadUnliftAff (PostgresT m)
|
||||
derive newtype instance MonadRec m => MonadRec (PostgresT m)
|
||||
derive newtype instance MonadTrans (PostgresT)
|
||||
derive newtype instance (MonadThrow e m) => MonadThrow e (PostgresT m)
|
||||
derive newtype instance (MonadError e m) => MonadError e (PostgresT m)
|
||||
@@ -86,29 +96,48 @@ instance (MonadBracket e f m, MonadAff m) => MonadSession (PostgresT m) where
|
||||
exec = session <<< exec
|
||||
exec_ = session <<< exec_
|
||||
|
||||
-- | Lifts a session to `PostgresT`, releasing the client to the pool
|
||||
-- | after execution.
|
||||
session :: forall e f m a. MonadBracket e f m => MonadAff m => MonadSession (SessionT m) => SessionT m a -> PostgresT m a
|
||||
session m = do
|
||||
pool <- ask
|
||||
let
|
||||
acq = liftAff $ Pool.connect pool
|
||||
rel _ c = liftEffect $ Pool.release pool c
|
||||
lift $ bracket acq rel (runReaderT m)
|
||||
|
||||
-- | Lifts a session to `PostgresT`, running the session
|
||||
-- | in a transaction.
|
||||
-- | Typeclass generalizing `PostgresT`. Allows for dependency-injecting different
|
||||
-- | implementations of the idea of a postgres connection.
|
||||
-- |
|
||||
-- | If the session throws an error, the transaction will be
|
||||
-- | rolled back and the error rethrown.
|
||||
transaction :: forall m a. MonadBracket Error Fiber m => MonadAff m => MonadSession (SessionT m) => SessionT m a -> PostgresT m a
|
||||
transaction m =
|
||||
let
|
||||
begin = void $ exec "begin;"
|
||||
commit = m <* exec "commit;"
|
||||
rollback e = exec "rollback;" *> throwError e
|
||||
in
|
||||
session $ begin *> catchError commit rollback
|
||||
-- | - `session` - Session monad (for `PostgresT` this is `SessionT`)
|
||||
-- | - `cursor` - Cursor session monad (for `PostgresT` this is `CursorT`)
|
||||
-- | - `ct` - Open type parameter for cursor type. Don't pin this to a concrete type.
|
||||
class (MonadSession session, MonadCursor cursor ct) <= MonadPostgres m session cursor ct | m -> ct cursor session where
|
||||
-- | Run a session in `m`.
|
||||
session :: session ~> m
|
||||
-- | Run a session in `m`, wrapped in a transaction.
|
||||
-- |
|
||||
-- | If any errors are raised, the transaction is rolled back and
|
||||
-- | the error rethrown.
|
||||
transaction :: session ~> m
|
||||
-- | `cursor`, but using a custom deserialize function for the data
|
||||
-- | yielded by the cursor
|
||||
cursorWith :: forall q. AsQuery q => (Array Raw -> RepT ct) -> String -> q -> cursor ~> m
|
||||
|
||||
instance (MonadBracket e f m, MonadAff m, MonadSession (SessionT m), MonadCursor (CursorT t (SessionT m)) t) => MonadPostgres (PostgresT m) (SessionT m) (CursorT ct (SessionT m)) ct where
|
||||
session m = do
|
||||
pool <- ask
|
||||
let
|
||||
acq = liftAff $ Pool.connect pool
|
||||
rel _ c = liftEffect $ Pool.release pool c
|
||||
lift $ bracket acq rel (runReaderT m)
|
||||
transaction m =
|
||||
let
|
||||
begin = void $ exec "begin;"
|
||||
commit = m <* exec "commit;"
|
||||
rollback e = exec "rollback;" *> throwError e
|
||||
in
|
||||
session $ begin *> catchError commit rollback
|
||||
cursorWith f cur q m =
|
||||
transaction do
|
||||
q' <- liftEffect $ asQuery q
|
||||
exec_ $ "declare " <> cur <> " cursor for (" <> (unwrap q').text <> ");"
|
||||
runReaderT (unwrap m) (cur /\ f)
|
||||
|
||||
-- | Create a server-side cursor for a query in a transaction,
|
||||
-- | and execute a `CursorT` with a view to the new cursor.
|
||||
cursor :: forall @cursort t session cursor q a. MonadPostgres t session cursor cursort => AsQuery q => FromRow cursort => String -> q -> cursor a -> t a
|
||||
cursor = cursorWith fromRow
|
||||
|
||||
-- | Execute a `PostgresT` using an existing connection pool.
|
||||
-- |
|
||||
|
||||
@@ -6,23 +6,25 @@ import Control.Alt (class Alt)
|
||||
import Control.Alternative (class Plus)
|
||||
import Control.Monad.Error.Class (class MonadError, class MonadThrow)
|
||||
import Control.Monad.Fork.Class (class MonadBracket, class MonadFork, class MonadKill, bracket, kill, never, uninterruptible)
|
||||
import Control.Monad.Postgres.Base (PostgresT, transaction)
|
||||
import Control.Monad.Postgres.Session (class MonadSession, SessionT, exec, exec_, query)
|
||||
import Control.Monad.Reader (class MonadAsk, class MonadReader, ReaderT, ask, local, runReaderT)
|
||||
import Control.Monad.Postgres.Session (class MonadSession, exec, exec_, query)
|
||||
import Control.Monad.Reader (class MonadAsk, class MonadReader, ReaderT, ask, local)
|
||||
import Control.Monad.Rec.Class (class MonadRec)
|
||||
import Control.Monad.Trans.Class (class MonadTrans, lift)
|
||||
import Control.Parallel (class Parallel, parallel, sequential)
|
||||
import Data.Array as Array
|
||||
import Data.Maybe (Maybe)
|
||||
import Data.Newtype (class Newtype, unwrap, wrap)
|
||||
import Data.Postgres.Query (class AsQuery, asQuery)
|
||||
import Data.Postgres.Result (class FromRow)
|
||||
import Effect.Aff (Fiber)
|
||||
import Data.Postgres (RepT, smash)
|
||||
import Data.Postgres.Raw (Raw)
|
||||
import Data.Traversable (traverse)
|
||||
import Data.Tuple.Nested (type (/\), (/\))
|
||||
import Effect.Aff.Class (class MonadAff)
|
||||
import Effect.Aff.Unlift (class MonadUnliftAff)
|
||||
import Effect.Class (class MonadEffect, liftEffect)
|
||||
import Effect.Exception (Error)
|
||||
import Effect.Unlift (class MonadUnliftEffect)
|
||||
|
||||
newtype CursorT :: forall k. Type -> (k -> Type) -> k -> Type
|
||||
newtype CursorT t m a = CursorT (ReaderT String m a)
|
||||
newtype CursorT t m a = CursorT (ReaderT (String /\ (Array Raw -> RepT t)) m a)
|
||||
|
||||
derive instance Newtype (CursorT t m a) _
|
||||
derive newtype instance (Functor m) => Functor (CursorT t m)
|
||||
@@ -34,6 +36,9 @@ derive newtype instance (Bind m) => Bind (CursorT t m)
|
||||
derive newtype instance (Monad m) => Monad (CursorT t m)
|
||||
derive newtype instance (MonadEffect m) => MonadEffect (CursorT t m)
|
||||
derive newtype instance (MonadAff m) => MonadAff (CursorT t m)
|
||||
derive newtype instance MonadRec m => MonadRec (CursorT t m)
|
||||
derive newtype instance (MonadUnliftEffect m) => MonadUnliftEffect (CursorT t m)
|
||||
derive newtype instance (MonadUnliftAff m) => MonadUnliftAff (CursorT t m)
|
||||
derive newtype instance MonadTrans (CursorT t)
|
||||
derive newtype instance (MonadThrow e m) => MonadThrow e (CursorT t m)
|
||||
derive newtype instance (MonadError e m) => MonadError e (CursorT t m)
|
||||
@@ -46,10 +51,10 @@ instance (Monad m, MonadBracket e f (ReaderT String m), MonadBracket e f m) => M
|
||||
uninterruptible a = wrap $ uninterruptible $ unwrap a
|
||||
never = lift $ never
|
||||
|
||||
instance Monad m => MonadAsk String (CursorT t m) where
|
||||
instance Monad m => MonadAsk (String /\ (Array Raw -> RepT t)) (CursorT t m) where
|
||||
ask = wrap ask
|
||||
|
||||
instance Monad m => MonadReader String (CursorT t m) where
|
||||
instance Monad m => MonadReader (String /\ (Array Raw -> RepT t)) (CursorT t m) where
|
||||
local f m = wrap $ local f $ unwrap m
|
||||
|
||||
instance (Apply m, Apply p, Parallel p m) => Parallel (CursorT t p) (CursorT t m) where
|
||||
@@ -78,19 +83,21 @@ instance (Apply m, Apply p, Parallel p m) => Parallel (CursorT t p) (CursorT t m
|
||||
-- | e <- fetchAll -- 15..100
|
||||
-- | pure unit
|
||||
-- | ```
|
||||
class (MonadSession m, FromRow t) <= MonadCursor m t where
|
||||
class (MonadSession m) <= MonadCursor m t where
|
||||
-- | Fetch a specified number of rows from the cursor
|
||||
fetch :: Int -> m (Array t)
|
||||
-- | Fetch all remaining rows from the cursor
|
||||
fetchAll :: m (Array t)
|
||||
|
||||
instance (FromRow t, MonadSession m) => MonadCursor (CursorT t m) t where
|
||||
instance (MonadSession m) => MonadCursor (CursorT t m) t where
|
||||
fetch n = do
|
||||
cur <- ask
|
||||
query $ "fetch forward " <> show n <> " from " <> cur
|
||||
cur /\ f <- ask
|
||||
raw :: Array (Array Raw) <- query $ "fetch forward " <> show n <> " from " <> cur
|
||||
liftEffect $ smash $ traverse f raw
|
||||
fetchAll = do
|
||||
cur <- ask
|
||||
query $ "fetch all from " <> cur
|
||||
cur /\ f <- ask
|
||||
raw :: Array (Array Raw) <- query $ "fetch all from " <> cur
|
||||
liftEffect $ smash $ traverse f raw
|
||||
|
||||
instance (MonadSession m) => MonadSession (CursorT t m) where
|
||||
query = lift <<< query
|
||||
@@ -100,12 +107,3 @@ instance (MonadSession m) => MonadSession (CursorT t m) where
|
||||
-- | Fetch the next row from the cursor
|
||||
fetchOne :: forall m t. MonadCursor m t => m (Maybe t)
|
||||
fetchOne = Array.head <$> fetch 1
|
||||
|
||||
-- | Create a server-side cursor for a query in a transaction,
|
||||
-- | and execute a `CursorT` with a view to the new cursor.
|
||||
cursor :: forall m @t a q. AsQuery q => MonadAff m => MonadBracket Error Fiber m => MonadSession (SessionT m) => String -> q -> CursorT t (SessionT m) a -> PostgresT m a
|
||||
cursor cur q m =
|
||||
transaction do
|
||||
q' <- liftEffect $ asQuery q
|
||||
exec_ $ "declare " <> cur <> " cursor for (" <> (unwrap q').text <> ");"
|
||||
runReaderT (unwrap m) cur
|
||||
|
||||
@@ -5,6 +5,7 @@ import Prelude
|
||||
import Control.Alt ((<|>))
|
||||
import Control.Monad.Error.Class (liftMaybe)
|
||||
import Data.Array.NonEmpty.Internal (NonEmptyArray)
|
||||
import Data.Bifunctor (lmap)
|
||||
import Data.Foldable (intercalate)
|
||||
import Data.Generic.Rep (class Generic)
|
||||
import Data.Generic.Rep as G
|
||||
@@ -17,7 +18,7 @@ import Data.Postgres.Raw (Raw)
|
||||
import Data.Symbol (class IsSymbol)
|
||||
import Data.Traversable (find)
|
||||
import Data.Tuple (fst, snd)
|
||||
import Data.Tuple.Nested (type (/\))
|
||||
import Data.Tuple.Nested (type (/\), (/\))
|
||||
import Foreign (ForeignError(..))
|
||||
import Type.Prelude (Proxy(..), reflectSymbol)
|
||||
|
||||
@@ -45,19 +46,19 @@ defaultSerializeEnum :: forall @a ty. CustomEnum a ty => a -> RepT Raw
|
||||
defaultSerializeEnum = serialize <<< printEnum
|
||||
|
||||
class GenericCustomEnum a where
|
||||
genericEnumVariants' :: NonEmptyArray a
|
||||
genericEnumVariants' :: NonEmptyArray (a /\ String)
|
||||
genericParseEnum' :: String -> Maybe a
|
||||
genericPrintEnum' :: a -> String
|
||||
|
||||
instance IsSymbol n => GenericCustomEnum (G.Constructor n G.NoArguments) where
|
||||
genericEnumVariants' = pure (G.Constructor @n G.NoArguments)
|
||||
genericEnumVariants' = pure (G.Constructor @n G.NoArguments /\ reflectSymbol (Proxy @n))
|
||||
genericParseEnum' s
|
||||
| s == reflectSymbol (Proxy @n) = Just (G.Constructor @n G.NoArguments)
|
||||
| otherwise = Nothing
|
||||
genericPrintEnum' _ = reflectSymbol (Proxy @n)
|
||||
|
||||
instance (GenericCustomEnum a, GenericCustomEnum b) => GenericCustomEnum (G.Sum a b) where
|
||||
genericEnumVariants' = (G.Inl <$> genericEnumVariants' @a) <> (G.Inr <$> genericEnumVariants' @b)
|
||||
genericEnumVariants' = (lmap G.Inl <$> genericEnumVariants' @a) <> (lmap G.Inr <$> genericEnumVariants' @b)
|
||||
genericParseEnum' s = (G.Inl <$> genericParseEnum' @a s) <|> (G.Inr <$> genericParseEnum' @b s)
|
||||
genericPrintEnum' (G.Inl a) = genericPrintEnum' a
|
||||
genericPrintEnum' (G.Inr a) = genericPrintEnum' a
|
||||
@@ -65,8 +66,8 @@ instance (GenericCustomEnum a, GenericCustomEnum b) => GenericCustomEnum (G.Sum
|
||||
enumPrintExpr :: forall @a ty. CustomEnum a ty => a -> Maybe String
|
||||
enumPrintExpr = Just <<< (\s -> quoted s <> " :: " <> typeName @a) <<< printEnum
|
||||
|
||||
genericEnumVariants :: forall a g. Generic a g => GenericCustomEnum g => NonEmptyArray a
|
||||
genericEnumVariants = G.to <$> genericEnumVariants'
|
||||
genericEnumVariants :: forall a g. Generic a g => GenericCustomEnum g => NonEmptyArray (a /\ String)
|
||||
genericEnumVariants = lmap G.to <$> genericEnumVariants'
|
||||
|
||||
genericParseEnum :: forall a g. Generic a g => GenericCustomEnum g => String -> Maybe a
|
||||
genericParseEnum = map G.to <<< genericParseEnum'
|
||||
|
||||
@@ -8,7 +8,7 @@ import Data.Int as Int
|
||||
import Data.Maybe (Maybe)
|
||||
import Data.Nullable (Nullable)
|
||||
import Data.Nullable as Nullable
|
||||
import Data.Postgres (class Rep, RepT, deserialize)
|
||||
import Data.Postgres (class Deserialize, class Rep, RepT, deserialize)
|
||||
import Data.Postgres.Raw (Raw)
|
||||
import Data.Traversable (traverse)
|
||||
import Data.Tuple (Tuple)
|
||||
@@ -79,7 +79,7 @@ class FromRow (a :: Type) where
|
||||
-- | Performs the conversion
|
||||
fromRow :: Array Raw -> RepT a
|
||||
|
||||
instance (Rep a, FromRow b) => FromRow (a /\ b) where
|
||||
instance (Deserialize a, FromRow b) => FromRow (a /\ b) where
|
||||
minColumnCount _ = minColumnCount (Proxy @b) + 1
|
||||
fromRow r =
|
||||
let
|
||||
@@ -97,7 +97,7 @@ else instance FromRow (Array Raw) where
|
||||
else instance FromRow Unit where
|
||||
minColumnCount _ = 0
|
||||
fromRow _ = pure unit
|
||||
else instance Rep a => FromRow a where
|
||||
else instance Deserialize a => FromRow a where
|
||||
minColumnCount _ = 1
|
||||
fromRow r =
|
||||
let
|
||||
|
||||
27
src/Data.Postgres.Unresult.purs
Normal file
27
src/Data.Postgres.Unresult.purs
Normal file
@@ -0,0 +1,27 @@
|
||||
module Data.Postgres.Unresult where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Control.Monad.Error.Class (liftMaybe)
|
||||
import Control.Monad.State (StateT, runStateT, state)
|
||||
import Data.Array as Array
|
||||
import Data.Postgres (class Deserialize, RepT, deserialize, smash)
|
||||
import Data.Postgres.Raw (Raw)
|
||||
import Data.Tuple (fst)
|
||||
import Data.Tuple.Nested ((/\))
|
||||
import Effect.Class (liftEffect)
|
||||
import Foreign (ForeignError(..))
|
||||
|
||||
-- | Monad used to incrementally deserialize columns from a row
|
||||
type Unresult a = StateT { ix :: Int, row :: Array Raw } RepT a
|
||||
|
||||
-- | Run an `UnresultT`
|
||||
unresult :: forall a. Unresult a -> Array Raw -> RepT a
|
||||
unresult m row = fst <$> runStateT m { ix: 0, row }
|
||||
|
||||
-- | Take the next column from the row, unmarshalling into `a`
|
||||
take :: forall a. Deserialize a => Unresult a
|
||||
take = do
|
||||
raw <- state (\r -> Array.index r.row r.ix /\ r { ix = r.ix + 1 })
|
||||
raw' <- liftMaybe (pure $ ForeignError $ "Ran out of columns!") raw
|
||||
liftEffect $ smash $ deserialize raw'
|
||||
@@ -41,7 +41,7 @@ derive newtype instance ReadForeign a => ReadForeign (JSON a)
|
||||
foreign import modifyPgTypes :: Effect Unit
|
||||
|
||||
-- | The serialization & deserialization monad.
|
||||
type RepT a = ExceptT (NonEmptyList ForeignError) Effect a
|
||||
type RepT = ExceptT (NonEmptyList ForeignError) Effect
|
||||
|
||||
-- | Flatten to an Effect, `show`ing errors
|
||||
smash :: forall a. RepT a -> Effect a
|
||||
|
||||
@@ -10,7 +10,7 @@ import Data.Generic.Rep (class Generic)
|
||||
import Data.Maybe (Maybe(..))
|
||||
import Data.Newtype (unwrap)
|
||||
import Data.Postgres (class Deserialize, class Serialize, deserialize, serialize, smash)
|
||||
import Data.Postgres.Custom.Enum (class CustomEnum, create, enumDeserialize, enumPrintExpr, enumSerialize, genericEnumVariants, genericParseEnum, genericPrintEnum, parseEnum, printEnum)
|
||||
import Data.Postgres.Custom.Enum (class CustomEnum, create, defaultDeserializeEnum, defaultSerializeEnum, enumPrintExpr, genericEnumVariants, genericParseEnum, genericPrintEnum, parseEnum, printEnum)
|
||||
import Data.Show.Generic (genericShow)
|
||||
import Effect.Class (liftEffect)
|
||||
import Test.Spec (Spec, describe, it)
|
||||
@@ -25,10 +25,10 @@ instance Show Enum1 where
|
||||
show = genericShow
|
||||
|
||||
instance Serialize Enum1 where
|
||||
serialize a = enumSerialize a
|
||||
serialize a = defaultSerializeEnum a
|
||||
|
||||
instance Deserialize Enum1 where
|
||||
deserialize a = enumDeserialize a
|
||||
deserialize a = defaultDeserializeEnum a
|
||||
|
||||
instance CustomEnum Enum1 "enum_1" where
|
||||
printEnum = genericPrintEnum
|
||||
@@ -43,10 +43,10 @@ instance Show Enum2 where
|
||||
show = genericShow
|
||||
|
||||
instance Serialize Enum2 where
|
||||
serialize a = enumSerialize a
|
||||
serialize a = defaultSerializeEnum a
|
||||
|
||||
instance Deserialize Enum2 where
|
||||
deserialize a = enumDeserialize a
|
||||
deserialize a = defaultDeserializeEnum a
|
||||
|
||||
instance CustomEnum Enum2 "enum_2" where
|
||||
printEnum a = genericPrintEnum a
|
||||
@@ -61,10 +61,10 @@ instance Show Enum5 where
|
||||
show = genericShow
|
||||
|
||||
instance Serialize Enum5 where
|
||||
serialize a = enumSerialize a
|
||||
serialize a = defaultSerializeEnum a
|
||||
|
||||
instance Deserialize Enum5 where
|
||||
deserialize a = enumDeserialize a
|
||||
deserialize a = defaultDeserializeEnum a
|
||||
|
||||
instance CustomEnum Enum5 "enum_5" where
|
||||
printEnum a = genericPrintEnum a
|
||||
|
||||
Reference in New Issue
Block a user