generated from tpl/purs
fix: test client bindings
This commit is contained in:
parent
d7916683d7
commit
d1f84bcc72
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,3 +11,4 @@
|
|||||||
.log
|
.log
|
||||||
.purs-repl
|
.purs-repl
|
||||||
.env
|
.env
|
||||||
|
pg
|
||||||
|
9
docker-compose.yml
Normal file
9
docker-compose.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: 'postgres:16-bookworm'
|
||||||
|
volumes:
|
||||||
|
- './pg:/var/run/postgresql'
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: 'postgres'
|
||||||
|
POSTGRES_PASSWORD: 'password'
|
129
spago.lock
129
spago.lock
@ -3,6 +3,7 @@ workspace:
|
|||||||
pg:
|
pg:
|
||||||
path: ./
|
path: ./
|
||||||
dependencies:
|
dependencies:
|
||||||
|
- aff
|
||||||
- aff-promise
|
- aff-promise
|
||||||
- bifunctors
|
- bifunctors
|
||||||
- control
|
- control
|
||||||
@ -11,6 +12,7 @@ workspace:
|
|||||||
- exceptions
|
- exceptions
|
||||||
- foldable-traversable
|
- foldable-traversable
|
||||||
- foreign
|
- foreign
|
||||||
|
- integers
|
||||||
- lists
|
- lists
|
||||||
- maybe
|
- maybe
|
||||||
- mmorph
|
- mmorph
|
||||||
@ -20,11 +22,17 @@ workspace:
|
|||||||
- nullable
|
- nullable
|
||||||
- precise-datetime
|
- precise-datetime
|
||||||
- prelude
|
- prelude
|
||||||
|
- record
|
||||||
- simple-json
|
- simple-json
|
||||||
- transformers
|
- transformers
|
||||||
|
- tuples
|
||||||
|
- typelevel-prelude
|
||||||
- unsafe-coerce
|
- unsafe-coerce
|
||||||
test_dependencies:
|
test_dependencies:
|
||||||
|
- filterable
|
||||||
- foreign-object
|
- foreign-object
|
||||||
|
- node-child-process
|
||||||
|
- node-process
|
||||||
- quickcheck
|
- quickcheck
|
||||||
- spec
|
- spec
|
||||||
- spec-quickcheck
|
- spec-quickcheck
|
||||||
@ -49,6 +57,7 @@ workspace:
|
|||||||
- enums
|
- enums
|
||||||
- exceptions
|
- exceptions
|
||||||
- exists
|
- exists
|
||||||
|
- filterable
|
||||||
- fixed-points
|
- fixed-points
|
||||||
- foldable-traversable
|
- foldable-traversable
|
||||||
- foreign
|
- foreign
|
||||||
@ -70,7 +79,13 @@ workspace:
|
|||||||
- mmorph
|
- mmorph
|
||||||
- newtype
|
- newtype
|
||||||
- node-buffer
|
- node-buffer
|
||||||
|
- node-child-process
|
||||||
- node-event-emitter
|
- node-event-emitter
|
||||||
|
- node-fs
|
||||||
|
- node-os
|
||||||
|
- node-path
|
||||||
|
- node-process
|
||||||
|
- node-streams
|
||||||
- nonempty
|
- nonempty
|
||||||
- now
|
- now
|
||||||
- nullable
|
- nullable
|
||||||
@ -81,6 +96,7 @@ workspace:
|
|||||||
- parsing
|
- parsing
|
||||||
- partial
|
- partial
|
||||||
- pipes
|
- pipes
|
||||||
|
- posix-types
|
||||||
- precise-datetime
|
- precise-datetime
|
||||||
- prelude
|
- prelude
|
||||||
- profunctor
|
- profunctor
|
||||||
@ -313,6 +329,17 @@ packages:
|
|||||||
integrity: sha256-A0JQHpTfo1dNOj9U5/Fd3xndlRSE0g2IQWOGor2yXn8=
|
integrity: sha256-A0JQHpTfo1dNOj9U5/Fd3xndlRSE0g2IQWOGor2yXn8=
|
||||||
dependencies:
|
dependencies:
|
||||||
- unsafe-coerce
|
- unsafe-coerce
|
||||||
|
filterable:
|
||||||
|
type: registry
|
||||||
|
version: 5.0.0
|
||||||
|
integrity: sha256-cCojJHRnTmpY1j1kegI4CFwghdQ2Fm/8dzM8IlC+lng=
|
||||||
|
dependencies:
|
||||||
|
- arrays
|
||||||
|
- either
|
||||||
|
- foldable-traversable
|
||||||
|
- identity
|
||||||
|
- lists
|
||||||
|
- ordered-collections
|
||||||
fixed-points:
|
fixed-points:
|
||||||
type: registry
|
type: registry
|
||||||
version: 7.0.0
|
version: 7.0.0
|
||||||
@ -552,6 +579,22 @@ packages:
|
|||||||
- nullable
|
- nullable
|
||||||
- st
|
- st
|
||||||
- unsafe-coerce
|
- unsafe-coerce
|
||||||
|
node-child-process:
|
||||||
|
type: registry
|
||||||
|
version: 11.1.0
|
||||||
|
integrity: sha256-vioMNgk8p+CGwlb6T3I3TIir27el85Yg4satLE/I89w=
|
||||||
|
dependencies:
|
||||||
|
- exceptions
|
||||||
|
- foreign
|
||||||
|
- foreign-object
|
||||||
|
- functions
|
||||||
|
- node-event-emitter
|
||||||
|
- node-fs
|
||||||
|
- node-os
|
||||||
|
- node-streams
|
||||||
|
- nullable
|
||||||
|
- posix-types
|
||||||
|
- unsafe-coerce
|
||||||
node-event-emitter:
|
node-event-emitter:
|
||||||
type: registry
|
type: registry
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
@ -564,6 +607,85 @@ packages:
|
|||||||
- nullable
|
- nullable
|
||||||
- prelude
|
- prelude
|
||||||
- unsafe-coerce
|
- unsafe-coerce
|
||||||
|
node-fs:
|
||||||
|
type: registry
|
||||||
|
version: 9.1.0
|
||||||
|
integrity: sha256-TzhvGdrwcM0bazDvrWSqh+M/H8GKYf1Na6aGm2Qg4+c=
|
||||||
|
dependencies:
|
||||||
|
- datetime
|
||||||
|
- effect
|
||||||
|
- either
|
||||||
|
- enums
|
||||||
|
- exceptions
|
||||||
|
- functions
|
||||||
|
- integers
|
||||||
|
- js-date
|
||||||
|
- maybe
|
||||||
|
- node-buffer
|
||||||
|
- node-path
|
||||||
|
- node-streams
|
||||||
|
- nullable
|
||||||
|
- partial
|
||||||
|
- prelude
|
||||||
|
- strings
|
||||||
|
- unsafe-coerce
|
||||||
|
node-os:
|
||||||
|
type: registry
|
||||||
|
version: 5.1.0
|
||||||
|
integrity: sha256-K3gcu9AXanN1+qtk1900+Fi+CuO0s3/H/RMNRNgIzso=
|
||||||
|
dependencies:
|
||||||
|
- arrays
|
||||||
|
- bifunctors
|
||||||
|
- console
|
||||||
|
- control
|
||||||
|
- datetime
|
||||||
|
- effect
|
||||||
|
- either
|
||||||
|
- exceptions
|
||||||
|
- foldable-traversable
|
||||||
|
- foreign
|
||||||
|
- foreign-object
|
||||||
|
- functions
|
||||||
|
- maybe
|
||||||
|
- node-buffer
|
||||||
|
- nullable
|
||||||
|
- partial
|
||||||
|
- posix-types
|
||||||
|
- prelude
|
||||||
|
- unsafe-coerce
|
||||||
|
node-path:
|
||||||
|
type: registry
|
||||||
|
version: 5.0.0
|
||||||
|
integrity: sha256-pd82nQ+2l5UThzaxPdKttgDt7xlsgIDLpPG0yxDEdyE=
|
||||||
|
dependencies:
|
||||||
|
- effect
|
||||||
|
node-process:
|
||||||
|
type: registry
|
||||||
|
version: 11.2.0
|
||||||
|
integrity: sha256-+2MQDYChjGbVbapCyJtuWYwD41jk+BntF/kcOTKBMVs=
|
||||||
|
dependencies:
|
||||||
|
- effect
|
||||||
|
- foreign
|
||||||
|
- foreign-object
|
||||||
|
- maybe
|
||||||
|
- node-event-emitter
|
||||||
|
- node-streams
|
||||||
|
- posix-types
|
||||||
|
- prelude
|
||||||
|
- unsafe-coerce
|
||||||
|
node-streams:
|
||||||
|
type: registry
|
||||||
|
version: 9.0.0
|
||||||
|
integrity: sha256-2n6dq7YWleTDmD1Kur/ul7Cn08IvWrScgPf+0PgX2TQ=
|
||||||
|
dependencies:
|
||||||
|
- aff
|
||||||
|
- effect
|
||||||
|
- either
|
||||||
|
- exceptions
|
||||||
|
- node-buffer
|
||||||
|
- node-event-emitter
|
||||||
|
- nullable
|
||||||
|
- prelude
|
||||||
nonempty:
|
nonempty:
|
||||||
type: registry
|
type: registry
|
||||||
version: 7.0.0
|
version: 7.0.0
|
||||||
@ -683,6 +805,13 @@ packages:
|
|||||||
- tailrec
|
- tailrec
|
||||||
- transformers
|
- transformers
|
||||||
- tuples
|
- tuples
|
||||||
|
posix-types:
|
||||||
|
type: registry
|
||||||
|
version: 6.0.0
|
||||||
|
integrity: sha256-ZfFz8RR1lee/o/Prccyeut3Q+9tYd08mlR72sIh6GzA=
|
||||||
|
dependencies:
|
||||||
|
- maybe
|
||||||
|
- prelude
|
||||||
precise-datetime:
|
precise-datetime:
|
||||||
type: registry
|
type: registry
|
||||||
version: 7.0.0
|
version: 7.0.0
|
||||||
|
@ -4,6 +4,7 @@ package:
|
|||||||
strict: true
|
strict: true
|
||||||
pedantic_packages: true
|
pedantic_packages: true
|
||||||
dependencies:
|
dependencies:
|
||||||
|
- aff
|
||||||
- aff-promise
|
- aff-promise
|
||||||
- bifunctors
|
- bifunctors
|
||||||
- control
|
- control
|
||||||
@ -12,6 +13,7 @@ package:
|
|||||||
- exceptions
|
- exceptions
|
||||||
- foldable-traversable
|
- foldable-traversable
|
||||||
- foreign
|
- foreign
|
||||||
|
- integers
|
||||||
- lists
|
- lists
|
||||||
- maybe
|
- maybe
|
||||||
- mmorph
|
- mmorph
|
||||||
@ -21,13 +23,19 @@ package:
|
|||||||
- nullable
|
- nullable
|
||||||
- precise-datetime
|
- precise-datetime
|
||||||
- prelude
|
- prelude
|
||||||
|
- record
|
||||||
- simple-json
|
- simple-json
|
||||||
- transformers
|
- transformers
|
||||||
|
- tuples
|
||||||
|
- typelevel-prelude
|
||||||
- unsafe-coerce
|
- unsafe-coerce
|
||||||
test:
|
test:
|
||||||
main: Test.Main
|
main: Test.Main
|
||||||
dependencies:
|
dependencies:
|
||||||
|
- filterable
|
||||||
- foreign-object
|
- foreign-object
|
||||||
|
- node-child-process
|
||||||
|
- node-process
|
||||||
- quickcheck
|
- quickcheck
|
||||||
- spec
|
- spec
|
||||||
- spec-quickcheck
|
- spec-quickcheck
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as Pg from 'pg'
|
import Pg from 'pg'
|
||||||
import * as Range from 'postgres-range'
|
import Range from 'postgres-range'
|
||||||
|
|
||||||
export const null_ = null
|
export const null_ = null
|
||||||
|
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import {Client} from 'pg'
|
import Pg from 'pg'
|
||||||
|
|
||||||
/** @typedef {{statementTimeout: unknown, queryTimeout: unknown, idleInTransactionTimeout: unknown, connectionTimeout: unknown, applicationName: string}} ClientConfigExtra */
|
/** @typedef {{statementTimeout: unknown, queryTimeout: unknown, idleInTransactionTimeout: unknown, connectionTimeout: unknown, applicationName: string}} ClientConfigExtra */
|
||||||
|
|
||||||
/** @type {(_: {unwrapMillis: (_m: unknown) => number}) => (cfg: import('pg').ClientConfig & ClientConfigExtra) => () => Client} */
|
/** @type {(_: {unwrapMillis: (_m: unknown) => number}) => (cfg: Pg.ClientConfig & ClientConfigExtra) => () => Pg.Client} */
|
||||||
export const makeImpl = ({unwrapMillis}) => cfg => () => {
|
export const makeImpl =
|
||||||
|
({ unwrapMillis }) =>
|
||||||
|
cfg =>
|
||||||
|
() => {
|
||||||
if ('statementTimeout' in cfg) {
|
if ('statementTimeout' in cfg) {
|
||||||
cfg.statement_timeout = unwrapMillis(cfg.statementTimeout)
|
cfg.statement_timeout = unwrapMillis(cfg.statementTimeout)
|
||||||
}
|
}
|
||||||
@ -11,7 +14,9 @@ export const makeImpl = ({unwrapMillis}) => cfg => () => {
|
|||||||
cfg.query_timeout = unwrapMillis(cfg.queryTimeout)
|
cfg.query_timeout = unwrapMillis(cfg.queryTimeout)
|
||||||
}
|
}
|
||||||
if ('idleInTransactionTimeout' in cfg) {
|
if ('idleInTransactionTimeout' in cfg) {
|
||||||
cfg.idle_in_transaction_session_timeout = unwrapMillis(cfg.idleInTransactionTimeout)
|
cfg.idle_in_transaction_session_timeout = unwrapMillis(
|
||||||
|
cfg.idleInTransactionTimeout,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if ('connectionTimeout' in cfg) {
|
if ('connectionTimeout' in cfg) {
|
||||||
cfg.connectionTimeoutMillis = unwrapMillis(cfg.connectionTimeout)
|
cfg.connectionTimeoutMillis = unwrapMillis(cfg.connectionTimeout)
|
||||||
@ -19,5 +24,5 @@ export const makeImpl = ({unwrapMillis}) => cfg => () => {
|
|||||||
if ('applicationName' in cfg) {
|
if ('applicationName' in cfg) {
|
||||||
cfg.application_name = cfg.applicationName
|
cfg.application_name = cfg.applicationName
|
||||||
}
|
}
|
||||||
return new Client(cfg)
|
return new Pg.Client(cfg)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
module Effect.Postgres where
|
module Effect.Postgres where
|
||||||
|
|
||||||
import Prelude
|
|
||||||
|
|
||||||
import Data.Time.Duration (Milliseconds)
|
|
||||||
|
|
||||||
foreign import data Pool :: Type
|
foreign import data Pool :: Type
|
||||||
|
52
test/Test.Effect.Postgres.Client.purs
Normal file
52
test/Test.Effect.Postgres.Client.purs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
module Test.Effect.Postgres.Client where
|
||||||
|
|
||||||
|
import Prelude
|
||||||
|
|
||||||
|
import Control.Monad.Error.Class (try)
|
||||||
|
import Data.Array as Array
|
||||||
|
import Data.Either (isLeft)
|
||||||
|
import Data.Postgres (deserialize, smash)
|
||||||
|
import Data.Traversable (traverse)
|
||||||
|
import Effect.Aff (Aff)
|
||||||
|
import Effect.Aff.Postgres.Client as PG.Aff.Client
|
||||||
|
import Effect.Class (liftEffect)
|
||||||
|
import Effect.Console (log)
|
||||||
|
import Effect.Postgres.Client as PG
|
||||||
|
import Effect.Postgres.Client as PG.Client
|
||||||
|
import Effect.Postgres.Result as Result
|
||||||
|
import Node.Path as Path
|
||||||
|
import Node.Process (cwd)
|
||||||
|
import Test.Spec (Spec, describe, it)
|
||||||
|
import Test.Spec.Assertions (shouldEqual)
|
||||||
|
|
||||||
|
client :: Aff PG.Client
|
||||||
|
client = do
|
||||||
|
cwd' <- liftEffect cwd
|
||||||
|
host <- liftEffect $ Path.resolve [ cwd' ] "./pg"
|
||||||
|
liftEffect $ PG.Client.make { host, user: "postgres", password: "password", database: "postgres" }
|
||||||
|
|
||||||
|
spec :: Spec Unit
|
||||||
|
spec = do
|
||||||
|
describe "Client" do
|
||||||
|
describe "make" do
|
||||||
|
it "does not throw" $ void $ client
|
||||||
|
describe "connect" do
|
||||||
|
it "does not throw" $ PG.Aff.Client.connect =<< client
|
||||||
|
describe "end" do
|
||||||
|
it "does not throw" $ do
|
||||||
|
c <- client
|
||||||
|
PG.Aff.Client.connect c
|
||||||
|
PG.Aff.Client.end c
|
||||||
|
describe "query" do
|
||||||
|
it "ok if connected" $ do
|
||||||
|
c <- client
|
||||||
|
PG.Aff.Client.connect c
|
||||||
|
res <- Result.rows <$> PG.Aff.Client.query "select unnest(array[1, 2, 3])" c
|
||||||
|
ints :: Array Int <- liftEffect $ smash $ traverse deserialize $ Array.catMaybes $ map Array.head res
|
||||||
|
ints `shouldEqual` [ 1, 2, 3 ]
|
||||||
|
it "throws if ended" $ do
|
||||||
|
c <- client
|
||||||
|
PG.Aff.Client.connect c
|
||||||
|
PG.Aff.Client.end c
|
||||||
|
res <- try $ PG.Aff.Client.query "select 1" c
|
||||||
|
isLeft res `shouldEqual` true
|
@ -2,12 +2,63 @@ module Test.Main where
|
|||||||
|
|
||||||
import Prelude
|
import Prelude
|
||||||
|
|
||||||
import Effect (Effect)
|
import Control.Alternative (guard)
|
||||||
import Effect.Aff (launchAff_)
|
import Control.Monad.Rec.Class (untilJust)
|
||||||
|
import Data.Either (Either(..), hush)
|
||||||
|
import Data.Filterable (filter)
|
||||||
|
import Data.Maybe (Maybe(..), isNothing, maybe)
|
||||||
|
import Data.Newtype (wrap)
|
||||||
|
import Data.String as String
|
||||||
|
import Effect (Effect, untilE)
|
||||||
|
import Effect.Aff (Aff, bracket, delay, launchAff_, makeAff)
|
||||||
|
import Effect.Class (liftEffect)
|
||||||
|
import Effect.Console (log)
|
||||||
|
import Node.Buffer as Buffer
|
||||||
|
import Node.ChildProcess (ChildProcess)
|
||||||
|
import Node.ChildProcess as ChildProcess
|
||||||
|
import Node.ChildProcess.Aff as ChildProcess.Aff
|
||||||
|
import Node.ChildProcess.Types (Exit(..), stringSignal)
|
||||||
|
import Node.Encoding (Encoding(..))
|
||||||
|
import Node.EventEmitter as Event
|
||||||
import Test.Data.Postgres as Test.Data.Postgres
|
import Test.Data.Postgres as Test.Data.Postgres
|
||||||
import Test.Spec.Reporter (consoleReporter)
|
import Test.Effect.Postgres.Client as Test.Effect.Postgres.Client
|
||||||
|
import Test.Spec.Reporter (specReporter)
|
||||||
import Test.Spec.Runner (runSpec)
|
import Test.Spec.Runner (runSpec)
|
||||||
|
|
||||||
|
spawnDb :: Aff ChildProcess
|
||||||
|
spawnDb =
|
||||||
|
let
|
||||||
|
isReady = do
|
||||||
|
{ exitStatus, error } <- liftEffect (ChildProcess.spawnSync "docker" [ "compose", "exec", "db", "pg_isready" ])
|
||||||
|
let
|
||||||
|
exitOk (Normally 0) = true
|
||||||
|
exitOk _ = false
|
||||||
|
pure $ isNothing error && exitOk exitStatus
|
||||||
|
waitReady =
|
||||||
|
void $ untilJust do
|
||||||
|
delay $ wrap $ 100.0
|
||||||
|
isReady' <- isReady
|
||||||
|
pure $ filter (const isReady') (Just unit)
|
||||||
|
in
|
||||||
|
do
|
||||||
|
liftEffect $ log $ "[db] starting..."
|
||||||
|
db <- liftEffect $ ChildProcess.spawn "docker" [ "compose", "up" ]
|
||||||
|
waitReady
|
||||||
|
liftEffect $ log $ "[db] started!"
|
||||||
|
pure db
|
||||||
|
|
||||||
|
killDb :: ChildProcess -> Aff Unit
|
||||||
|
killDb db = do
|
||||||
|
let
|
||||||
|
onexit eff = Event.on ChildProcess.exitH eff db
|
||||||
|
exit = makeAff \res -> mempty <$ onexit (const $ res $ Right unit)
|
||||||
|
_ <- liftEffect $ ChildProcess.kill' (stringSignal "SIGTERM") db
|
||||||
|
exit
|
||||||
|
|
||||||
main :: Effect Unit
|
main :: Effect Unit
|
||||||
main = launchAff_ $ runSpec [ consoleReporter ] do
|
main = launchAff_ do
|
||||||
|
bracket spawnDb killDb
|
||||||
|
$ const
|
||||||
|
$ runSpec [ specReporter ] do
|
||||||
Test.Data.Postgres.spec
|
Test.Data.Postgres.spec
|
||||||
|
Test.Effect.Postgres.Client.spec
|
||||||
|
Loading…
Reference in New Issue
Block a user