22 Commits

Author SHA1 Message Date
c9e5ee9205 chore: prepare v1.7.2 2024-06-23 20:36:00 -05:00
9ab6e37bb1 fix: bump node-stream-pipes 2024-06-23 20:35:44 -05:00
f23eb4143a chore: prepare v1.7.1 2024-06-22 20:01:10 -05:00
d10d21b708 fix: bump node-stream-pipes to 2.0.2 (big perf improvement) 2024-06-22 20:00:58 -05:00
826c1e10b1 chore: prepare v1.7.0 2024-06-14 18:04:01 -05:00
fbb1f3b8a5 fix: add interval support 2024-06-14 17:00:22 -05:00
b4a84a3210 chore: prepare v1.6.5 2024-05-22 15:49:37 -05:00
a56add0ffc fix: update node-stream-pipes 2024-05-22 15:49:14 -05:00
7ed85ae22b fix: tagOf is not instanceof 2024-05-22 15:42:43 -05:00
bead3d81c3 chore: prepare v1.6.4 2024-05-11 23:00:24 -05:00
27a7abb329 fix: stdin txn 2024-05-11 23:00:05 -05:00
86263a7521 chore: prepare v1.6.3 2024-05-11 22:11:07 -05:00
2db29b8916 chore: prepare v1.6.2 2024-05-11 22:10:24 -05:00
cfb01608cd fix: ensure-ranges 2024-05-11 22:09:38 -05:00
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
16 changed files with 496 additions and 70 deletions

View File

@@ -259,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.5.0/Effect.Aff.Postgres.Pool#t:Pool
[`Config`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Effect.Aff.Postgres.Pool#t:Config
[`Pool.make`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Effect.Aff.Postgres.Pool#v:make
[`Pool.end`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Effect.Aff.Postgres.Pool#v:end
[`Pool.connect`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Effect.Aff.Postgres.Pool#v:connect
[`Pool.destroy`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Effect.Aff.Postgres.Pool#v:destroy
[`Pool.release`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Effect.Aff.Postgres.Pool#v:release
[`Pool`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Effect.Aff.Postgres.Pool#t:Pool
[`Config`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Effect.Aff.Postgres.Pool#t:Config
[`Pool.make`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Effect.Aff.Postgres.Pool#v:make
[`Pool.end`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Effect.Aff.Postgres.Pool#v:end
[`Pool.connect`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Effect.Aff.Postgres.Pool#v:connect
[`Pool.destroy`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Effect.Aff.Postgres.Pool#v:destroy
[`Pool.release`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Effect.Aff.Postgres.Pool#v:release
[`Client`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Effect.Aff.Postgres.Client#t:Client
[`Client.end`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Effect.Aff.Postgres.Client#v:end
[`Client.make`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Effect.Aff.Postgres.Client#v:make
[`Client.connected`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Effect.Aff.Postgres.Client#v:connected
[`Client.query`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Effect.Aff.Postgres.Client#v:query
[`Client.queryRaw`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Effect.Aff.Postgres.Client#v:queryRaw
[`Client.exec`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Effect.Aff.Postgres.Client#v:exec
[`Client`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Effect.Aff.Postgres.Client#t:Client
[`Client.end`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Effect.Aff.Postgres.Client#v:end
[`Client.make`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Effect.Aff.Postgres.Client#v:make
[`Client.connected`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Effect.Aff.Postgres.Client#v:connected
[`Client.query`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Effect.Aff.Postgres.Client#v:query
[`Client.queryRaw`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Effect.Aff.Postgres.Client#v:queryRaw
[`Client.exec`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Effect.Aff.Postgres.Client#v:exec
[`Range`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Range#t:Range
[`Range.gt`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Range#v:gt
[`Range.gte`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Range#v:gte
[`Range.lt`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Range#v:lt
[`Range.lte`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Range#v:lte
[`Range`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Range#t:Range
[`Range.gt`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Range#v:gt
[`Range.gte`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Range#v:gte
[`Range.lt`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Range#v:lt
[`Range.lte`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Range#v:lte
[`Raw`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Raw#t:Raw
[`Null`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Raw#t:Null
[`Raw`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Raw#t:Raw
[`Null`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Raw#t:Null
[`Serialize`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres#t:Serialize
[`Deserialize`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres#t:Deserialize
[`Rep`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres#t:Rep
[`modifyPgTypes`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres#v:modifyPgTypes
[`Serialize`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres#t:Serialize
[`Deserialize`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres#t:Deserialize
[`Rep`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres#t:Rep
[`modifyPgTypes`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres#v:modifyPgTypes
[`Result`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Result#t:Result
[`FromRow`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Result#t:FromRow
[`FromRows`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Result#t:FromRows
[`Result`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Result#t:Result
[`FromRow`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Result#t:FromRow
[`FromRows`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Result#t:FromRows
[`Query`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Query#t:Query
[`AsQuery`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Query#t:AsQuery
[`Query`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Query#t:Query
[`AsQuery`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Query#t:AsQuery
[`Query.Builder`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Query.Builder#t:Builder
[`Query.Builder.param`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Query.Builder#v:param
[`Query.Builder.build`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Data.Postgres.Query.Builder#v:build
[`Query.Builder`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Query.Builder#t:Builder
[`Query.Builder.param`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Query.Builder#v:param
[`Query.Builder.build`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Data.Postgres.Query.Builder#v:build
[`MonadCursor`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Control.Monad.Postgres#t:MonadCursor
[`MonadSession`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Control.Monad.Postgres#t:MonadSession
[`CursorT`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Control.Monad.Postgres#t:CursorT
[`SessionT`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Control.Monad.Postgres#t:SessionT
[`PostgresT`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Control.Monad.Postgres#t:PostgresT
[`cursor`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Control.Monad.Postgres#v:cursor
[`session`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Control.Monad.Postgres#v:session
[`transaction`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Control.Monad.Postgres#v:transaction
[`runPostgres`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Control.Monad.Postgres#v:runPostgres
[`query`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Control.Monad.Postgres#v:query
[`exec`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Control.Monad.Postgres#v:exec
[`exec_`]: https://pursuit.purescript.org//////////////////////////////packages/purescript-postgresql/1.5.0/Control.Monad.Postgres#v:exec_
[`MonadCursor`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Control.Monad.Postgres#t:MonadCursor
[`MonadSession`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Control.Monad.Postgres#t:MonadSession
[`CursorT`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Control.Monad.Postgres#t:CursorT
[`SessionT`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Control.Monad.Postgres#t:SessionT
[`PostgresT`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Control.Monad.Postgres#t:PostgresT
[`cursor`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Control.Monad.Postgres#v:cursor
[`session`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Control.Monad.Postgres#v:session
[`transaction`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Control.Monad.Postgres#v:transaction
[`runPostgres`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Control.Monad.Postgres#v:runPostgres
[`query`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Control.Monad.Postgres#v:query
[`exec`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/Control.Monad.Postgres#v:exec
[`exec_`]: https://pursuit.purescript.org//////////////////////////////////////////packages/purescript-postgresql/1.7.2/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",
@@ -15,6 +15,8 @@
"decimal.js": "^10.4.3",
"pg": "^8.11.3",
"pg-copy-streams": "^6.0.6",
"pg-listen": "^1.7.0",
"postgres-interval": "1.2.0",
"postgres-range": "^1.1.4"
}
}

View File

@@ -23,10 +23,12 @@ 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-stream-pipes: ">=2.1.0 <3.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"
- pipes: ">=8.0.0 <9.0.0"
- precise-datetime: ">=7.0.0 <8.0.0"
- prelude: ">=6.0.1 <7.0.0"
- profunctor: ">=6.0.1 <7.0.0"
@@ -44,6 +46,7 @@ workspace:
- foreign-object
- node-child-process
- node-process
- precise-datetime
- quickcheck
- spec
- spec-quickcheck
@@ -99,7 +102,9 @@ workspace:
- node-os
- node-path
- node-process
- node-stream-pipes
- node-streams
- node-zlib
- nonempty
- now
- nullable
@@ -132,6 +137,7 @@ workspace:
- unfoldable
- unicode
- unlift
- unordered-collections
- unsafe-coerce
- variant
extra_packages: {}
@@ -720,6 +726,44 @@ packages:
- posix-types
- prelude
- unsafe-coerce
node-stream-pipes:
type: registry
version: 2.1.0
integrity: sha256-pYBOQY4bGEZzI5UHsUxJAhsKqtmE6CC1sHmFqgj64V8=
dependencies:
- aff
- arrays
- console
- control
- datetime
- effect
- either
- exceptions
- foldable-traversable
- foreign-object
- fork
- lists
- maybe
- mmorph
- newtype
- node-buffer
- node-event-emitter
- node-fs
- node-path
- node-streams
- node-zlib
- now
- ordered-collections
- parallel
- pipes
- prelude
- st
- strings
- tailrec
- transformers
- tuples
- unordered-collections
- unsafe-coerce
node-streams:
type: registry
version: 9.0.0
@@ -733,6 +777,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
@@ -1132,6 +1189,21 @@ packages:
- st
- transformers
- tuples
unordered-collections:
type: registry
version: 3.1.0
integrity: sha256-H2eQR+ylI+cljz4XzWfEbdF7ee+pnw2IZCeq69AuJ+Q=
dependencies:
- arrays
- enums
- functions
- integers
- lists
- prelude
- record
- tuples
- typelevel-prelude
- unfoldable
unsafe-coerce:
type: registry
version: 6.0.0

View File

@@ -1,7 +1,7 @@
package:
name: postgresql
publish:
version: '1.5.0'
version: '1.7.2'
license: 'GPL-3.0-or-later'
location:
githubOwner: 'cakekindel'
@@ -33,10 +33,12 @@ 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-stream-pipes: ">=2.1.0 <3.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"
- pipes: ">=8.0.0 <9.0.0"
- precise-datetime: ">=7.0.0 <8.0.0"
- prelude: ">=6.0.1 <7.0.0"
- profunctor: ">=6.0.1 <7.0.0"
@@ -56,6 +58,7 @@ package:
- foreign-object
- node-child-process
- node-process
- precise-datetime
- quickcheck
- spec
- spec-quickcheck

View File

@@ -3,7 +3,7 @@ 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)
@@ -57,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)
@@ -104,7 +105,7 @@ instance (MonadBracket e f m, MonadAff m) => MonadSession (PostgresT m) where
-- | - `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
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.

View File

@@ -3,7 +3,7 @@ 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.Session (class MonadSession, exec, exec_, query, streamIn, streamOut)
@@ -39,6 +39,7 @@ 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)

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

@@ -0,0 +1,30 @@
import PostgresInterval from 'postgres-interval'
/** @typedef {import('postgres-interval').IPostgresInterval} I */
/** @type {(o: {years: number, months: number, days: number, hours: number, minutes: number, seconds: number, milliseconds: number}) => I} */
export const make = o => Object.assign(PostgresInterval(''), o)
/** @type {(s: string) => () => I} */
export const parse = s => () => PostgresInterval(s)
/** @type {(a: I) => number} */
export const getYears = i => i.years || 0.0
/** @type {(a: I) => number} */
export const getMonths = i => i.months || 0.0
/** @type {(a: I) => number} */
export const getDays = i => i.days || 0.0
/** @type {(a: I) => number} */
export const getMinutes = i => i.minutes || 0.0
/** @type {(a: I) => number} */
export const getHours = i => i.hours || 0.0
/** @type {(a: I) => number} */
export const getSeconds = i => i.seconds || 0.0
/** @type {(a: I) => number} */
export const getMilliseconds = i => i.milliseconds || 0.0

View File

@@ -0,0 +1,88 @@
module Data.Postgres.Interval where
import Prelude
import Data.Int as Int
import Data.Maybe (Maybe(..))
import Data.Newtype (unwrap)
import Data.Time.Duration (class Duration, Days(..), Hours(..), Milliseconds(..), Minutes(..), Seconds(..), convertDuration)
import Effect (Effect)
zero :: IntervalRecord
zero = {years: 0, months: 0, days: 0, hours: 0, minutes: 0, seconds: 0, milliseconds: 0.0}
type IntervalRecord =
{ years :: Int
, months :: Int
, days :: Int
, hours :: Int
, minutes :: Int
, seconds :: Int
, milliseconds :: Number
}
foreign import data Interval :: Type
foreign import make :: IntervalRecord -> Interval
foreign import parse :: String -> Effect Interval
foreign import getYears :: Interval -> Int
foreign import getMonths :: Interval -> Int
foreign import getDays :: Interval -> Int
foreign import getHours :: Interval -> Int
foreign import getMinutes :: Interval -> Int
foreign import getSeconds :: Interval -> Int
foreign import getMilliseconds :: Interval -> Number
toDuration :: forall d. Semigroup d => Duration d => Interval -> Maybe d
toDuration a =
let
includesMonths = getYears a > 0 || getMonths a > 0
days :: d
days = convertDuration $ Days $ Int.toNumber $ getDays a
hours :: d
hours = convertDuration $ Hours $ Int.toNumber $ getHours a
minutes :: d
minutes = convertDuration $ Minutes $ Int.toNumber $ getMinutes a
seconds :: d
seconds = convertDuration $ Seconds $ Int.toNumber $ getSeconds a
milliseconds :: d
milliseconds = convertDuration $ Milliseconds $ getMilliseconds a
in
if includesMonths then Nothing else Just (days <> hours <> minutes <> seconds <> milliseconds)
toRecord :: Interval -> IntervalRecord
toRecord a =
{ years: getYears a
, months: getMonths a
, days: getDays a
, hours: getHours a
, minutes: getMinutes a
, seconds: getSeconds a
, milliseconds: getMilliseconds a
}
fromDuration :: forall d. Duration d => d -> Interval
fromDuration a =
let
millisTotal :: Number
millisTotal = (unwrap :: Milliseconds -> Number) $ convertDuration a
secondFactor = 1000.0
minuteFactor = 60.0 * secondFactor
hourFactor = 60.0 * minuteFactor
dayFactor = 24.0 * hourFactor
days = Int.trunc $ millisTotal / dayFactor
daysRem = millisTotal - (Int.toNumber days * dayFactor)
hours = Int.trunc $ daysRem / hourFactor
hoursRem = daysRem - (Int.toNumber hours * hourFactor)
minutes = Int.trunc $ hoursRem / minuteFactor
minutesRem = hoursRem - (Int.toNumber minutes * minuteFactor)
seconds = Int.trunc $ minutesRem / secondFactor
milliseconds = minutesRem - (Int.toNumber seconds * secondFactor)
in
make {years: 0, months: 0, days, hours, minutes, seconds, milliseconds}

View File

@@ -1,5 +1,24 @@
import Pg from 'pg'
import Range from 'postgres-range'
import { Buffer } from 'buffer'
import PostgresInterval from 'postgres-interval'
/** @type {(a: unknown) => boolean} */
export const isInstanceOfBuffer = a => a instanceof Buffer
/** @type {(a: unknown) => boolean} */
export const isInstanceOfInterval = a => {
return typeof a === 'object'
&& a !== null
&& ('years' in a
|| 'months' in a
|| 'days' in a
|| 'hours' in a
|| 'minutes' in a
|| 'seconds' in a
|| 'milliseconds' in a
)
}
export const modifyPgTypes = () => {
// https://github.com/brianc/node-pg-types/blob/master/lib/textParsers.js

View File

@@ -3,23 +3,28 @@ module Data.Postgres where
import Prelude
import Control.Alt ((<|>))
import Control.Monad.Error.Class (liftEither, liftMaybe)
import Control.Monad.Error.Class (liftEither, liftMaybe, throwError)
import Control.Monad.Except (ExceptT, runExceptT)
import Control.Monad.Morph (hoist)
import Control.Monad.Trans.Class (lift)
import Data.Bifunctor (lmap)
import Data.DateTime (DateTime)
import Data.DateTime.Instant (Instant)
import Data.DateTime.Instant as Instant
import Data.List.NonEmpty (NonEmptyList)
import Data.Maybe (Maybe(..))
import Data.Newtype (class Newtype, unwrap, wrap)
import Data.Postgres.Interval (Interval)
import Data.Postgres.Interval as Interval
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
import Data.RFC3339String as DateTime.ISO
import Data.Time.Duration (Days, Hours, Milliseconds, Minutes, Seconds)
import Data.Traversable (traverse)
import Effect (Effect)
import Effect.Exception (error)
import Foreign (ForeignError(..), unsafeToForeign)
import Foreign (ForeignError(..), tagOf, unsafeFromForeign, unsafeToForeign)
import Foreign as F
import JS.BigInt (BigInt)
import JS.BigInt as BigInt
@@ -40,6 +45,9 @@ derive newtype instance ReadForeign a => ReadForeign (JSON a)
-- | for some types to unmarshal as strings rather than JS values.
foreign import modifyPgTypes :: Effect Unit
foreign import isInstanceOfBuffer :: F.Foreign -> Boolean
foreign import isInstanceOfInterval :: F.Foreign -> Boolean
-- | The serialization & deserialization monad.
type RepT = ExceptT (NonEmptyList ForeignError) Effect
@@ -68,6 +76,9 @@ instance (Serialize a, Deserialize a) => Rep a
unsafeSerializeCoerce :: forall m a. Monad m => a -> m Raw
unsafeSerializeCoerce = pure <<< Raw.unsafeFromForeign <<< F.unsafeToForeign
invalidDuration :: NonEmptyList ForeignError
invalidDuration = pure $ ForeignError $ "Can't convert interval with year or month components to Milliseconds"
instance Serialize Raw where
serialize = pure
@@ -107,10 +118,38 @@ instance Serialize String where
instance Serialize Number where
serialize = unsafeSerializeCoerce
-- | `timestamp`, `timestamptz`
-- | `interval`
instance Serialize DateTime where
serialize = serialize <<< unwrap <<< DateTime.ISO.fromDateTime
-- | `interval`
instance Serialize Interval where
serialize = unsafeSerializeCoerce
-- | `interval`
instance Serialize Milliseconds where
serialize = serialize <<< Interval.fromDuration
-- | `interval`
instance Serialize Seconds where
serialize = serialize <<< Interval.fromDuration
-- | `interval`
instance Serialize Minutes where
serialize = serialize <<< Interval.fromDuration
-- | `interval`
instance Serialize Hours where
serialize = serialize <<< Interval.fromDuration
-- | `interval`
instance Serialize Days where
serialize = serialize <<< Interval.fromDuration
-- | `timestamp`, `timestamptz`
instance Serialize Instant where
serialize = serialize <<< Instant.toDateTime
-- | `Just` -> `a`, `Nothing` -> `NULL`
instance Serialize a => Serialize (Maybe a) where
serialize (Just a) = serialize a
@@ -142,7 +181,41 @@ instance ReadForeign a => Deserialize (JSON a) where
-- | `bytea`
instance Deserialize Buffer where
deserialize = (F.unsafeReadTagged "Buffer") <<< Raw.asForeign
deserialize =
let
notBuffer a = pure $ TypeMismatch (tagOf a) "Buffer"
readBuffer a = when (not $ isInstanceOfBuffer a) (throwError $ notBuffer a) $> unsafeFromForeign a
in
readBuffer <<< Raw.asForeign
-- | `interval`
instance Deserialize Interval where
deserialize =
let
notInterval a = pure $ TypeMismatch (tagOf a) "Interval"
readInterval a = when (not $ isInstanceOfInterval a) (throwError $ notInterval a) $> unsafeFromForeign a
in
readInterval <<< Raw.asForeign
-- | `interval`
instance Deserialize Milliseconds where
deserialize = flip bind (liftMaybe invalidDuration) <<< map Interval.toDuration <<< deserialize
-- | `interval`
instance Deserialize Seconds where
deserialize = flip bind (liftMaybe invalidDuration) <<< map Interval.toDuration <<< deserialize
-- | `interval`
instance Deserialize Minutes where
deserialize = flip bind (liftMaybe invalidDuration) <<< map Interval.toDuration <<< deserialize
-- | `interval`
instance Deserialize Hours where
deserialize = flip bind (liftMaybe invalidDuration) <<< map Interval.toDuration <<< deserialize
-- | `interval`
instance Deserialize Days where
deserialize = flip bind (liftMaybe invalidDuration) <<< map Interval.toDuration <<< deserialize
-- | `int2`, `int4`
instance Deserialize Int where
@@ -176,6 +249,10 @@ instance Deserialize DateTime where
let invalid = pure $ ForeignError $ "Not a valid ISO8601 string: `" <> s <> "`"
liftMaybe invalid $ DateTime.ISO.toDateTime $ wrap s
-- | `timestamp`, `timestamptz`
instance Deserialize Instant where
deserialize = map Instant.fromDateTime <<< deserialize
-- | postgres `array`
instance Deserialize a => Deserialize (Array a) where
deserialize = traverse (deserialize <<< Raw.unsafeFromForeign) <=< F.readArray <<< Raw.asForeign

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

@@ -0,0 +1,65 @@
module Pipes.Postgres where
import Prelude
import Control.Monad.Error.Class (class MonadError, class MonadThrow, catchError, throwError)
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 Effect.Exception (Error)
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
=> MonadError Error 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
liftAff $ void $ Client.exec "begin" client
let
releaseOnEOS Nothing = do
liftAff $ void $ Client.exec "commit" client
liftEffect $ Pool.release pool client
pure Nothing
releaseOnEOS (Just a) = pure (Just a)
pipe = Pipes.mapM releaseOnEOS >-> fromWritable (O.unsafeFromBufferWritable stream)
err e = do
liftAff $ void $ Client.exec "rollback" client
liftEffect $ Pool.release pool client
throwError e
catchError pipe err
stdout
:: forall m s c ct
. MonadAff m
=> MonadThrow Error 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 = liftEffect $ Pool.release pool client $> Nothing
releaseOnEOS (Just a) = pure (Just a)
fromReadable (O.unsafeFromBufferReadable stream) >-> Pipes.mapM releaseOnEOS

View File

@@ -0,0 +1,37 @@
module Test.Data.Postgres.Interval where
import Prelude
import Data.Postgres.Interval as Interval
import Data.Time.Duration (Milliseconds(..))
import Data.Traversable (for_)
import Data.Tuple.Nested (type (/\), (/\))
import Effect.Class (liftEffect)
import Test.Spec (Spec, describe, it)
import Test.Spec.Assertions (shouldEqual)
spec :: Spec Unit
spec =
describe "Data.Postgres.Interval" do
it "parse & toRecord" do
p <- liftEffect $ Interval.parse "3 days 04:05:06"
Interval.toRecord p `shouldEqual` Interval.zero {days = 3, hours = 4, minutes = 5, seconds = 6}
it "make & toRecord" do
let p = Interval.make $ Interval.zero {days = 3, hours = 4, minutes = 5, seconds = 6}
Interval.toRecord p `shouldEqual` Interval.zero {days = 3, hours = 4, minutes = 5, seconds = 6}
describe "fromDuration" do
for_
[ Milliseconds 100.0 /\ Interval.zero {milliseconds = 100.0}
, Milliseconds 1000.0 /\ Interval.zero {seconds = 1}
, Milliseconds 1100.0 /\ Interval.zero {seconds = 1, milliseconds = 100.0}
, Milliseconds 60000.0 /\ Interval.zero {minutes = 1}
, Milliseconds 61100.0 /\ Interval.zero {minutes = 1, seconds = 1, milliseconds = 100.0}
, Milliseconds 3600000.0 /\ Interval.zero {hours = 1}
, Milliseconds 3661100.0 /\ Interval.zero {hours = 1, minutes = 1, seconds = 1, milliseconds = 100.0}
, Milliseconds 86400000.0 /\ Interval.zero {days = 1}
, Milliseconds 90061100.0 /\ Interval.zero {days = 1, hours = 1, minutes = 1, seconds = 1, milliseconds = 100.0}
]
\(i /\ o) -> it ("converts " <> show i) do
Interval.toRecord (Interval.fromDuration i) `shouldEqual` o

View File

@@ -2,28 +2,28 @@ module Test.Data.Postgres where
import Prelude
import Control.Monad.Gen (chooseInt, elements, oneOf)
import Control.Monad.Gen (chooseFloat, chooseInt, elements, oneOf)
import Control.Parallel (parTraverse_)
import Data.Array (intercalate)
import Data.Array as Array
import Data.Array.NonEmpty as Array.NonEmpty
import Data.DateTime (DateTime(..), canonicalDate)
import Data.DateTime.Instant as Instant
import Data.Enum (toEnum)
import Data.Foldable (fold)
import Data.Identity (Identity)
import Data.Int as Int
import Data.Maybe (Maybe(..), fromJust, maybe)
import Data.Maybe (Maybe(..), fromJust, fromMaybe)
import Data.Newtype (class Newtype, unwrap, wrap)
import Data.Number (abs) as Number
import Data.Postgres (class Rep)
import Data.Postgres.Interval (Interval)
import Data.Postgres.Interval as Interval
import Data.Postgres.Query.Builder as Q
import Data.Postgres.Raw (Raw, jsNull)
import Data.Postgres.Raw as Raw
import Data.Postgres.Result (class FromRow)
import Data.RFC3339String as DateTime.ISO
import Data.String as String
import Data.Time (Time(..))
import Data.Time.Duration (class Duration, Days, Hours, Milliseconds, Minutes, Seconds)
import Data.Traversable (for, sequence)
import Data.Tuple.Nested ((/\))
import Effect (Effect)
@@ -35,20 +35,45 @@ import Effect.Unsafe (unsafePerformEffect)
import Foreign (Foreign, unsafeToForeign)
import Foreign.Object as Object
import JS.BigInt (BigInt)
import JS.BigInt as BigInt
import Node.Buffer (Buffer)
import Node.Buffer as Buffer
import Partial.Unsafe (unsafePartial)
import Simple.JSON (writeJSON)
import Test.Common (withClient, withPoolClient)
import Test.Common (withPoolClient)
import Test.QuickCheck (class Arbitrary, arbitrary, randomSeed)
import Test.QuickCheck.Gen (sample, vectorOf)
import Test.Spec (Spec, SpecT, around, describe, it, parallel)
import Test.Spec (Spec, SpecT, around, describe, it)
import Test.Spec.Assertions (fail)
foreign import readBigInt64BE :: Buffer -> Effect BigInt
foreign import dbg :: forall a. a -> Effect Unit
newtype GenIntervalSubMonth = GenIntervalSubMonth Interval
derive instance Newtype GenIntervalSubMonth _
instance Arbitrary GenIntervalSubMonth where
arbitrary = do
days <- chooseInt 0 30
hours <- chooseInt 0 23
minutes <- chooseInt 0 59
seconds <- chooseInt 0 59
milliseconds <- chooseFloat 0.0 999.9
pure $ wrap $ Interval.make $ Interval.zero {days = days, hours = hours, minutes = minutes, seconds = seconds, milliseconds = milliseconds}
newtype GenInterval = GenInterval Interval
derive instance Newtype GenInterval _
instance Arbitrary GenInterval where
arbitrary = do
years <- chooseInt 0 10
months <- chooseInt 0 11
days <- chooseInt 0 30
hours <- chooseInt 0 23
minutes <- chooseInt 0 59
seconds <- chooseInt 0 59
milliseconds <- chooseFloat 0.0 999.9
pure $ wrap $ Interval.make {years, months, days, hours, minutes, seconds, milliseconds}
newtype GenSmallInt = GenSmallInt Int
derive instance Newtype GenSmallInt _
@@ -196,6 +221,17 @@ spec =
around withPoolClient
$ describe "Data.Postgres"
$ do
let
durationFromGenInterval :: forall d. Semigroup d => Duration d => Newtype d Number => GenIntervalSubMonth -> d
durationFromGenInterval = fromMaybe (wrap 0.0) <<< Interval.toDuration <<< unwrap
durationEq :: forall d. Duration d => Newtype d Number => d -> d -> Boolean
durationEq a b = Number.abs (unwrap a - unwrap b) <= 0.001
check @Milliseconds @GenIntervalSubMonth { purs: "Milliseconds", sql: "interval", fromArb: durationFromGenInterval, isEq: durationEq}
check @Seconds @GenIntervalSubMonth { purs: "Seconds", sql: "interval", fromArb: durationFromGenInterval, isEq: durationEq}
check @Minutes @GenIntervalSubMonth { purs: "Minutes", sql: "interval", fromArb: durationFromGenInterval, isEq: durationEq}
check @Hours @GenIntervalSubMonth { purs: "Hours", sql: "interval", fromArb: durationFromGenInterval, isEq: durationEq}
check @Days @GenIntervalSubMonth { purs: "Days", sql: "interval", fromArb: durationFromGenInterval, isEq: durationEq}
check @Int @GenSmallInt { purs: "Int", sql: "int2", fromArb: unwrap, isEq: eq }
check @Int { purs: "Int", sql: "int4", fromArb: identity, isEq: eq }
check @String @GenString { purs: "String", sql: "text", fromArb: unwrap, isEq: eq }

View File

@@ -23,6 +23,7 @@ import Node.EventEmitter as Event
import Test.Control.Monad.Postgres as Test.Control.Monad.Postgres
import Test.Data.Postgres as Test.Data.Postgres
import Test.Data.Postgres.Custom as Test.Data.Postgres.Custom
import Test.Data.Postgres.Interval as Test.Data.Postgres.Interval
import Test.Effect.Postgres.Client as Test.Effect.Postgres.Client
import Test.Effect.Postgres.Pool as Test.Effect.Postgres.Pool
import Test.Spec.Reporter (specReporter)
@@ -65,6 +66,7 @@ main = launchAff_ do
$ runSpec [ specReporter ] do
Test.Data.Postgres.Custom.spec
Test.Data.Postgres.spec
Test.Data.Postgres.Interval.spec
Test.Effect.Postgres.Client.spec
Test.Effect.Postgres.Pool.spec
Test.Control.Monad.Postgres.spec