29 Commits

Author SHA1 Message Date
aca76f7de3 chore: prepare v1.6.1 2024-05-11 20:45:41 -05:00
188403681a fix: pipes monad stuff 2024-05-11 20:45:04 -05:00
ca7ebb4337 chore: prepare v1.6.0 2024-05-11 13:26:44 -05:00
b3806d5f6e feat: add node-stream-pipes support 2024-05-11 13:25:27 -05:00
adb414662e chore: prepare v1.5.1 2024-04-30 19:26:35 -05:00
69721fcda4 chore: prepare v1.5.1 2024-04-30 19:26:21 -05:00
a616440abe chore: prepare v1.5.1 2024-04-30 19:26:20 -05:00
d66c3261b6 fix: impl Alternative 2024-04-30 19:26:01 -05:00
4e2fd8fa3f chore: prepare v1.5.0 2024-04-30 15:52:30 -05:00
e59266406b feat: streaming STDIO support 2024-04-30 15:46:10 -05:00
3be968da3a chore: prepare v1.4.0 2024-04-29 09:33:44 -05:00
20a0a6de31 chore: prepare v1.4.0 2024-04-29 09:32:23 -05:00
036a7b5de9 chore: prepare v1.4.0 2024-04-29 09:32:19 -05:00
639bee96d0 chore: prepare v 2024-04-29 09:32:05 -05:00
24b2156524 feat: MOVE support for cursors, RowsAffected 2024-04-29 09:31:49 -05:00
3e9f22397d chore: prepare v1.3.0 2024-04-11 16:45:35 -05:00
d3be053a8b chore: prepare v1.3.0 2024-04-11 16:45:27 -05:00
1319a4bce7 chore: prepare v1.3.0 2024-04-11 16:45:25 -05:00
8722e69013 feat: generalize PostgresT to MonadPostgres to allow mocking 2024-04-11 16:45:13 -05:00
5dc5912933 chore: prepare v1.2.7 2024-04-11 15:55:22 -05:00
a4d4e6bd75 fix: impl unlift 2024-04-11 15:55:11 -05:00
f0d2d764fe chore: prepare v1.2.6 2024-04-11 15:38:10 -05:00
ea3ff9b003 chore: lockfile 2024-04-11 15:38:01 -05:00
4832b594dc chore: prepare v1.2.5 2024-04-11 15:37:35 -05:00
aad6544658 chore: ranges 2024-04-11 15:37:29 -05:00
89dec85a31 chore: prepare v1.2.4 2024-04-11 15:36:40 -05:00
5a99e58062 fix: impl monadrec 2024-04-11 15:36:31 -05:00
02add2653a chore: prepare v1.2.3 2024-04-05 22:15:26 -05:00
de1aaccfb6 fix: pin unresult api to rept 2024-04-05 22:15:18 -05:00
14 changed files with 454 additions and 680 deletions

100
README.md
View File

@@ -116,6 +116,8 @@ which is implemented for:
- `Array a` where `a` is [`FromRow`]
- `Maybe a` where `a` is [`FromRow`] (equivalent to `Array.head <<< fromRows`)
- `a` where `a` is [`FromRow`] (throws if 0 rows yielded)
- `RowsAffected`
- Extracts the number of rows processed by the last command in the query (ex. `INSERT INTO foo (bar) VALUES ('a'), ('b')` -> `INSERT 2` -> `RowsAffected 2`)
### Data - Ranges
Postgres ranges are represented with [`Range`].
@@ -223,9 +225,11 @@ Execute [`CursorT`] monads with [`cursor`]:
dbMain :: PostgresT Aff Int
dbMain =
cursor @(Int /\ String) "people_cursor" "select id, name from persons" do
fetchOne -- Just (1 /\ "Henry")
fetchAll -- [2 /\ "Sarah"]
fetchOne -- Nothing
a <- fetchOne -- Just (1 /\ "Henry")
b <- fetchOne -- Just (2 /\ "Sarah")
void $ move (MoveRelative -2)
c <- fetchAll -- [1 /\ "Henry", 2 /\ "Sarah"]
d <- fetchOne -- Nothing
```
### Monads - `SessionT`
@@ -255,59 +259,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.2.2/docs/Effect.Aff.Postgres.Pool#t:Pool
[`Config`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Effect.Aff.Postgres.Pool#t:Config
[`Pool.make`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Effect.Aff.Postgres.Pool#v:make
[`Pool.end`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Effect.Aff.Postgres.Pool#v:end
[`Pool.connect`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Effect.Aff.Postgres.Pool#v:connect
[`Pool.destroy`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Effect.Aff.Postgres.Pool#v:destroy
[`Pool.release`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Effect.Aff.Postgres.Pool#v:release
[`Pool`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Effect.Aff.Postgres.Pool#t:Pool
[`Config`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Effect.Aff.Postgres.Pool#t:Config
[`Pool.make`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Effect.Aff.Postgres.Pool#v:make
[`Pool.end`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Effect.Aff.Postgres.Pool#v:end
[`Pool.connect`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Effect.Aff.Postgres.Pool#v:connect
[`Pool.destroy`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Effect.Aff.Postgres.Pool#v:destroy
[`Pool.release`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Effect.Aff.Postgres.Pool#v:release
[`Client`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Effect.Aff.Postgres.Client#t:Client
[`Client.end`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Effect.Aff.Postgres.Client#v:end
[`Client.make`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Effect.Aff.Postgres.Client#v:make
[`Client.connected`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Effect.Aff.Postgres.Client#v:connected
[`Client.query`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Effect.Aff.Postgres.Client#v:query
[`Client.queryRaw`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Effect.Aff.Postgres.Client#v:queryRaw
[`Client.exec`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Effect.Aff.Postgres.Client#v:exec
[`Client`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Effect.Aff.Postgres.Client#t:Client
[`Client.end`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Effect.Aff.Postgres.Client#v:end
[`Client.make`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Effect.Aff.Postgres.Client#v:make
[`Client.connected`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Effect.Aff.Postgres.Client#v:connected
[`Client.query`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Effect.Aff.Postgres.Client#v:query
[`Client.queryRaw`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Effect.Aff.Postgres.Client#v:queryRaw
[`Client.exec`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Effect.Aff.Postgres.Client#v:exec
[`Range`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Range#t:Range
[`Range.gt`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Range#v:gt
[`Range.gte`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Range#v:gte
[`Range.lt`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Range#v:lt
[`Range.lte`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Range#v:lte
[`Range`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Range#t:Range
[`Range.gt`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Range#v:gt
[`Range.gte`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Range#v:gte
[`Range.lt`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Range#v:lt
[`Range.lte`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Range#v:lte
[`Raw`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Raw#t:Raw
[`Null`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Raw#t:Null
[`Raw`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Raw#t:Raw
[`Null`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Raw#t:Null
[`Serialize`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres#t:Serialize
[`Deserialize`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres#t:Deserialize
[`Rep`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres#t:Rep
[`modifyPgTypes`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres#v:modifyPgTypes
[`Serialize`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres#t:Serialize
[`Deserialize`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres#t:Deserialize
[`Rep`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres#t:Rep
[`modifyPgTypes`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres#v:modifyPgTypes
[`Result`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Result#t:Result
[`FromRow`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Result#t:FromRow
[`FromRows`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Result#t:FromRows
[`Result`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Result#t:Result
[`FromRow`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Result#t:FromRow
[`FromRows`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Result#t:FromRows
[`Query`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Query#t:Query
[`AsQuery`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Query#t:AsQuery
[`Query`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Query#t:Query
[`AsQuery`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Query#t:AsQuery
[`Query.Builder`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Query.Builder#t:Builder
[`Query.Builder.param`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Query.Builder#v:param
[`Query.Builder.build`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Data.Postgres.Query.Builder#v:build
[`Query.Builder`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Query.Builder#t:Builder
[`Query.Builder.param`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Query.Builder#v:param
[`Query.Builder.build`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Data.Postgres.Query.Builder#v:build
[`MonadCursor`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Control.Monad.Postgres#t:MonadCursor
[`MonadSession`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Control.Monad.Postgres#t:MonadSession
[`CursorT`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Control.Monad.Postgres#t:CursorT
[`SessionT`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Control.Monad.Postgres#t:SessionT
[`PostgresT`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Control.Monad.Postgres#t:PostgresT
[`cursor`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Control.Monad.Postgres#v:cursor
[`session`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Control.Monad.Postgres#v:session
[`transaction`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Control.Monad.Postgres#v:transaction
[`runPostgres`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Control.Monad.Postgres#v:runPostgres
[`query`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Control.Monad.Postgres#v:query
[`exec`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Control.Monad.Postgres#v:exec
[`exec_`]: https://pursuit.purescript.org//////////packages/purescript-postgresql/1.2.2/docs/Control.Monad.Postgres#v:exec_
[`MonadCursor`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Control.Monad.Postgres#t:MonadCursor
[`MonadSession`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Control.Monad.Postgres#t:MonadSession
[`CursorT`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Control.Monad.Postgres#t:CursorT
[`SessionT`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Control.Monad.Postgres#t:SessionT
[`PostgresT`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Control.Monad.Postgres#t:PostgresT
[`cursor`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Control.Monad.Postgres#v:cursor
[`session`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Control.Monad.Postgres#v:session
[`transaction`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Control.Monad.Postgres#v:transaction
[`runPostgres`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Control.Monad.Postgres#v:runPostgres
[`query`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Control.Monad.Postgres#v:query
[`exec`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Control.Monad.Postgres#v:exec
[`exec_`]: https://pursuit.purescript.org///////////////////////////////////packages/purescript-postgresql/1.6.1/Control.Monad.Postgres#v:exec_
[`node-postgres`]: https://node-postgres.com/
[`pg-types`]: https://github.com/brianc/node-pg-types/

BIN
bun.lockb

Binary file not shown.

View File

@@ -1,5 +1,5 @@
{
"name": "purs",
"name": "purescript-postgresql",
"private": true,
"module": "index.js",
"type": "module",
@@ -14,6 +14,7 @@
"dependencies": {
"decimal.js": "^10.4.3",
"pg": "^8.11.3",
"pg-copy-streams": "^6.0.6",
"postgres-range": "^1.1.4"
}
}

View File

@@ -3,44 +3,50 @@ workspace:
postgresql:
path: ./
dependencies:
- aff: ">=7.1.0 <8.0.0"
- aff-promise: ">=4.0.0 <5.0.0"
- arrays: ">=7.3.0 <8.0.0"
- bifunctors: ">=6.0.0 <7.0.0"
- control: ">=6.0.0 <7.0.0"
- datetime: ">=6.1.0 <7.0.0"
- effect: ">=4.0.0 <5.0.0"
- either: ">=6.1.0 <7.0.0"
- exceptions: ">=6.0.0 <7.0.0"
- foldable-traversable: ">=6.0.0 <7.0.0"
- foreign: ">=7.0.0 <8.0.0"
- fork: ">=6.0.0 <7.0.0"
- integers: ">=6.0.0 <7.0.0"
- js-bigints: ">=2.2.1 <3.0.0"
- lists: ">=7.0.0 <8.0.0"
- maybe: ">=6.0.0 <7.0.0"
- mmorph: ">=7.0.0 <8.0.0"
- newtype: ">=5.0.0 <6.0.0"
- node-buffer: ">=9.0.0 <10.0.0"
- node-event-emitter: ">=3.0.0 <4.0.0"
- nullable: ">=6.0.0 <7.0.0"
- parallel: ">=6.0.0 <7.0.0"
- partial: ">=4.0.0 <5.0.0"
- precise-datetime: ">=7.0.0 <8.0.0"
- prelude: ">=6.0.1 <7.0.0"
- profunctor: ">=6.0.1 <7.0.0"
- record: ">=4.0.0 <5.0.0"
- simple-json: ">=9.0.0 <10.0.0"
- strings: ">=6.0.1 <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"
- unsafe-coerce: ">=6.0.0 <7.0.0"
- aff
- aff-promise
- arrays
- bifunctors
- control
- datetime
- effect
- either
- exceptions
- foldable-traversable
- foreign
- fork
- integers
- js-bigints
- lists
- maybe
- mmorph
- newtype
- node-buffer
- node-event-emitter
- node-stream-pipes
- node-streams
- nullable
- parallel
- partial
- pipes
- precise-datetime
- prelude
- profunctor
- record
- simple-json
- strings
- tailrec
- transformers
- tuples
- typelevel-prelude
- unlift
- unsafe-coerce
test_dependencies:
- filterable
- foreign-object
- node-child-process
- node-process
- precise-datetime
- quickcheck
- spec
- spec-quickcheck
@@ -73,6 +79,7 @@ workspace:
- fork
- formatters
- free
- freet
- functions
- functors
- gen
@@ -86,6 +93,7 @@ workspace:
- lists
- maybe
- mmorph
- monad-control
- newtype
- node-buffer
- node-child-process
@@ -94,7 +102,9 @@ workspace:
- node-os
- node-path
- node-process
- node-stream-pipes
- node-streams
- node-zlib
- nonempty
- now
- nullable
@@ -126,489 +136,9 @@ workspace:
- typelevel-prelude
- unfoldable
- unicode
- unlift
- unsafe-coerce
- variant
package_set:
address:
registry: 50.5.0
compiler: ">=0.15.15 <0.16.0"
content:
abc-parser: 2.0.1
ace: 9.1.0
aff: 7.1.0
aff-bus: 6.0.0
aff-coroutines: 9.0.0
aff-promise: 4.0.0
aff-retry: 2.0.0
affjax: 13.0.0
affjax-node: 1.0.0
affjax-web: 1.0.0
ansi: 7.0.0
applicative-phases: 1.0.0
argonaut: 9.0.0
argonaut-aeson-generic: 0.4.1
argonaut-codecs: 9.1.0
argonaut-core: 7.0.0
argonaut-generic: 8.0.0
argonaut-traversals: 10.0.0
argparse-basic: 2.0.0
array-builder: 0.1.2
array-search: 0.5.6
arraybuffer: 13.2.0
arraybuffer-builder: 3.1.0
arraybuffer-types: 3.0.2
arrays: 7.3.0
arrays-extra: 0.6.1
arrays-zipper: 2.0.1
ask: 1.0.0
assert: 6.0.0
assert-multiple: 0.3.4
avar: 5.0.0
b64: 0.0.8
barbies: 1.0.1
barlow-lens: 0.9.0
bifunctors: 6.0.0
bigints: 7.0.1
bolson: 0.3.9
bookhound: 0.1.7
bower-json: 3.0.0
call-by-name: 4.0.1
canvas: 6.0.0
canvas-action: 9.0.0
cartesian: 1.0.6
catenable-lists: 7.0.0
chameleon: 1.0.0
chameleon-halogen: 1.0.3
chameleon-react-basic: 1.1.0
chameleon-styled: 2.5.0
chameleon-transformers: 1.0.0
channel: 1.0.0
checked-exceptions: 3.1.1
choku: 1.0.1
classless: 0.1.1
classless-arbitrary: 0.1.1
classless-decode-json: 0.1.1
classless-encode-json: 0.1.3
classnames: 2.0.0
codec: 6.1.0
codec-argonaut: 10.0.0
codec-json: 1.1.0
colors: 7.0.1
concur-core: 0.5.0
concur-react: 0.5.0
concurrent-queues: 3.0.0
console: 6.1.0
const: 6.0.0
contravariant: 6.0.0
control: 6.0.0
convertable-options: 1.0.0
coroutines: 7.0.0
css: 6.0.0
css-frameworks: 1.0.1
data-mvc: 0.0.2
datetime: 6.1.0
datetime-parsing: 0.2.0
debug: 6.0.2
decimals: 7.1.0
default-values: 1.0.1
deku: 0.9.23
deno: 0.0.5
dissect: 1.0.0
distributive: 6.0.0
dom-filereader: 7.0.0
dom-indexed: 12.0.0
dotenv: 4.0.3
droplet: 0.6.0
dts: 1.0.0
dual-numbers: 1.0.2
dynamic-buffer: 3.0.1
echarts-simple: 0.0.1
effect: 4.0.0
either: 6.1.0
elmish: 0.11.3
elmish-enzyme: 0.1.1
elmish-hooks: 0.10.0
elmish-html: 0.8.2
elmish-testing-library: 0.3.2
email-validate: 7.0.0
encoding: 0.0.9
enums: 6.0.1
env-names: 0.3.4
error: 2.0.0
eta-conversion: 0.3.2
exceptions: 6.0.0
exists: 6.0.0
exitcodes: 4.0.0
expect-inferred: 3.0.0
fahrtwind: 2.0.0
fallback: 0.1.0
fast-vect: 1.2.0
fetch: 4.1.0
fetch-argonaut: 1.0.1
fetch-core: 5.1.0
fetch-yoga-json: 1.1.0
fft-js: 0.1.0
filterable: 5.0.0
fix-functor: 0.1.0
fixed-points: 7.0.0
fixed-precision: 5.0.0
flame: 1.3.0
float32: 2.0.0
fmt: 0.2.1
foldable-traversable: 6.0.0
foldable-traversable-extra: 0.0.6
foreign: 7.0.0
foreign-object: 4.1.0
foreign-readwrite: 3.4.0
forgetmenot: 0.1.0
fork: 6.0.0
form-urlencoded: 7.0.0
formatters: 7.0.0
framer-motion: 1.0.1
free: 7.1.0
freeap: 7.0.0
freer-free: 0.0.1
freet: 7.0.0
functions: 6.0.0
functor1: 3.0.0
functors: 5.0.0
fuzzy: 0.4.0
gen: 4.0.0
generate-values: 1.0.1
generic-router: 0.0.1
geojson: 0.0.5
geometry-plane: 1.0.3
gojs: 0.1.1
grain: 3.0.0
grain-router: 3.0.0
grain-virtualized: 3.0.0
graphs: 8.1.0
group: 4.1.1
halogen: 7.0.0
halogen-bootstrap5: 5.3.2
halogen-canvas: 1.0.0
halogen-css: 10.0.0
halogen-echarts-simple: 0.0.4
halogen-formless: 4.0.3
halogen-helix: 1.0.0
halogen-hooks: 0.6.3
halogen-hooks-extra: 0.9.0
halogen-infinite-scroll: 1.1.0
halogen-store: 0.5.4
halogen-storybook: 2.0.0
halogen-subscriptions: 2.0.0
halogen-svg-elems: 8.0.0
halogen-typewriter: 1.0.4
halogen-vdom: 8.0.0
halogen-vdom-string-renderer: 0.5.0
halogen-xterm: 2.0.0
heckin: 2.0.1
heterogeneous: 0.6.0
homogeneous: 0.4.0
http-methods: 6.0.0
httpurple: 4.0.0
humdrum: 0.0.1
hyrule: 2.3.8
identity: 6.0.0
identy: 4.0.1
indexed-db: 1.0.0
indexed-monad: 3.0.0
int64: 3.0.0
integers: 6.0.0
interpolate: 5.0.2
intersection-observer: 1.0.1
invariant: 6.0.0
jarilo: 1.0.1
jelly: 0.10.0
jelly-router: 0.3.0
jelly-signal: 0.4.0
jest: 1.0.0
js-abort-controller: 1.0.0
js-bigints: 2.2.1
js-date: 8.0.0
js-fetch: 0.2.1
js-fileio: 3.0.0
js-intl: 1.0.4
js-iterators: 0.1.1
js-maps: 0.1.2
js-promise: 1.0.0
js-promise-aff: 1.0.0
js-timers: 6.1.0
js-uri: 3.1.0
json: 1.0.0
json-codecs: 5.0.0
justifill: 0.5.0
jwt: 0.0.9
labeled-data: 0.2.0
language-cst-parser: 0.14.0
lazy: 6.0.0
lazy-joe: 1.0.0
lcg: 4.0.0
leibniz: 5.0.0
leveldb: 1.0.1
liminal: 1.0.1
linalg: 6.0.0
lists: 7.0.0
literals: 1.0.2
logging: 3.0.0
logging-journald: 0.4.0
lumi-components: 18.0.0
machines: 7.0.0
maps-eager: 0.4.1
marionette: 1.0.0
marionette-react-basic-hooks: 0.1.1
marked: 0.1.0
matrices: 5.0.1
matryoshka: 1.0.0
maybe: 6.0.0
media-types: 6.0.0
meowclient: 1.0.0
midi: 4.0.0
milkis: 9.0.0
minibench: 4.0.1
mmorph: 7.0.0
monad-control: 5.0.0
monad-logger: 1.3.1
monad-loops: 0.5.0
monad-unlift: 1.0.1
monoid-extras: 0.0.1
monoidal: 0.16.0
morello: 0.4.0
mote: 3.0.0
motsunabe: 2.0.0
mvc: 0.0.1
mysql: 6.0.1
n3: 0.1.0
nano-id: 1.1.0
nanoid: 0.1.0
naturals: 3.0.0
nested-functor: 0.2.1
newtype: 5.0.0
nextjs: 0.1.1
nextui: 0.2.0
node-buffer: 9.0.0
node-child-process: 11.1.0
node-event-emitter: 3.0.0
node-execa: 5.0.0
node-fs: 9.1.0
node-glob-basic: 1.3.0
node-http: 9.1.0
node-http2: 1.1.1
node-human-signals: 1.0.0
node-net: 5.1.0
node-os: 5.1.0
node-path: 5.0.0
node-process: 11.2.0
node-readline: 8.1.0
node-sqlite3: 8.0.0
node-streams: 9.0.0
node-tls: 0.3.1
node-url: 7.0.1
node-zlib: 0.4.0
nonempty: 7.0.0
now: 6.0.0
npm-package-json: 2.0.0
nullable: 6.0.0
numberfield: 0.1.0
numbers: 9.0.1
oak: 3.1.1
oak-debug: 1.2.2
object-maps: 0.3.0
ocarina: 1.5.4
open-folds: 6.3.0
open-memoize: 6.1.0
open-pairing: 6.1.0
options: 7.0.0
optparse: 5.0.1
ordered-collections: 3.2.0
ordered-set: 0.4.0
orders: 6.0.0
owoify: 1.2.0
pairs: 9.0.1
parallel: 7.0.0
parsing: 10.2.0
parsing-dataview: 3.2.4
partial: 4.0.0
pathy: 9.0.0
pha: 0.13.0
phaser: 0.7.0
phylio: 1.1.2
pipes: 8.0.0
pirates-charm: 0.0.1
pmock: 0.9.0
point-free: 1.0.0
pointed-list: 0.5.1
polymorphic-vectors: 4.0.0
posix-types: 6.0.0
precise: 6.0.0
precise-datetime: 7.0.0
prelude: 6.0.1
prettier-printer: 3.0.0
profunctor: 6.0.1
profunctor-lenses: 8.0.0
protobuf: 4.3.0
psa-utils: 8.0.0
psci-support: 6.0.0
punycode: 1.0.0
qualified-do: 2.2.0
quantities: 12.2.0
quickcheck: 8.0.1
quickcheck-combinators: 0.1.3
quickcheck-laws: 7.0.0
quickcheck-utf8: 0.0.0
random: 6.0.0
rationals: 6.0.0
rdf: 0.1.0
react: 11.0.0
react-aria: 0.2.0
react-basic: 17.0.0
react-basic-classic: 3.0.0
react-basic-dnd: 10.1.0
react-basic-dom: 6.1.0
react-basic-emotion: 7.1.0
react-basic-hooks: 8.2.0
react-basic-storybook: 2.0.0
react-dom: 8.0.0
react-halo: 3.0.0
react-icons: 1.1.4
react-markdown: 0.1.0
react-testing-library: 4.0.1
react-virtuoso: 1.0.0
read: 1.0.1
recharts: 1.1.0
record: 4.0.0
record-extra: 5.0.1
record-ptional-fields: 0.1.2
record-studio: 1.0.4
refs: 6.0.0
remotedata: 5.0.1
resize-observer: 1.0.0
resource: 2.0.1
resourcet: 1.0.0
result: 1.0.3
return: 0.2.0
ring-modules: 5.0.1
rito: 0.3.4
rough-notation: 1.0.2
routing: 11.0.0
routing-duplex: 0.7.0
run: 5.0.0
safe-coerce: 2.0.0
safely: 4.0.1
school-of-music: 1.3.0
selection-foldable: 0.2.0
selective-functors: 1.0.1
semirings: 7.0.0
signal: 13.0.0
simple-emitter: 3.0.1
simple-i18n: 2.0.1
simple-json: 9.0.0
simple-ulid: 3.0.0
sized-matrices: 1.0.0
sized-vectors: 5.0.2
slug: 3.0.8
small-ffi: 4.0.1
soundfonts: 4.1.0
sparse-matrices: 1.3.0
sparse-polynomials: 2.0.5
spec: 7.6.0
spec-mocha: 5.1.0
spec-quickcheck: 5.0.0
splitmix: 2.1.0
ssrs: 1.0.0
st: 6.2.0
statistics: 0.3.2
strictlypositiveint: 1.0.1
string-parsers: 8.0.0
strings: 6.0.1
strings-extra: 4.0.0
stringutils: 0.0.12
substitute: 0.2.3
supply: 0.2.0
svg-parser: 3.0.0
systemd-journald: 0.3.0
tagged: 4.0.2
tailrec: 6.1.0
tecton: 0.2.1
tecton-halogen: 0.2.0
test-unit: 17.0.0
thermite: 6.3.1
thermite-dom: 0.3.1
these: 6.0.0
transformation-matrix: 1.0.1
transformers: 6.0.0
tree-rose: 4.0.2
ts-bridge: 4.0.0
tuples: 7.0.0
two-or-more: 1.0.0
type-equality: 4.0.1
typedenv: 2.0.1
typelevel: 6.0.0
typelevel-lists: 2.1.0
typelevel-peano: 1.0.1
typelevel-prelude: 7.0.0
typelevel-regex: 0.0.3
typelevel-rows: 0.1.0
uint: 7.0.0
ulid: 3.0.1
uncurried-transformers: 1.1.0
undefined: 2.0.0
undefined-is-not-a-problem: 1.1.0
unfoldable: 6.0.0
unicode: 6.0.0
unique: 0.6.1
unlift: 1.0.1
unordered-collections: 3.1.0
unsafe-coerce: 6.0.0
unsafe-reference: 5.0.0
untagged-to-tagged: 0.1.4
untagged-union: 1.0.0
uri: 9.0.0
uuid: 9.0.0
uuidv4: 1.0.0
validation: 6.0.0
variant: 8.0.0
variant-encodings: 2.0.0
vectorfield: 1.0.1
vectors: 2.1.0
versions: 7.0.0
visx: 0.0.2
web-clipboard: 5.0.0
web-cssom: 2.0.0
web-cssom-view: 0.1.0
web-dom: 6.0.0
web-dom-parser: 8.0.0
web-dom-xpath: 3.0.0
web-encoding: 3.0.0
web-events: 4.0.0
web-fetch: 4.0.1
web-file: 4.0.0
web-geometry: 0.1.0
web-html: 4.1.0
web-pointerevents: 2.0.0
web-proletarian: 1.0.0
web-promise: 3.2.0
web-resize-observer: 2.1.0
web-router: 1.0.0
web-socket: 4.0.0
web-storage: 5.0.0
web-streams: 4.0.0
web-touchevents: 4.0.0
web-uievents: 5.0.0
web-url: 2.0.0
web-workers: 1.1.0
web-xhr: 5.0.1
webextension-polyfill: 0.1.0
webgpu: 0.0.1
which: 2.0.0
xterm: 1.0.0
yoga-fetch: 1.0.1
yoga-json: 5.1.0
yoga-om: 0.1.0
yoga-postgres: 6.0.0
yoga-tree: 1.0.0
z3: 0.0.2
zipperarray: 2.0.0
extra_packages: {}
packages:
aff:
@@ -923,6 +453,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 +604,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
@@ -1171,6 +725,35 @@ packages:
- posix-types
- prelude
- unsafe-coerce
node-stream-pipes:
type: registry
version: 1.0.2
integrity: sha256-JC5eIR1mFq3wuALBwezoQnJdXw4a4XoHfu8vtMu8xUI=
dependencies:
- aff
- arrays
- effect
- either
- exceptions
- foldable-traversable
- maybe
- mmorph
- newtype
- node-buffer
- node-event-emitter
- node-fs
- node-path
- node-streams
- node-zlib
- parallel
- pipes
- prelude
- st
- strings
- tailrec
- transformers
- tuples
- unsafe-coerce
node-streams:
type: registry
version: 9.0.0
@@ -1184,6 +767,19 @@ packages:
- node-event-emitter
- nullable
- prelude
node-zlib:
type: registry
version: 0.4.0
integrity: sha256-kYSajFQFzWVg71l5/y4w4kXdTr5EJoqyV3D2RqmAjQ4=
dependencies:
- aff
- effect
- either
- functions
- node-buffer
- node-streams
- prelude
- unsafe-coerce
nonempty:
type: registry
version: 7.0.0
@@ -1242,8 +838,8 @@ packages:
- prelude
parallel:
type: registry
version: 7.0.0
integrity: sha256-gUC9i4Txnx9K9RcMLsjujbwZz6BB1bnE2MLvw4GIw5o=
version: 6.0.0
integrity: sha256-VJbkGD0rAKX+NUEeBJbYJ78bEKaZbgow+QwQEfPB6ko=
dependencies:
- control
- effect
@@ -1566,6 +1162,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

View File

@@ -1,7 +1,7 @@
package:
name: postgresql
publish:
version: '1.2.2'
version: '1.6.1'
license: 'GPL-3.0-or-later'
location:
githubOwner: 'cakekindel'
@@ -13,39 +13,44 @@ package:
strict: true
pedanticPackages: true
dependencies:
- aff: ">=7.1.0 <8.0.0"
- aff-promise: ">=4.0.0 <5.0.0"
- arrays: ">=7.3.0 <8.0.0"
- bifunctors: ">=6.0.0 <7.0.0"
- control: ">=6.0.0 <7.0.0"
- datetime: ">=6.1.0 <7.0.0"
- effect: ">=4.0.0 <5.0.0"
- either: ">=6.1.0 <7.0.0"
- exceptions: ">=6.0.0 <7.0.0"
- foldable-traversable: ">=6.0.0 <7.0.0"
- foreign: ">=7.0.0 <8.0.0"
- fork: ">=6.0.0 <7.0.0"
- integers: ">=6.0.0 <7.0.0"
- js-bigints: ">=2.2.1 <3.0.0"
- lists: ">=7.0.0 <8.0.0"
- maybe: ">=6.0.0 <7.0.0"
- mmorph: ">=7.0.0 <8.0.0"
- newtype: ">=5.0.0 <6.0.0"
- node-buffer: ">=9.0.0 <10.0.0"
- node-event-emitter: ">=3.0.0 <4.0.0"
- nullable: ">=6.0.0 <7.0.0"
- parallel: ">=6.0.0 <7.0.0"
- partial: ">=4.0.0 <5.0.0"
- precise-datetime: ">=7.0.0 <8.0.0"
- prelude: ">=6.0.1 <7.0.0"
- profunctor: ">=6.0.1 <7.0.0"
- record: ">=4.0.0 <5.0.0"
- simple-json: ">=9.0.0 <10.0.0"
- strings: ">=6.0.1 <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"
- unsafe-coerce: ">=6.0.0 <7.0.0"
- aff
- aff-promise
- arrays
- bifunctors
- control
- datetime
- effect
- either
- exceptions
- foldable-traversable
- foreign
- fork
- integers
- js-bigints
- lists
- maybe
- mmorph
- newtype
- node-buffer
- node-event-emitter
- node-stream-pipes
- node-streams
- nullable
- parallel
- partial
- pipes
- precise-datetime
- prelude
- profunctor
- record
- simple-json
- strings
- tailrec
- transformers
- tuples
- typelevel-prelude
- unlift
- unsafe-coerce
test:
main: Test.Main
dependencies:
@@ -53,10 +58,9 @@ package:
- foreign-object
- node-child-process
- node-process
- precise-datetime
- quickcheck
- spec
- spec-quickcheck
workspace:
extraPackages: {}
packageSet:
registry: 50.5.0

View File

@@ -3,21 +3,28 @@ module Control.Monad.Postgres.Base where
import Prelude
import Control.Alt (class Alt)
import Control.Alternative (class Plus)
import Control.Alternative (class 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.Session (class MonadSession, SessionT, exec, exec_, query)
import Control.Monad.Postgres.Cursor (class MonadCursor, CursorT)
import Control.Monad.Postgres.Session (class MonadSession, SessionT, exec, exec_, query, streamIn, streamOut)
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
@@ -50,6 +57,7 @@ newtype PostgresT m a = PostgresT (ReaderT Pool m a)
derive instance Newtype (PostgresT m a) _
derive newtype instance (Functor m) => Functor (PostgresT m)
derive newtype instance (Apply m) => Apply (PostgresT m)
derive newtype instance (Alternative m) => Alternative (PostgresT m)
derive newtype instance (Applicative m) => Applicative (PostgresT m)
derive newtype instance (Plus m) => Plus (PostgresT m)
derive newtype instance (Alt m) => Alt (PostgresT m)
@@ -57,6 +65,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)
@@ -85,30 +96,51 @@ instance (MonadBracket e f m, MonadAff m) => MonadSession (PostgresT m) where
query = session <<< query
exec = session <<< exec
exec_ = session <<< exec_
streamIn = session <<< streamIn
streamOut = session <<< streamOut
-- | 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 (Monad m, 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.
-- |

View File

@@ -3,27 +3,32 @@ module Control.Monad.Postgres.Cursor where
import Prelude
import Control.Alt (class Alt)
import Control.Alternative (class Plus)
import Control.Alternative (class 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, mapReader, runReaderT, withReader, withReaderT)
import Control.Monad.Postgres.Session (class MonadSession, exec, exec_, query, streamIn, streamOut)
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 (class Deserialize, RepT, deserialize, smash)
import Data.Postgres.Query (class AsQuery, asQuery)
import Data.Postgres (RepT, smash)
import Data.Postgres.Raw (Raw)
import Data.Postgres.Result (class FromRow, fromRow)
import Data.Postgres.Result (RowsAffected(..))
import Data.Traversable (traverse)
import Data.Tuple.Nested (type (/\), (/\))
import Effect.Aff (Fiber)
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)
data Move
-- | `MOVE RELATIVE`
= MoveRelative Int
-- | `MOVE ABSOLUTE`
| MoveTo Int
newtype CursorT :: forall k. Type -> (k -> Type) -> k -> Type
newtype CursorT t m a = CursorT (ReaderT (String /\ (Array Raw -> RepT t)) m a)
@@ -34,10 +39,14 @@ derive newtype instance (Apply m) => Apply (CursorT t m)
derive newtype instance (Applicative m) => Applicative (CursorT t m)
derive newtype instance (Plus m) => Plus (CursorT t m)
derive newtype instance (Alt m) => Alt (CursorT t m)
derive newtype instance (Alternative m) => Alternative (CursorT t m)
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)
@@ -87,6 +96,9 @@ class (MonadSession m) <= MonadCursor m t where
fetch :: Int -> m (Array t)
-- | Fetch all remaining rows from the cursor
fetchAll :: m (Array t)
-- | Change the cursor's position without fetching any data,
-- | returning the number of rows skipped.
move :: Move -> m Int
instance (MonadSession m) => MonadCursor (CursorT t m) t where
fetch n = do
@@ -97,26 +109,22 @@ instance (MonadSession m) => MonadCursor (CursorT t m) t where
cur /\ f <- ask
raw :: Array (Array Raw) <- query $ "fetch all from " <> cur
liftEffect $ smash $ traverse f raw
move (MoveTo n) = do
cur /\ _ <- ask
RowsAffected n' <- query $ ("move absolute $1 from " <> cur) /\ n
pure n'
move (MoveRelative n) = do
cur /\ _ <- ask
RowsAffected n' <- query $ ("move relative $1 from " <> cur) /\ n
pure n'
instance (MonadSession m) => MonadSession (CursorT t m) where
query = lift <<< query
exec = lift <<< exec
exec_ = lift <<< exec_
streamIn = lift <<< streamIn
streamOut = lift <<< streamOut
-- | 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. FromRow t => 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 = cursorWith cur q fromRow m
-- | `cursor`, but using a custom deserialize function for the data
-- | yielded by the cursor
cursorWith :: forall m @t a q. AsQuery q => MonadAff m => MonadBracket Error Fiber m => MonadSession (SessionT m) => String -> q -> (Array Raw -> RepT t) -> CursorT t (SessionT m) a -> PostgresT m a
cursorWith cur q f m =
transaction do
q' <- liftEffect $ asQuery q
exec_ $ "declare " <> cur <> " cursor for (" <> (unwrap q').text <> ");"
runReaderT (unwrap m) (cur /\ f)

View File

@@ -8,6 +8,8 @@ import Data.Postgres.Result (class FromRows)
import Effect.Aff.Class (class MonadAff, liftAff)
import Effect.Aff.Postgres.Client (Client)
import Effect.Aff.Postgres.Client as Client
import Effect.Class (liftEffect)
import Node.Stream (Writable, Readable)
type SessionT :: forall k. (k -> Type) -> k -> Type
type SessionT = ReaderT Client
@@ -20,6 +22,24 @@ class MonadAff m <= MonadSession m where
exec :: forall q. AsQuery q => q -> m Int
-- | Executes a query and discards the result
exec_ :: forall q. AsQuery q => q -> m Unit
-- | Execute a query with a `Writable` stream to `STDIN`
-- |
-- | Use with `COPY .. FROM` like so:
-- |
-- | ```purescript
-- | w <- streamIn "COPY foo FROM STDIN WITH (FORMAT CSV, HEADER true)"
-- | liftEffect $ Stream.writeString "bar\n\"my bar column\"" UTF8 w
-- | ```
streamIn :: String -> m (Writable ())
-- | Execute a query with a `Readable` stream from `STDOUT`
-- |
-- | Use with `COPY .. TO` like so:
-- |
-- | ```purescript
-- | r <- streamIn "COPY foo TO STDIN WITH (FORMAT CSV, HEADER true)"
-- | liftEffect $ Stream.readString r -- "bar\n\"my bar column\""
-- | ```
streamOut :: String -> m (Readable ())
instance MonadAff m => MonadSession (SessionT m) where
query q = do
@@ -29,3 +49,9 @@ instance MonadAff m => MonadSession (SessionT m) where
client <- ask
liftAff $ Client.exec q client
exec_ = void <<< exec
streamIn q = do
client <- ask
liftEffect $ Client.execWithStdin q client
streamOut q = do
client <- ask
liftEffect $ Client.queryWithStdout q client

View File

@@ -2,20 +2,13 @@ module Data.Postgres.Custom where
import Prelude
import Control.Monad.Except (ExceptT)
import Data.Either (hush)
import Data.List.NonEmpty (NonEmptyList)
import Data.Maybe (Maybe, fromJust)
import Data.Postgres.Raw (Raw)
import Data.Maybe (fromJust)
import Data.String as String
import Data.String.Regex (Regex)
import Data.String.Regex as Regex
import Data.String.Regex.Flags as Regex.Flags
import Effect (Effect)
import Foreign (ForeignError)
import Partial.Unsafe (unsafePartial)
import Type.Data.Symbol (reflectSymbol)
import Type.Prelude (class IsSymbol, Proxy(..))
quoted :: String -> String
quoted s = "'" <> s <> "'"

View File

@@ -4,11 +4,13 @@ import Prelude
import Control.Monad.Error.Class (liftMaybe, throwError)
import Data.Array as Array
import Data.Generic.Rep (class Generic)
import Data.Int as Int
import Data.Maybe (Maybe)
import Data.Newtype (class Newtype)
import Data.Nullable (Nullable)
import Data.Nullable as Nullable
import Data.Postgres (class Deserialize, class Rep, RepT, deserialize)
import Data.Postgres (class Deserialize, RepT, deserialize)
import Data.Postgres.Raw (Raw)
import Data.Traversable (traverse)
import Data.Tuple (Tuple)
@@ -27,19 +29,29 @@ foreign import data Result :: Type
rowsAffected :: Result -> Maybe Int
rowsAffected = Int.fromNumber <=< Nullable.toMaybe <<< __rowsAffected
class FromRows a where
fromRows :: Array (Array Raw) -> RepT a
newtype RowsAffected = RowsAffected Int
instance (FromRow a) => FromRows (Array a) where
fromRows = traverse fromRow
derive instance Newtype RowsAffected _
derive instance Generic RowsAffected _
derive newtype instance Eq RowsAffected
derive newtype instance Ord RowsAffected
derive newtype instance Show RowsAffected
class FromRows a where
fromRows :: RowsAffected -> Array (Array Raw) -> RepT a
instance FromRows RowsAffected where
fromRows a _ = pure a
else instance (FromRow a) => FromRows (Array a) where
fromRows _ = traverse fromRow
else instance (FromRow a) => FromRows (Maybe a) where
fromRows = map Array.head <<< traverse fromRow
fromRows _ = map Array.head <<< traverse fromRow
else instance (FromRow a) => FromRows a where
fromRows =
fromRows a =
let
e = pure $ ForeignError $ "Expected at least 1 row"
in
liftMaybe e <=< fromRows @(Maybe a)
liftMaybe e <=< fromRows @(Maybe a) a
-- | Can be unmarshalled from a queried row
-- |

View File

@@ -2,27 +2,26 @@ module Data.Postgres.Unresult where
import Prelude
import Control.Monad.Error.Class (class MonadThrow, liftMaybe)
import Control.Monad.Error.Class (liftMaybe)
import Control.Monad.State (StateT, runStateT, state)
import Data.Array as Array
import Data.Postgres (class Deserialize, deserialize, smash)
import Data.Postgres (class Deserialize, RepT, deserialize, smash)
import Data.Postgres.Raw (Raw)
import Data.Tuple (fst)
import Data.Tuple.Nested ((/\))
import Effect.Aff (error)
import Effect.Class (class MonadEffect, liftEffect)
import Effect.Exception (Error)
import Effect.Class (liftEffect)
import Foreign (ForeignError(..))
-- | Monad used to incrementally deserialize columns from a row
type UnresultT m a = StateT {ix :: Int, row :: Array Raw} m a
type Unresult a = StateT { ix :: Int, row :: Array Raw } RepT a
-- | Run an `UnresultT`
unresult :: forall m a. Monad m => Array Raw -> UnresultT m a -> m a
unresult row m = fst <$> runStateT m {ix: 0, row}
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 m a. MonadThrow Error m => Deserialize a => MonadEffect m => UnresultT m 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 (error "Ran out of columns!") raw
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'

View File

@@ -1,3 +1,5 @@
import QueryStream from 'pg-copy-streams'
/** @type {(c: import('pg').Client) => () => Promise<void>} */
export const __connect = c => () => c.connect()
@@ -6,3 +8,9 @@ export const __end = c => () => c.end()
/** @type {(q: import('pg').QueryConfig) => (c: import('pg').Client) => () => Promise<import('pg').QueryResult>} */
export const __query = q => c => () => c.query(q)
/** @type {(q: string) => (c: import('pg').Client) => () => import('stream').Readable} */
export const __execStreamStdout = q => c => () => c.query(QueryStream.to(q))
/** @type {(q: string) => (c: import('pg').Client) => () => import('stream').Writable} */
export const __execStreamStdin = q => c => () => c.query(QueryStream.from(q))

View File

@@ -1,4 +1,4 @@
module Effect.Aff.Postgres.Client (connected, connect, end, exec, query, queryRaw, __connect, __end, __query, module X) where
module Effect.Aff.Postgres.Client (connected, connect, end, exec, execWithStdin, queryWithStdout, query, queryRaw, __connect, __end, __query, __execStreamStdin, __execStreamStdout, module X) where
import Prelude
@@ -6,14 +6,16 @@ import Control.Promise (Promise)
import Control.Promise as Promise
import Data.Functor (voidRight)
import Data.Maybe (fromMaybe)
import Data.Newtype (wrap)
import Data.Postgres (smash)
import Data.Postgres.Query (class AsQuery, QueryRaw, asQuery, __queryToRaw)
import Data.Postgres.Result (class FromRows, Result, fromRows, rows, rowsAffected)
import Effect (Effect)
import Effect.Aff (Aff)
import Effect.Class (liftEffect)
import Effect.Postgres.Client (Client, Config, make)
import Effect.Postgres.Client (Client, ClientConfigRaw, Config, Notification, NotificationRaw, __make, __uncfg, endE, errorE, make, noticeE, notificationE) as X
import Effect.Postgres.Client (Client, Config, make)
import Node.Stream (Readable, Writable)
import Prim.Row (class Union)
-- | Create a client and immediately connect it to the database
@@ -56,7 +58,18 @@ exec q = map (fromMaybe 0 <<< rowsAffected) <<< queryRaw q
-- |
-- | <https://node-postgres.com/apis/client#clientquery>
query :: forall q r. AsQuery q => FromRows r => q -> Client -> Aff r
query q = (liftEffect <<< smash <<< fromRows) <=< map rows <<< queryRaw q
query q c = do
raw <- queryRaw q c
let
affected = rowsAffected raw
rows' = rows raw
liftEffect $ smash $ fromRows (wrap $ fromMaybe 0 affected) rows'
execWithStdin :: String -> Client -> Effect (Writable ())
execWithStdin q c = __execStreamStdin q c
queryWithStdout :: String -> Client -> Effect (Readable ())
queryWithStdout q c = __execStreamStdout q c
-- | FFI binding to `Client#connect`
foreign import __connect :: Client -> Effect (Promise Unit)
@@ -66,3 +79,9 @@ foreign import __end :: Client -> Effect (Promise Unit)
-- | FFI binding to `Client#query`
foreign import __query :: QueryRaw -> Client -> Effect (Promise Result)
-- | FFI binding to `import('pg-copy-streams').to`
foreign import __execStreamStdout :: String -> Client -> Effect (Readable ())
-- | FFI binding to `import('pg-copy-streams').from`
foreign import __execStreamStdin :: String -> Client -> Effect (Writable ())

55
src/Pipes.Postgres.purs Normal file
View File

@@ -0,0 +1,55 @@
module Pipes.Postgres where
import Prelude
import Control.Monad.Morph (hoist)
import Control.Monad.Postgres (class MonadPostgres)
import Control.Monad.Reader (class MonadAsk, ask)
import Data.Maybe (Maybe(..))
import Effect.Aff.Class (class MonadAff, liftAff)
import Effect.Aff.Postgres.Client as Client
import Effect.Aff.Postgres.Pool (Pool)
import Effect.Aff.Postgres.Pool as Pool
import Effect.Class (liftEffect)
import Node.Buffer (Buffer)
import Node.Stream.Object as O
import Pipes ((>->))
import Pipes.Core (Consumer, Producer)
import Pipes.Node.Stream (fromReadable, fromWritable)
import Pipes.Prelude as Pipes
stdin
:: forall m s c ct
. MonadAff m
=> MonadAsk Pool m
=> MonadPostgres m s c ct
=> String
-> Consumer (Maybe Buffer) m Unit
stdin q = do
pool <- ask
client <- liftAff $ Pool.connect pool
stream <- liftEffect $ Client.execWithStdin q client
let
releaseOnEOS Nothing = Pool.release pool client $> Nothing
releaseOnEOS (Just a) = pure (Just a)
hoist liftAff
$ hoist liftEffect (Pipes.mapM releaseOnEOS)
>-> fromWritable (O.fromBufferWritable stream)
stdout
:: forall m s c ct
. MonadAff m
=> MonadAsk Pool m
=> MonadPostgres m s c ct
=> String
-> Producer (Maybe Buffer) m Unit
stdout q = do
pool <- ask
client <- liftAff $ Pool.connect pool
stream <- liftEffect $ Client.queryWithStdout q client
let
releaseOnEOS Nothing = Pool.release pool client $> Nothing
releaseOnEOS (Just a) = pure (Just a)
hoist liftAff
$ fromReadable (O.fromBufferReadable stream)
>-> hoist liftEffect (Pipes.mapM releaseOnEOS)