46 Commits

Author SHA1 Message Date
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
43ce1354ea chore: prepare v1.2.2 2024-04-05 22:11:51 -05:00
87614611dd fix: relax cursor constraints, fix enum test 2024-04-05 22:11:44 -05:00
2ab53c43b2 chore: prepare v1.2.1 2024-04-05 21:53:42 -05:00
500e67d793 fix: FromRow t bound on cursor 2024-04-05 21:53:37 -05:00
ca95e0aa94 chore: prepare v1.2.0 2024-04-05 21:49:36 -05:00
bc120b072c feat: UnresultT 2024-04-05 21:49:31 -05:00
614db02470 chore: prepare v1.1.1 2024-04-05 20:56:58 -05:00
4aab05300b fix: improve custom enum api 2024-04-05 20:56:46 -05:00
651bc8cb8d chore: prepare v1.1.0 2024-04-05 20:06:43 -05:00
34fed4c369 chore: prepare v1.1.0 2024-04-05 20:06:27 -05:00
5fcf8c4549 feat: allow instances of serialize + deserialize outside this lib 2024-04-05 20:06:23 -05:00
07c2f5dd84 chore: prepare v1.1.0 2024-04-05 20:05:47 -05:00
bd25d12453 fix: prepare 2024-04-03 16:42:41 -05:00
7eb9a6e96a chore: prepare v1.0.6 2024-04-03 16:42:25 -05:00
6188a194cd chore: prepare 1.0.5 2024-04-03 16:41:55 -05:00
60f442fc21 fix: prepare 2024-04-03 16:41:53 -05:00
154fb0f1e7 fix: prepare 2024-04-03 16:40:17 -05:00
fb8e5af073 chore: prepare v1.0.4 2024-04-03 16:40:04 -05:00
dee8b85b84 fix: make publishing easier 2024-04-03 16:37:27 -05:00
8160660a98 feat: withPool 2024-04-03 16:27:41 -05:00
a0d2322441 docs: fix links 2024-04-03 13:22:34 -05:00
17 changed files with 441 additions and 702 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/postgresql/1.0.1/docs/Effect.Aff.Postgres.Pool#t:Pool
[`Config`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Effect.Aff.Postgres.Pool#t:Config
[`Pool.make`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Effect.Aff.Postgres.Pool#v:make
[`Pool.end`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Effect.Aff.Postgres.Pool#v:end
[`Pool.connect`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Effect.Aff.Postgres.Pool#v:connect
[`Pool.destroy`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Effect.Aff.Postgres.Pool#v:destroy
[`Pool.release`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Effect.Aff.Postgres.Pool#v:release
[`Pool`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Effect.Aff.Postgres.Pool#t:Pool
[`Config`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Effect.Aff.Postgres.Pool#t:Config
[`Pool.make`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Effect.Aff.Postgres.Pool#v:make
[`Pool.end`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Effect.Aff.Postgres.Pool#v:end
[`Pool.connect`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Effect.Aff.Postgres.Pool#v:connect
[`Pool.destroy`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Effect.Aff.Postgres.Pool#v:destroy
[`Pool.release`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Effect.Aff.Postgres.Pool#v:release
[`Client`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Effect.Aff.Postgres.Client#t:Client
[`Client.end`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Effect.Aff.Postgres.Client#v:end
[`Client.make`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Effect.Aff.Postgres.Client#v:make
[`Client.connected`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Effect.Aff.Postgres.Client#v:connected
[`Client.query`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Effect.Aff.Postgres.Client#v:query
[`Client.queryRaw`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Effect.Aff.Postgres.Client#v:queryRaw
[`Client.exec`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Effect.Aff.Postgres.Client#v:exec
[`Client`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Effect.Aff.Postgres.Client#t:Client
[`Client.end`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Effect.Aff.Postgres.Client#v:end
[`Client.make`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Effect.Aff.Postgres.Client#v:make
[`Client.connected`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Effect.Aff.Postgres.Client#v:connected
[`Client.query`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Effect.Aff.Postgres.Client#v:query
[`Client.queryRaw`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Effect.Aff.Postgres.Client#v:queryRaw
[`Client.exec`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Effect.Aff.Postgres.Client#v:exec
[`Range`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Range#t:Range
[`Range.gt`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Range#v:gt
[`Range.gte`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Range#v:gte
[`Range.lt`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Range#v:lt
[`Range.lte`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Range#v:lte
[`Range`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Range#t:Range
[`Range.gt`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Range#v:gt
[`Range.gte`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Range#v:gte
[`Range.lt`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Range#v:lt
[`Range.lte`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Range#v:lte
[`Raw`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Raw#t:Raw
[`Null`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Raw#t:Null
[`Raw`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Raw#t:Raw
[`Null`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Raw#t:Null
[`Serialize`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres#t:Serialize
[`Deserialize`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres#t:Deserialize
[`Rep`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres#t:Rep
[`modifyPgTypes`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres#v:modifyPgTypes
[`Serialize`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres#t:Serialize
[`Deserialize`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres#t:Deserialize
[`Rep`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres#t:Rep
[`modifyPgTypes`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres#v:modifyPgTypes
[`Result`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Result#t:Result
[`FromRow`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Result#t:FromRow
[`FromRows`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Result#t:FromRows
[`Result`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Result#t:Result
[`FromRow`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Result#t:FromRow
[`FromRows`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Result#t:FromRows
[`Query`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Query#t:Query
[`AsQuery`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Query#t:AsQuery
[`Query`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Query#t:Query
[`AsQuery`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Query#t:AsQuery
[`Query.Builder`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Query.Builder#t:Builder
[`Query.Builder.param`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Query.Builder#v:param
[`Query.Builder.build`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Data.Postgres.Query.Builder#v:build
[`Query.Builder`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Query.Builder#t:Builder
[`Query.Builder.param`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Query.Builder#v:param
[`Query.Builder.build`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Data.Postgres.Query.Builder#v:build
[`MonadCursor`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Control.Monad.Postgres#t:MonadCursor
[`MonadSession`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Control.Monad.Postgres#t:MonadSession
[`CursorT`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Control.Monad.Postgres#t:CursorT
[`SessionT`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Control.Monad.Postgres#t:SessionT
[`PostgresT`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Control.Monad.Postgres#t:PostgresT
[`cursor`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Control.Monad.Postgres#v:cursor
[`session`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Control.Monad.Postgres#v:session
[`transaction`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Control.Monad.Postgres#v:transaction
[`runPostgres`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Control.Monad.Postgres#v:runPostgres
[`query`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Control.Monad.Postgres#v:query
[`exec`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Control.Monad.Postgres#v:exec
[`exec_`]: https://pursuit.purescript.org/packages/postgresql/1.0.1/docs/Control.Monad.Postgres#v:exec_
[`MonadCursor`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Control.Monad.Postgres#t:MonadCursor
[`MonadSession`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Control.Monad.Postgres#t:MonadSession
[`CursorT`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Control.Monad.Postgres#t:CursorT
[`SessionT`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Control.Monad.Postgres#t:SessionT
[`PostgresT`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Control.Monad.Postgres#t:PostgresT
[`cursor`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Control.Monad.Postgres#v:cursor
[`session`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Control.Monad.Postgres#v:session
[`transaction`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Control.Monad.Postgres#v:transaction
[`runPostgres`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Control.Monad.Postgres#v:runPostgres
[`query`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Control.Monad.Postgres#v:query
[`exec`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.1/Control.Monad.Postgres#v:exec
[`exec_`]: https://pursuit.purescript.org/////////////////////////////////packages/purescript-postgresql/1.5.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.

32
bun/prepare.js Normal file
View File

@@ -0,0 +1,32 @@
import { readFile, writeFile } from 'fs/promises'
import { execSync } from 'child_process'
let ver = process.argv[2]
if (!ver) {
console.error(`tag required: bun bun/prepare.js v1.0.0`)
} else if (!/v\d+\.\d+\.\d+/.test(ver)) {
console.error(`invalid tag: ${ver}`)
}
ver = (/\d+\.\d+\.\d+/.exec(ver) || [])[0] || ''
const pkg = await readFile('./package.json', 'utf8')
const pkgnew = pkg.replace(/"version": ".+"/, `"version": "v${ver}"`)
await writeFile('./package.json', pkgnew)
const spago = await readFile('./spago.yaml', 'utf8')
const spagonew = spago.replace(/version: .+/, `version: '${ver}'`)
await writeFile('./spago.yaml', spagonew)
const readme = await readFile('./README.md', 'utf8')
const readmenew = readme.replace(
/packages\/purescript-postgresql\/.+?\//g,
`/packages/purescript-postgresql/${ver}/`,
)
await writeFile('./README.md', readmenew)
execSync(`git add spago.yaml package.json README.md`)
execSync(`git commit -m 'chore: prepare v${ver}'`)
execSync(`git tag v${ver}`)
execSync(`git push --tags`)
execSync(`git push --mirror github-mirror`)

View File

@@ -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

@@ -23,6 +23,7 @@ workspace:
- newtype: ">=5.0.0 <6.0.0"
- node-buffer: ">=9.0.0 <10.0.0"
- node-event-emitter: ">=3.0.0 <4.0.0"
- node-streams: ">=9.0.0 <10.0.0"
- nullable: ">=6.0.0 <7.0.0"
- parallel: ">=6.0.0 <7.0.0"
- partial: ">=4.0.0 <5.0.0"
@@ -32,9 +33,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 +76,7 @@ workspace:
- fork
- formatters
- free
- freet
- functions
- functors
- gen
@@ -86,6 +90,7 @@ workspace:
- lists
- maybe
- mmorph
- monad-control
- newtype
- node-buffer
- node-child-process
@@ -126,489 +131,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 +448,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 +599,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
@@ -1242,8 +791,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 +1115,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.0.1'
version: '1.5.1'
license: 'GPL-3.0-or-later'
location:
githubOwner: 'cakekindel'
@@ -33,6 +33,7 @@ package:
- newtype: ">=5.0.0 <6.0.0"
- node-buffer: ">=9.0.0 <10.0.0"
- node-event-emitter: ">=3.0.0 <4.0.0"
- node-streams: ">=9.0.0 <10.0.0"
- nullable: ">=6.0.0 <7.0.0"
- parallel: ">=6.0.0 <7.0.0"
- partial: ">=4.0.0 <5.0.0"
@@ -42,9 +43,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
@@ -58,5 +61,3 @@ package:
- 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,57 @@ 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 (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.
-- |
-- | This will not invoke `Pool.end` after executing.
withPool :: forall m a. PostgresT m a -> Pool -> m a
withPool = runReaderT <<< unwrap
-- | Create a new connection pool from the provided config and execute
-- | the postgres monad, invoking `Effect.Aff.Postgres.Pool.end` afterwards.
@@ -118,4 +156,4 @@ runPostgres cfg m =
acq = liftEffect $ Pool.make @r @missing @trash cfg
rel _ p = liftAff $ Pool.end p
in
bracket acq rel $ runReaderT $ unwrap m
bracket acq rel $ withPool m

View File

@@ -3,26 +3,35 @@ 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, runReaderT)
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.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.Postgres.Result (RowsAffected(..))
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)
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 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)
@@ -30,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)
@@ -46,10 +59,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,34 +91,40 @@ 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)
-- | Change the cursor's position without fetching any data,
-- | returning the number of rows skipped.
move :: Move -> m Int
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
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. 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

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

@@ -5,71 +5,69 @@ import Prelude
import Control.Alt ((<|>))
import Control.Monad.Error.Class (liftMaybe)
import Data.Array.NonEmpty.Internal (NonEmptyArray)
import Data.Either (hush)
import Data.Bifunctor (lmap)
import Data.Foldable (intercalate)
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep as G
import Data.Maybe (Maybe(..), fromJust)
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Newtype as Newtype
import Data.Postgres (RepT, deserialize, serialize)
import Data.Postgres.Custom (class CustomRep, quoted, typeName)
import Data.Postgres (class Rep, RepT, deserialize, serialize)
import Data.Postgres.Custom (quoted)
import Data.Postgres.Query (Query, emptyQuery)
import Data.Postgres.Raw (Raw)
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 Data.Symbol (class IsSymbol)
import Data.Traversable (find)
import Data.Tuple (fst, snd)
import Data.Tuple.Nested (type (/\), (/\))
import Foreign (ForeignError(..))
import Partial.Unsafe (unsafePartial)
import Type.Prelude (Proxy(..), reflectSymbol)
upperRe :: Regex
upperRe = unsafePartial fromJust $ hush $ Regex.regex "[A-Z]" Regex.Flags.global
typeName :: forall @a ty. CustomEnum a ty => String
typeName = reflectSymbol (Proxy @ty)
leadingUnderRe :: Regex
leadingUnderRe = unsafePartial fromJust $ hush $ Regex.regex "^_" Regex.Flags.noFlags
pascalToSnake :: String -> String
pascalToSnake = String.toLower <<< Regex.replace leadingUnderRe "" <<< Regex.replace upperRe "_$1"
class CustomRep a ty <= CustomEnum a ty | a -> ty where
enumVariants :: NonEmptyArray a
class (IsSymbol ty, Rep a, Eq a) <= CustomEnum a ty | a -> ty where
enumVariants :: NonEmptyArray (a /\ String)
parseEnum :: String -> Maybe a
printEnum :: a -> String
defaultParseEnum :: forall a ty. CustomEnum a ty => String -> Maybe a
defaultParseEnum s = map fst $ find (eq s <<< snd) enumVariants
defaultPrintEnum :: forall a ty. CustomEnum a ty => a -> String
defaultPrintEnum a = fromMaybe "ERROR: CustomEnum enumVariants was not exhaustive" $ map snd $ find (eq a <<< fst) enumVariants
defaultDeserializeEnum :: forall @a ty. CustomEnum a ty => Raw -> RepT a
defaultDeserializeEnum raw = do
s <- deserialize raw
let e = pure $ ForeignError $ "unsupported enum variant for " <> typeName @a <> ": " <> quoted s
liftMaybe e $ parseEnum s
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
enumDeserialize :: forall @a ty. CustomEnum a ty => Raw -> RepT a
enumDeserialize raw = do
s <- deserialize raw
let e = pure $ ForeignError $ "unsupported enum variant for " <> typeName @a <> ": " <> quoted s
liftMaybe e $ parseEnum s
enumSerialize :: forall @a ty. CustomEnum a ty => a -> RepT Raw
enumSerialize = serialize <<< printEnum
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'
@@ -80,9 +78,7 @@ genericPrintEnum = genericPrintEnum' <<< G.from
create :: forall @a ty. CustomEnum a ty => Query
create =
let
variants' :: NonEmptyArray a
variants' = enumVariants
variants = intercalate ", " $ quoted <$> printEnum <$> variants'
variants = intercalate ", " $ quoted <$> snd <$> enumVariants @a
q = "create type " <> typeName @a <> " as enum (" <> variants <> ");"
in
Newtype.modify (_ { text = q }) emptyQuery

View File

@@ -3,27 +3,28 @@ 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)
import Data.Maybe (Maybe, fromJust)
import Data.Postgres.Raw (Raw)
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(..))
class (IsSymbol ty) <= CustomSerialize a ty | a -> ty where
customPrintExpr :: a -> Maybe String
customSerialize :: a -> ExceptT (NonEmptyList ForeignError) Effect Raw
class (IsSymbol ty) <= CustomDeserialize a ty | a -> ty where
customDeserialize :: Raw -> ExceptT (NonEmptyList ForeignError) Effect a
class (IsSymbol ty, CustomSerialize a ty, CustomDeserialize a ty) <= CustomRep a ty | a -> ty
instance (IsSymbol ty, CustomSerialize a ty, CustomDeserialize a ty) => CustomRep a ty
quoted :: String -> String
quoted s = "'" <> s <> "'"
typeName :: forall @a ty. CustomRep a ty => String
typeName = reflectSymbol (Proxy @ty)
upperRe :: Regex
upperRe = unsafePartial fromJust $ hush $ Regex.regex "[A-Z]" Regex.Flags.global
leadingUnderRe :: Regex
leadingUnderRe = unsafePartial fromJust $ hush $ Regex.regex "^_" Regex.Flags.noFlags
pascalToSnake :: String -> String
pascalToSnake = String.toLower <<< Regex.replace leadingUnderRe "" <<< Regex.replace upperRe "_$1"

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 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
-- |
@@ -79,7 +91,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 +109,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

View 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'

View File

@@ -12,7 +12,6 @@ import Data.DateTime (DateTime)
import Data.List.NonEmpty (NonEmptyList)
import Data.Maybe (Maybe(..))
import Data.Newtype (class Newtype, unwrap, wrap)
import Data.Postgres.Custom (class CustomDeserialize, class CustomSerialize, customDeserialize, customSerialize)
import Data.Postgres.Range (Range, __rangeFromRecord, __rangeRawFromRaw, __rangeRawFromRecord, __rangeRawToRecord, __rangeToRecord)
import Data.Postgres.Raw (Null(..), Raw, jsNull)
import Data.Postgres.Raw (unsafeFromForeign, asForeign) as Raw
@@ -42,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
@@ -73,87 +72,84 @@ instance Serialize Raw where
serialize = pure
-- | `NULL`
else instance Serialize Unit where
instance Serialize Unit where
serialize _ = serialize Null
-- | `NULL`
else instance Serialize Null where
instance Serialize Null where
serialize _ = unsafeSerializeCoerce jsNull
-- | `json`, `jsonb`
else instance WriteForeign a => Serialize (JSON a) where
instance WriteForeign a => Serialize (JSON a) where
serialize = serialize <<< writeJSON <<< unwrap
-- | `bytea`
else instance Serialize Buffer where
instance Serialize Buffer where
serialize = unsafeSerializeCoerce
-- | `int2`, `int4`
else instance Serialize Int where
instance Serialize Int where
serialize = unsafeSerializeCoerce
-- | `int8`
else instance Serialize BigInt where
instance Serialize BigInt where
serialize = serialize <<< BigInt.toString
-- | `bool`
else instance Serialize Boolean where
instance Serialize Boolean where
serialize = unsafeSerializeCoerce
-- | `text`, `inet`, `tsquery`, `tsvector`, `uuid`, `xml`, `cidr`, `time`, `timetz`
else instance Serialize String where
instance Serialize String where
serialize = unsafeSerializeCoerce
-- | `float4`, `float8`
else instance Serialize Number where
instance Serialize Number where
serialize = unsafeSerializeCoerce
-- | `timestamp`, `timestamptz`
else instance Serialize DateTime where
instance Serialize DateTime where
serialize = serialize <<< unwrap <<< DateTime.ISO.fromDateTime
-- | `Just` -> `a`, `Nothing` -> `NULL`
else instance Serialize a => Serialize (Maybe a) where
instance Serialize a => Serialize (Maybe a) where
serialize (Just a) = serialize a
serialize Nothing = unsafeSerializeCoerce jsNull
-- | postgres `array`
else instance Serialize a => Serialize (Array a) where
instance Serialize a => Serialize (Array a) where
serialize = unsafeSerializeCoerce <=< traverse serialize
else instance (Ord a, Rep a) => Serialize (Range a) where
instance (Ord a, Rep a) => Serialize (Range a) where
serialize =
map (Raw.unsafeFromForeign <<< unsafeToForeign <<< __rangeRawFromRecord <<< __rangeToRecord)
<<< traverse serialize
else instance (CustomSerialize a ty) => Serialize a where
serialize = customSerialize
instance Deserialize Raw where
deserialize = pure
-- | `NULL` (always succeeds)
else instance Deserialize Unit where
instance Deserialize Unit where
deserialize _ = pure unit
-- | `NULL` (fails if non-null)
else instance Deserialize Null where
instance Deserialize Null where
deserialize = map (const Null) <<< F.readNullOrUndefined <<< Raw.asForeign
-- | `json`, `jsonb`
else instance ReadForeign a => Deserialize (JSON a) where
instance ReadForeign a => Deserialize (JSON a) where
deserialize = map wrap <<< (hoist (pure <<< unwrap) <<< readJSON') <=< deserialize @String
-- | `bytea`
else instance Deserialize Buffer where
instance Deserialize Buffer where
deserialize = (F.unsafeReadTagged "Buffer") <<< Raw.asForeign
-- | `int2`, `int4`
else instance Deserialize Int where
instance Deserialize Int where
deserialize = F.readInt <<< Raw.asForeign
-- | `int8`
else instance Deserialize BigInt where
instance Deserialize BigInt where
deserialize =
let
invalid s = pure $ ForeignError $ "Invalid bigint: " <> s
@@ -162,30 +158,30 @@ else instance Deserialize BigInt where
fromString <=< deserialize @String
-- | `bool`
else instance Deserialize Boolean where
instance Deserialize Boolean where
deserialize = F.readBoolean <<< Raw.asForeign
-- | `text`, `inet`, `tsquery`, `tsvector`, `uuid`, `xml`, `cidr`, `time`, `timetz`
else instance Deserialize String where
instance Deserialize String where
deserialize = F.readString <<< Raw.asForeign
-- | `float4`, `float8`
else instance Deserialize Number where
instance Deserialize Number where
deserialize = F.readNumber <<< Raw.asForeign
-- | `timestamp`, `timestamptz`
else instance Deserialize DateTime where
instance Deserialize DateTime where
deserialize raw = do
s :: String <- deserialize raw
let invalid = pure $ ForeignError $ "Not a valid ISO8601 string: `" <> s <> "`"
liftMaybe invalid $ DateTime.ISO.toDateTime $ wrap s
-- | postgres `array`
else instance Deserialize a => Deserialize (Array a) where
instance Deserialize a => Deserialize (Array a) where
deserialize = traverse (deserialize <<< Raw.unsafeFromForeign) <=< F.readArray <<< Raw.asForeign
-- | non-NULL -> `Just`, NULL -> `Nothing`
else instance Deserialize a => Deserialize (Maybe a) where
instance Deserialize a => Deserialize (Maybe a) where
deserialize raw =
let
nothing = const Nothing <$> deserialize @Null raw
@@ -193,8 +189,5 @@ else instance Deserialize a => Deserialize (Maybe a) where
in
just <|> nothing
else instance (Ord a, Rep a) => Deserialize (Range a) where
instance (Ord a, Rep a) => Deserialize (Range a) where
deserialize = traverse deserialize <=< map (__rangeFromRecord <<< __rangeRawToRecord) <<< lift <<< __rangeRawFromRaw
else instance (CustomDeserialize a ty) => Deserialize a where
deserialize = customDeserialize

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 ())

View File

@@ -9,9 +9,8 @@ import Data.DateTime (DateTime(..))
import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe(..))
import Data.Newtype (unwrap)
import Data.Postgres (deserialize, serialize, smash)
import Data.Postgres.Custom (class CustomDeserialize, class CustomSerialize, customDeserialize)
import Data.Postgres.Custom.Enum (class CustomEnum, create, enumDeserialize, enumPrintExpr, enumSerialize, genericEnumVariants, genericParseEnum, genericPrintEnum, parseEnum, printEnum)
import Data.Postgres (class Deserialize, class Serialize, deserialize, serialize, smash)
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,12 +24,11 @@ derive instance Eq Enum1
instance Show Enum1 where
show = genericShow
instance CustomSerialize Enum1 "enum_1" where
customPrintExpr a = enumPrintExpr a
customSerialize a = enumSerialize a
instance Serialize Enum1 where
serialize a = defaultSerializeEnum a
instance CustomDeserialize Enum1 "enum_1" where
customDeserialize a = enumDeserialize a
instance Deserialize Enum1 where
deserialize a = defaultDeserializeEnum a
instance CustomEnum Enum1 "enum_1" where
printEnum = genericPrintEnum
@@ -44,12 +42,11 @@ derive instance Eq Enum2
instance Show Enum2 where
show = genericShow
instance CustomSerialize Enum2 "enum_2" where
customPrintExpr a = enumPrintExpr a
customSerialize a = enumSerialize a
instance Serialize Enum2 where
serialize a = defaultSerializeEnum a
instance CustomDeserialize Enum2 "enum_2" where
customDeserialize a = enumDeserialize a
instance Deserialize Enum2 where
deserialize a = defaultDeserializeEnum a
instance CustomEnum Enum2 "enum_2" where
printEnum a = genericPrintEnum a
@@ -63,12 +60,11 @@ derive instance Eq Enum5
instance Show Enum5 where
show = genericShow
instance CustomSerialize Enum5 "enum_5" where
customPrintExpr a = enumPrintExpr a
customSerialize a = enumSerialize a
instance Serialize Enum5 where
serialize a = defaultSerializeEnum a
instance CustomDeserialize Enum5 "enum_5" where
customDeserialize a = enumDeserialize a
instance Deserialize Enum5 where
deserialize a = defaultDeserializeEnum a
instance CustomEnum Enum5 "enum_5" where
printEnum a = genericPrintEnum a