generated from tpl/purs
feat: init, basic serde
This commit is contained in:
parent
6fadf32a68
commit
e2eb753317
@ -1,3 +1,2 @@
|
||||
bun 1.0.11
|
||||
purescript 0.15.12
|
||||
nodejs 20.9.0
|
||||
bun 1.0.35
|
||||
purescript 0.15.15
|
||||
|
@ -8,11 +8,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"bun-types": "1.0.11",
|
||||
"postgres-range": "^1.1.4",
|
||||
"purs-tidy": "^0.10.0",
|
||||
"spago": "next"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"dependencies": {}
|
||||
"dependencies": { "pg-types": "^4.0.2" }
|
||||
}
|
||||
|
877
spago.lock
Normal file
877
spago.lock
Normal file
@ -0,0 +1,877 @@
|
||||
workspace:
|
||||
packages:
|
||||
pg:
|
||||
path: ./
|
||||
dependencies:
|
||||
- bifunctors
|
||||
- control
|
||||
- datetime
|
||||
- effect
|
||||
- exceptions
|
||||
- foldable-traversable
|
||||
- foreign
|
||||
- lists
|
||||
- maybe
|
||||
- newtype
|
||||
- node-buffer
|
||||
- precise-datetime
|
||||
- prelude
|
||||
- transformers
|
||||
- unsafe-coerce
|
||||
test_dependencies:
|
||||
- quickcheck
|
||||
- spec
|
||||
- spec-quickcheck
|
||||
build_plan:
|
||||
- aff
|
||||
- ansi
|
||||
- arraybuffer-types
|
||||
- arrays
|
||||
- avar
|
||||
- bifunctors
|
||||
- catenable-lists
|
||||
- console
|
||||
- const
|
||||
- contravariant
|
||||
- control
|
||||
- datetime
|
||||
- decimals
|
||||
- distributive
|
||||
- effect
|
||||
- either
|
||||
- enums
|
||||
- exceptions
|
||||
- exists
|
||||
- fixed-points
|
||||
- foldable-traversable
|
||||
- foreign
|
||||
- fork
|
||||
- formatters
|
||||
- free
|
||||
- functions
|
||||
- functors
|
||||
- gen
|
||||
- identity
|
||||
- integers
|
||||
- invariant
|
||||
- js-date
|
||||
- lazy
|
||||
- lcg
|
||||
- lists
|
||||
- maybe
|
||||
- mmorph
|
||||
- newtype
|
||||
- node-buffer
|
||||
- nonempty
|
||||
- now
|
||||
- nullable
|
||||
- numbers
|
||||
- ordered-collections
|
||||
- orders
|
||||
- parallel
|
||||
- parsing
|
||||
- partial
|
||||
- pipes
|
||||
- precise-datetime
|
||||
- prelude
|
||||
- profunctor
|
||||
- quickcheck
|
||||
- random
|
||||
- record
|
||||
- refs
|
||||
- safe-coerce
|
||||
- spec
|
||||
- spec-quickcheck
|
||||
- st
|
||||
- strings
|
||||
- tailrec
|
||||
- transformers
|
||||
- tuples
|
||||
- type-equality
|
||||
- unfoldable
|
||||
- unicode
|
||||
- unsafe-coerce
|
||||
extra_packages: {}
|
||||
packages:
|
||||
aff:
|
||||
type: registry
|
||||
version: 7.1.0
|
||||
integrity: sha256-7hOC6uQO9XBAI5FD8F33ChLjFAiZVfd4BJMqlMh7TNU=
|
||||
dependencies:
|
||||
- arrays
|
||||
- bifunctors
|
||||
- control
|
||||
- datetime
|
||||
- effect
|
||||
- either
|
||||
- exceptions
|
||||
- foldable-traversable
|
||||
- functions
|
||||
- maybe
|
||||
- newtype
|
||||
- parallel
|
||||
- prelude
|
||||
- refs
|
||||
- tailrec
|
||||
- transformers
|
||||
- unsafe-coerce
|
||||
ansi:
|
||||
type: registry
|
||||
version: 7.0.0
|
||||
integrity: sha256-ZMB6HD+q9CXvn9fRCmJ8dvuDrOVHcjombL3oNOerVnE=
|
||||
dependencies:
|
||||
- foldable-traversable
|
||||
- lists
|
||||
- strings
|
||||
arraybuffer-types:
|
||||
type: registry
|
||||
version: 3.0.2
|
||||
integrity: sha256-mQKokysYVkooS4uXbO+yovmV/s8b138Ws3zQvOwIHRA=
|
||||
dependencies: []
|
||||
arrays:
|
||||
type: registry
|
||||
version: 7.3.0
|
||||
integrity: sha256-tmcklBlc/muUtUfr9RapdCPwnlQeB3aSrC4dK85gQlc=
|
||||
dependencies:
|
||||
- bifunctors
|
||||
- control
|
||||
- foldable-traversable
|
||||
- functions
|
||||
- maybe
|
||||
- nonempty
|
||||
- partial
|
||||
- prelude
|
||||
- safe-coerce
|
||||
- st
|
||||
- tailrec
|
||||
- tuples
|
||||
- unfoldable
|
||||
- unsafe-coerce
|
||||
avar:
|
||||
type: registry
|
||||
version: 5.0.0
|
||||
integrity: sha256-e7hf0x4hEpcygXP0LtvfvAQ49Bbj2aWtZT3gqM///0A=
|
||||
dependencies:
|
||||
- aff
|
||||
- effect
|
||||
- either
|
||||
- exceptions
|
||||
- functions
|
||||
- maybe
|
||||
bifunctors:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-/gZwC9YhNxZNQpnHa5BIYerCGM2jeX9ukZiEvYxm5Nw=
|
||||
dependencies:
|
||||
- const
|
||||
- either
|
||||
- newtype
|
||||
- prelude
|
||||
- tuples
|
||||
catenable-lists:
|
||||
type: registry
|
||||
version: 7.0.0
|
||||
integrity: sha256-76vYENhwF4BWTBsjeLuErCH2jqVT4M3R1HX+4RwSftA=
|
||||
dependencies:
|
||||
- control
|
||||
- foldable-traversable
|
||||
- lists
|
||||
- maybe
|
||||
- prelude
|
||||
- tuples
|
||||
- unfoldable
|
||||
console:
|
||||
type: registry
|
||||
version: 6.1.0
|
||||
integrity: sha256-CxmAzjgyuGDmt9FZW51VhV6rBPwR6o0YeKUzA9rSzcM=
|
||||
dependencies:
|
||||
- effect
|
||||
- prelude
|
||||
const:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-tNrxDW8D8H4jdHE2HiPzpLy08zkzJMmGHdRqt5BQuTc=
|
||||
dependencies:
|
||||
- invariant
|
||||
- newtype
|
||||
- prelude
|
||||
contravariant:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-TP+ooAp3vvmdjfQsQJSichF5B4BPDHp3wAJoWchip6c=
|
||||
dependencies:
|
||||
- const
|
||||
- either
|
||||
- newtype
|
||||
- prelude
|
||||
- tuples
|
||||
control:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-sH7Pg9E96JCPF9PIA6oQ8+BjTyO/BH1ZuE/bOcyj4Jk=
|
||||
dependencies:
|
||||
- newtype
|
||||
- prelude
|
||||
datetime:
|
||||
type: registry
|
||||
version: 6.1.0
|
||||
integrity: sha256-g/5X5BBegQWLpI9IWD+sY6mcaYpzzlW5lz5NBzaMtyI=
|
||||
dependencies:
|
||||
- bifunctors
|
||||
- control
|
||||
- either
|
||||
- enums
|
||||
- foldable-traversable
|
||||
- functions
|
||||
- gen
|
||||
- integers
|
||||
- lists
|
||||
- maybe
|
||||
- newtype
|
||||
- numbers
|
||||
- ordered-collections
|
||||
- partial
|
||||
- prelude
|
||||
- tuples
|
||||
decimals:
|
||||
type: registry
|
||||
version: 7.1.0
|
||||
integrity: sha256-DriR6lPEfFpjVv7e4JAQkr3ZLf0h17Qg2cAIrhxWV7w=
|
||||
dependencies:
|
||||
- maybe
|
||||
distributive:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-HTDdmEnzigMl+02SJB88j+gAXDx9VKsbvR4MJGDPbOQ=
|
||||
dependencies:
|
||||
- identity
|
||||
- newtype
|
||||
- prelude
|
||||
- tuples
|
||||
- type-equality
|
||||
effect:
|
||||
type: registry
|
||||
version: 4.0.0
|
||||
integrity: sha256-eBtZu+HZcMa5HilvI6kaDyVX3ji8p0W9MGKy2K4T6+M=
|
||||
dependencies:
|
||||
- prelude
|
||||
either:
|
||||
type: registry
|
||||
version: 6.1.0
|
||||
integrity: sha256-6hgTPisnMWVwQivOu2PKYcH8uqjEOOqDyaDQVUchTpY=
|
||||
dependencies:
|
||||
- control
|
||||
- invariant
|
||||
- maybe
|
||||
- prelude
|
||||
enums:
|
||||
type: registry
|
||||
version: 6.0.1
|
||||
integrity: sha256-HWaD73JFLorc4A6trKIRUeDMdzE+GpkJaEOM1nTNkC8=
|
||||
dependencies:
|
||||
- control
|
||||
- either
|
||||
- gen
|
||||
- maybe
|
||||
- newtype
|
||||
- nonempty
|
||||
- partial
|
||||
- prelude
|
||||
- tuples
|
||||
- unfoldable
|
||||
exceptions:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-y/xTAEIZIARCE+50/u1di0ncebJ+CIwNOLswyOWzMTw=
|
||||
dependencies:
|
||||
- effect
|
||||
- either
|
||||
- maybe
|
||||
- prelude
|
||||
exists:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-A0JQHpTfo1dNOj9U5/Fd3xndlRSE0g2IQWOGor2yXn8=
|
||||
dependencies:
|
||||
- unsafe-coerce
|
||||
fixed-points:
|
||||
type: registry
|
||||
version: 7.0.0
|
||||
integrity: sha256-hTl5fzeG4mzAOFzEzAeNH7kJvJgYCH7x3v2NdX9pOE4=
|
||||
dependencies:
|
||||
- exists
|
||||
- newtype
|
||||
- prelude
|
||||
- transformers
|
||||
foldable-traversable:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-fLeqRYM4jUrZD5H4WqcwUgzU7XfYkzO4zhgtNc3jcWM=
|
||||
dependencies:
|
||||
- bifunctors
|
||||
- const
|
||||
- control
|
||||
- either
|
||||
- functors
|
||||
- identity
|
||||
- maybe
|
||||
- newtype
|
||||
- orders
|
||||
- prelude
|
||||
- tuples
|
||||
foreign:
|
||||
type: registry
|
||||
version: 7.0.0
|
||||
integrity: sha256-1ORiqoS3HW+qfwSZAppHPWy4/6AQysxZ2t29jcdUMNA=
|
||||
dependencies:
|
||||
- either
|
||||
- functions
|
||||
- identity
|
||||
- integers
|
||||
- lists
|
||||
- maybe
|
||||
- prelude
|
||||
- strings
|
||||
- transformers
|
||||
fork:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-X7u0SuCvFbLbzuNEKLBNuWjmcroqMqit4xEzpQwAP7E=
|
||||
dependencies:
|
||||
- aff
|
||||
formatters:
|
||||
type: registry
|
||||
version: 7.0.0
|
||||
integrity: sha256-5JaC9d2p0xoqJWjWxlHH19R4iJwFTBr4j7SlYcLgicE=
|
||||
dependencies:
|
||||
- datetime
|
||||
- fixed-points
|
||||
- lists
|
||||
- numbers
|
||||
- parsing
|
||||
- prelude
|
||||
- transformers
|
||||
free:
|
||||
type: registry
|
||||
version: 7.1.0
|
||||
integrity: sha256-JAumgEsGSzJCNLD8AaFvuX7CpqS5yruCngi6yI7+V5k=
|
||||
dependencies:
|
||||
- catenable-lists
|
||||
- control
|
||||
- distributive
|
||||
- either
|
||||
- exists
|
||||
- foldable-traversable
|
||||
- invariant
|
||||
- lazy
|
||||
- maybe
|
||||
- prelude
|
||||
- tailrec
|
||||
- transformers
|
||||
- tuples
|
||||
- unsafe-coerce
|
||||
functions:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-adMyJNEnhGde2unHHAP79gPtlNjNqzgLB8arEOn9hLI=
|
||||
dependencies:
|
||||
- prelude
|
||||
functors:
|
||||
type: registry
|
||||
version: 5.0.0
|
||||
integrity: sha256-zfPWWYisbD84MqwpJSZFlvM6v86McM68ob8p9s27ywU=
|
||||
dependencies:
|
||||
- bifunctors
|
||||
- const
|
||||
- contravariant
|
||||
- control
|
||||
- distributive
|
||||
- either
|
||||
- invariant
|
||||
- maybe
|
||||
- newtype
|
||||
- prelude
|
||||
- profunctor
|
||||
- tuples
|
||||
- unsafe-coerce
|
||||
gen:
|
||||
type: registry
|
||||
version: 4.0.0
|
||||
integrity: sha256-f7yzAXWwr+xnaqEOcvyO3ezKdoes8+WXWdXIHDBCAPI=
|
||||
dependencies:
|
||||
- either
|
||||
- foldable-traversable
|
||||
- identity
|
||||
- maybe
|
||||
- newtype
|
||||
- nonempty
|
||||
- prelude
|
||||
- tailrec
|
||||
- tuples
|
||||
- unfoldable
|
||||
identity:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-4wY0XZbAksjY6UAg99WkuKyJlQlWAfTi2ssadH0wVMY=
|
||||
dependencies:
|
||||
- control
|
||||
- invariant
|
||||
- newtype
|
||||
- prelude
|
||||
integers:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-sf+sK26R1hzwl3NhXR7WAu9zCDjQnfoXwcyGoseX158=
|
||||
dependencies:
|
||||
- maybe
|
||||
- numbers
|
||||
- prelude
|
||||
invariant:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-RGWWyYrz0Hs1KjPDA+87Kia67ZFBhfJ5lMGOMCEFoLo=
|
||||
dependencies:
|
||||
- control
|
||||
- prelude
|
||||
js-date:
|
||||
type: registry
|
||||
version: 8.0.0
|
||||
integrity: sha256-6TVF4DWg5JL+jRAsoMssYw8rgOVALMUHT1CuNZt8NRo=
|
||||
dependencies:
|
||||
- datetime
|
||||
- effect
|
||||
- exceptions
|
||||
- foreign
|
||||
- integers
|
||||
- now
|
||||
lazy:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-lMsfFOnlqfe4KzRRiW8ot5ge6HtcU3Eyh2XkXcP5IgU=
|
||||
dependencies:
|
||||
- control
|
||||
- foldable-traversable
|
||||
- invariant
|
||||
- prelude
|
||||
lcg:
|
||||
type: registry
|
||||
version: 4.0.0
|
||||
integrity: sha256-h7ME5cthLfbgJOJdsZcSfFpwXsx4rf8YmhebU+3iSYg=
|
||||
dependencies:
|
||||
- effect
|
||||
- integers
|
||||
- maybe
|
||||
- partial
|
||||
- prelude
|
||||
- random
|
||||
lists:
|
||||
type: registry
|
||||
version: 7.0.0
|
||||
integrity: sha256-EKF15qYqucuXP2lT/xPxhqy58f0FFT6KHdIB/yBOayI=
|
||||
dependencies:
|
||||
- bifunctors
|
||||
- control
|
||||
- foldable-traversable
|
||||
- lazy
|
||||
- maybe
|
||||
- newtype
|
||||
- nonempty
|
||||
- partial
|
||||
- prelude
|
||||
- tailrec
|
||||
- tuples
|
||||
- unfoldable
|
||||
maybe:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-5cCIb0wPwbat2PRkQhUeZO0jcAmf8jCt2qE0wbC3v2Q=
|
||||
dependencies:
|
||||
- control
|
||||
- invariant
|
||||
- newtype
|
||||
- prelude
|
||||
mmorph:
|
||||
type: registry
|
||||
version: 7.0.0
|
||||
integrity: sha256-urZlZNNqGeQFe5D/ClHlR8QgGBNHTMFPtJ5S5IpflTQ=
|
||||
dependencies:
|
||||
- free
|
||||
- functors
|
||||
- transformers
|
||||
newtype:
|
||||
type: registry
|
||||
version: 5.0.0
|
||||
integrity: sha256-gdrQu8oGe9eZE6L3wOI8ql/igOg+zEGB5ITh2g+uttw=
|
||||
dependencies:
|
||||
- prelude
|
||||
- safe-coerce
|
||||
node-buffer:
|
||||
type: registry
|
||||
version: 9.0.0
|
||||
integrity: sha256-PWE2DJ5ruBLCmeA/fUiuySEFmUJ/VuRfyrnCuVZBlu4=
|
||||
dependencies:
|
||||
- arraybuffer-types
|
||||
- effect
|
||||
- maybe
|
||||
- nullable
|
||||
- st
|
||||
- unsafe-coerce
|
||||
nonempty:
|
||||
type: registry
|
||||
version: 7.0.0
|
||||
integrity: sha256-54ablJZUHGvvlTJzi3oXyPCuvY6zsrWJuH/dMJ/MFLs=
|
||||
dependencies:
|
||||
- control
|
||||
- foldable-traversable
|
||||
- maybe
|
||||
- prelude
|
||||
- tuples
|
||||
- unfoldable
|
||||
now:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-xZ7x37ZMREfs6GCDw/h+FaKHV/3sPWmtqBZRGTxybQY=
|
||||
dependencies:
|
||||
- datetime
|
||||
- effect
|
||||
nullable:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-yiGBVl3AD+Guy4kNWWeN+zl1gCiJK+oeIFtZtPCw4+o=
|
||||
dependencies:
|
||||
- effect
|
||||
- functions
|
||||
- maybe
|
||||
numbers:
|
||||
type: registry
|
||||
version: 9.0.1
|
||||
integrity: sha256-/9M6aeMDBdB4cwYDeJvLFprAHZ49EbtKQLIJsneXLIk=
|
||||
dependencies:
|
||||
- functions
|
||||
- maybe
|
||||
ordered-collections:
|
||||
type: registry
|
||||
version: 3.2.0
|
||||
integrity: sha256-o9jqsj5rpJmMdoe/zyufWHFjYYFTTsJpgcuCnqCO6PM=
|
||||
dependencies:
|
||||
- arrays
|
||||
- foldable-traversable
|
||||
- gen
|
||||
- lists
|
||||
- maybe
|
||||
- partial
|
||||
- prelude
|
||||
- st
|
||||
- tailrec
|
||||
- tuples
|
||||
- unfoldable
|
||||
orders:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-nBA0g3/ai0euH8q9pSbGqk53W2q6agm/dECZTHcoink=
|
||||
dependencies:
|
||||
- newtype
|
||||
- prelude
|
||||
parallel:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-VJbkGD0rAKX+NUEeBJbYJ78bEKaZbgow+QwQEfPB6ko=
|
||||
dependencies:
|
||||
- control
|
||||
- effect
|
||||
- either
|
||||
- foldable-traversable
|
||||
- functors
|
||||
- maybe
|
||||
- newtype
|
||||
- prelude
|
||||
- profunctor
|
||||
- refs
|
||||
- transformers
|
||||
parsing:
|
||||
type: registry
|
||||
version: 10.2.0
|
||||
integrity: sha256-ZDIdMFAKkst57x6BVa1aUWJnS8smoZnXsZ339Aq1mPA=
|
||||
dependencies:
|
||||
- arrays
|
||||
- control
|
||||
- effect
|
||||
- either
|
||||
- enums
|
||||
- foldable-traversable
|
||||
- functions
|
||||
- identity
|
||||
- integers
|
||||
- lazy
|
||||
- lists
|
||||
- maybe
|
||||
- newtype
|
||||
- nullable
|
||||
- numbers
|
||||
- partial
|
||||
- prelude
|
||||
- st
|
||||
- strings
|
||||
- tailrec
|
||||
- transformers
|
||||
- tuples
|
||||
- unfoldable
|
||||
- unicode
|
||||
- unsafe-coerce
|
||||
partial:
|
||||
type: registry
|
||||
version: 4.0.0
|
||||
integrity: sha256-fwXerld6Xw1VkReh8yeQsdtLVrjfGiVuC5bA1Wyo/J4=
|
||||
dependencies: []
|
||||
pipes:
|
||||
type: registry
|
||||
version: 8.0.0
|
||||
integrity: sha256-kvfqGM4cPA/wCcBHbp5psouFw5dZGvku2462x7ZBwSY=
|
||||
dependencies:
|
||||
- aff
|
||||
- lists
|
||||
- mmorph
|
||||
- prelude
|
||||
- tailrec
|
||||
- transformers
|
||||
- tuples
|
||||
precise-datetime:
|
||||
type: registry
|
||||
version: 7.0.0
|
||||
integrity: sha256-F7tzZ7++Ihtg3xjumzwaHQvGQg61UtEAe5MWeOlTzRY=
|
||||
dependencies:
|
||||
- arrays
|
||||
- datetime
|
||||
- decimals
|
||||
- either
|
||||
- enums
|
||||
- foldable-traversable
|
||||
- formatters
|
||||
- integers
|
||||
- js-date
|
||||
- lists
|
||||
- maybe
|
||||
- newtype
|
||||
- numbers
|
||||
- prelude
|
||||
- strings
|
||||
- tuples
|
||||
- unicode
|
||||
prelude:
|
||||
type: registry
|
||||
version: 6.0.1
|
||||
integrity: sha256-o8p6SLYmVPqzXZhQFd2hGAWEwBoXl1swxLG/scpJ0V0=
|
||||
dependencies: []
|
||||
profunctor:
|
||||
type: registry
|
||||
version: 6.0.1
|
||||
integrity: sha256-E58hSYdJvF2Qjf9dnWLPlJKh2Z2fLfFLkQoYi16vsFk=
|
||||
dependencies:
|
||||
- control
|
||||
- distributive
|
||||
- either
|
||||
- exists
|
||||
- invariant
|
||||
- newtype
|
||||
- prelude
|
||||
- tuples
|
||||
quickcheck:
|
||||
type: registry
|
||||
version: 8.0.1
|
||||
integrity: sha256-ZvpccKQCvgslTXZCNmpYW4bUsFzhZd/kQUr2WmxFTGY=
|
||||
dependencies:
|
||||
- arrays
|
||||
- console
|
||||
- control
|
||||
- effect
|
||||
- either
|
||||
- enums
|
||||
- exceptions
|
||||
- foldable-traversable
|
||||
- gen
|
||||
- identity
|
||||
- integers
|
||||
- lazy
|
||||
- lcg
|
||||
- lists
|
||||
- maybe
|
||||
- newtype
|
||||
- nonempty
|
||||
- numbers
|
||||
- partial
|
||||
- prelude
|
||||
- record
|
||||
- st
|
||||
- strings
|
||||
- tailrec
|
||||
- transformers
|
||||
- tuples
|
||||
- unfoldable
|
||||
random:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-CJ611a35MPCE7XQMp0rdC6MCn76znlhisiCRgboAG+Q=
|
||||
dependencies:
|
||||
- effect
|
||||
- integers
|
||||
record:
|
||||
type: registry
|
||||
version: 4.0.0
|
||||
integrity: sha256-Za5U85bTRJEfGK5Sk4hM41oXy84YQI0I8TL3WUn1Qzg=
|
||||
dependencies:
|
||||
- functions
|
||||
- prelude
|
||||
- unsafe-coerce
|
||||
refs:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-Vgwne7jIbD3ZMoLNNETLT8Litw6lIYo3MfYNdtYWj9s=
|
||||
dependencies:
|
||||
- effect
|
||||
- prelude
|
||||
safe-coerce:
|
||||
type: registry
|
||||
version: 2.0.0
|
||||
integrity: sha256-a1ibQkiUcbODbLE/WAq7Ttbbh9ex+x33VCQ7GngKudU=
|
||||
dependencies:
|
||||
- unsafe-coerce
|
||||
spec:
|
||||
type: registry
|
||||
version: 7.6.0
|
||||
integrity: sha256-+merGdQbL9zWONbnt8S8J9afGJ59MQqGtS0qSd3yu4I=
|
||||
dependencies:
|
||||
- aff
|
||||
- ansi
|
||||
- arrays
|
||||
- avar
|
||||
- bifunctors
|
||||
- control
|
||||
- datetime
|
||||
- effect
|
||||
- either
|
||||
- exceptions
|
||||
- foldable-traversable
|
||||
- fork
|
||||
- identity
|
||||
- integers
|
||||
- lists
|
||||
- maybe
|
||||
- newtype
|
||||
- now
|
||||
- ordered-collections
|
||||
- parallel
|
||||
- pipes
|
||||
- prelude
|
||||
- refs
|
||||
- strings
|
||||
- tailrec
|
||||
- transformers
|
||||
- tuples
|
||||
spec-quickcheck:
|
||||
type: registry
|
||||
version: 5.0.0
|
||||
integrity: sha256-iE0iThqZCuDGe3pwg5RvqcL8E5cRQ4txDuloCclOsCs=
|
||||
dependencies:
|
||||
- aff
|
||||
- prelude
|
||||
- quickcheck
|
||||
- random
|
||||
- spec
|
||||
st:
|
||||
type: registry
|
||||
version: 6.2.0
|
||||
integrity: sha256-z9X0WsOUlPwNx9GlCC+YccCyz8MejC8Wb0C4+9fiBRY=
|
||||
dependencies:
|
||||
- partial
|
||||
- prelude
|
||||
- tailrec
|
||||
- unsafe-coerce
|
||||
strings:
|
||||
type: registry
|
||||
version: 6.0.1
|
||||
integrity: sha256-WssD3DbX4OPzxSdjvRMX0yvc9+pS7n5gyPv5I2Trb7k=
|
||||
dependencies:
|
||||
- arrays
|
||||
- control
|
||||
- either
|
||||
- enums
|
||||
- foldable-traversable
|
||||
- gen
|
||||
- integers
|
||||
- maybe
|
||||
- newtype
|
||||
- nonempty
|
||||
- partial
|
||||
- prelude
|
||||
- tailrec
|
||||
- tuples
|
||||
- unfoldable
|
||||
- unsafe-coerce
|
||||
tailrec:
|
||||
type: registry
|
||||
version: 6.1.0
|
||||
integrity: sha256-Xx19ECVDRrDWpz9D2GxQHHV89vd61dnXxQm0IcYQHGk=
|
||||
dependencies:
|
||||
- bifunctors
|
||||
- effect
|
||||
- either
|
||||
- identity
|
||||
- maybe
|
||||
- partial
|
||||
- prelude
|
||||
- refs
|
||||
transformers:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-Pzw40HjthX77tdPAYzjx43LK3X5Bb7ZspYAp27wksFA=
|
||||
dependencies:
|
||||
- control
|
||||
- distributive
|
||||
- effect
|
||||
- either
|
||||
- exceptions
|
||||
- foldable-traversable
|
||||
- identity
|
||||
- lazy
|
||||
- maybe
|
||||
- newtype
|
||||
- prelude
|
||||
- tailrec
|
||||
- tuples
|
||||
- unfoldable
|
||||
tuples:
|
||||
type: registry
|
||||
version: 7.0.0
|
||||
integrity: sha256-1rXgTomes9105BjgXqIw0FL6Fz1lqqUTLWOumhWec1M=
|
||||
dependencies:
|
||||
- control
|
||||
- invariant
|
||||
- prelude
|
||||
type-equality:
|
||||
type: registry
|
||||
version: 4.0.1
|
||||
integrity: sha256-Hs9D6Y71zFi/b+qu5NSbuadUQXe5iv5iWx0226vOHUw=
|
||||
dependencies: []
|
||||
unfoldable:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-JtikvJdktRap7vr/K4ITlxUX1QexpnqBq0G/InLr6eg=
|
||||
dependencies:
|
||||
- foldable-traversable
|
||||
- maybe
|
||||
- partial
|
||||
- prelude
|
||||
- tuples
|
||||
unicode:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-QJnTVZpmihEAUiMeYrfkusVoziJWp2hJsgi9bMQLue8=
|
||||
dependencies:
|
||||
- foldable-traversable
|
||||
- maybe
|
||||
- strings
|
||||
unsafe-coerce:
|
||||
type: registry
|
||||
version: 6.0.0
|
||||
integrity: sha256-IqIYW4Vkevn8sI+6aUwRGvd87tVL36BBeOr0cGAE7t0=
|
||||
dependencies: []
|
33
spago.yaml
33
spago.yaml
@ -1,24 +1,31 @@
|
||||
package:
|
||||
name: pg
|
||||
build:
|
||||
strict: true
|
||||
pedantic_packages: true
|
||||
dependencies:
|
||||
- prelude
|
||||
- aff
|
||||
- bifunctors
|
||||
- control
|
||||
- datetime
|
||||
- effect
|
||||
- either
|
||||
- maybe
|
||||
- exceptions
|
||||
- foldable-traversable
|
||||
- console
|
||||
- foreign
|
||||
- lists
|
||||
- maybe
|
||||
- newtype
|
||||
- strings
|
||||
- stringutils
|
||||
- node-buffer
|
||||
- precise-datetime
|
||||
- prelude
|
||||
- transformers
|
||||
- tuples
|
||||
- typelevel-prelude
|
||||
name: project
|
||||
- unsafe-coerce
|
||||
test:
|
||||
main: Test.Main
|
||||
dependencies:
|
||||
- quickcheck
|
||||
- spec
|
||||
- spec-quickcheck
|
||||
workspace:
|
||||
extra_packages: {}
|
||||
package_set:
|
||||
url: https://raw.githubusercontent.com/purescript/package-sets/psc-0.15.10-20230930/packages.json
|
||||
hash: sha256-nTsd44o7/hrTdk0c6dh0wyBqhFFDJJIeKdQU6L1zv/A=
|
||||
packageSet:
|
||||
registry: 50.5.0
|
||||
|
23
src/Data.Postgres.Geometry.purs
Normal file
23
src/Data.Postgres.Geometry.purs
Normal file
@ -0,0 +1,23 @@
|
||||
module Data.Postgres.Geometry where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Data.Generic.Rep (class Generic)
|
||||
import Data.Newtype (class Newtype)
|
||||
import Data.Show.Generic (genericShow)
|
||||
|
||||
newtype Point = Point { x :: Number, y :: Number }
|
||||
|
||||
derive instance Newtype Point _
|
||||
derive instance Generic Point _
|
||||
derive instance Eq Point
|
||||
instance Show Point where
|
||||
show = genericShow
|
||||
|
||||
newtype Circle = Circle { center :: Point, radius :: Number }
|
||||
|
||||
derive instance Newtype Circle _
|
||||
derive instance Generic Circle _
|
||||
derive instance Eq Circle
|
||||
instance Show Circle where
|
||||
show = genericShow
|
71
src/Data.Postgres.Range.js
Normal file
71
src/Data.Postgres.Range.js
Normal file
@ -0,0 +1,71 @@
|
||||
import * as Range from 'postgres-range'
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {{upper: T | undefined, lower: T | undefined, lowerIncl: boolean, upperIncl: boolean}} RangeRawRecord
|
||||
*/
|
||||
|
||||
/** @type {<T>(_: Range.Range<T>) => RangeRawRecord<T>} */
|
||||
export const rangeRawToRecord = r => {
|
||||
if (r.hasMask(Range.RANGE_EMPTY)) {
|
||||
return {
|
||||
upper: undefined,
|
||||
lower: undefined,
|
||||
lowerIncl: false,
|
||||
upperIncl: false,
|
||||
}
|
||||
} else {
|
||||
const upper = r.upper === null ? undefined : r.upper
|
||||
const lower = r.lower === null ? undefined : r.lower
|
||||
return {
|
||||
upper: r.hasMask(Range.RANGE_UB_INF) ? undefined : upper,
|
||||
lower: r.hasMask(Range.RANGE_LB_INF) ? undefined : lower,
|
||||
lowerIncl: r.hasMask(Range.RANGE_LB_INC),
|
||||
upperIncl: r.hasMask(Range.RANGE_UB_INC),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {<T>(_: RangeRawRecord<T>) => Range.Range<T>} */
|
||||
export const rangeRawFromRecord = r => {
|
||||
const upper = r.upper === undefined ? null : r.upper
|
||||
const lower = r.lower === undefined ? null : r.lower
|
||||
if (upper === null && lower === null) {
|
||||
// @ts-ignore
|
||||
return new Range.Range(lower, upper, Range.RANGE_EMPTY)
|
||||
}
|
||||
|
||||
let mask = 0
|
||||
if (upper === null) {
|
||||
mask |= Range.RANGE_UB_INF
|
||||
} else if (r.upperIncl) {
|
||||
mask |= Range.RANGE_UB_INC
|
||||
}
|
||||
|
||||
if (lower === null) {
|
||||
mask |= Range.RANGE_LB_INF
|
||||
} else if (r.lowerIncl) {
|
||||
mask |= Range.RANGE_LB_INC
|
||||
}
|
||||
|
||||
return new Range.Range(lower, upper, mask)
|
||||
}
|
||||
|
||||
/** @type {<T>(r: Range.Range<T>) => () => string} */
|
||||
export const rangeRawSerialize = r => () => {
|
||||
return Range.serialize(r)
|
||||
}
|
||||
|
||||
/** @type {<T>(r: string) => (f: (s: string) => () => T) => () => Range.Range<T>} */
|
||||
export const rangeRawParse = r => f => () => {
|
||||
return Range.parse(r, s => f(s)())
|
||||
}
|
||||
|
||||
/** @type {(r: unknown) => () => Range.Range<unknown>} */
|
||||
export const readRangeRaw = r => () => {
|
||||
if (r instanceof Range.Range) {
|
||||
return r
|
||||
} else {
|
||||
throw new TypeError(`expected instance of Range, found ${r}`)
|
||||
}
|
||||
}
|
122
src/Data.Postgres.Range.purs
Normal file
122
src/Data.Postgres.Range.purs
Normal file
@ -0,0 +1,122 @@
|
||||
module Data.Postgres.Range where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Control.Alt ((<|>))
|
||||
import Control.Monad.Trans.Class (lift)
|
||||
import Data.Generic.Rep (class Generic)
|
||||
import Data.Maybe (Maybe(..), fromMaybe)
|
||||
import Data.Newtype (class Newtype, unwrap)
|
||||
import Data.Postgres (class Deserialize, class Rep, class Serialize, RepT, deserialize, serialize, smash)
|
||||
import Data.Postgres.Raw (Raw)
|
||||
import Data.Postgres.Raw as Raw
|
||||
import Data.Show.Generic (genericShow)
|
||||
import Effect (Effect)
|
||||
import Foreign (unsafeToForeign)
|
||||
|
||||
type RangeRawRecord = { upper :: Raw, lower :: Raw, lowerIncl :: Boolean, upperIncl :: Boolean }
|
||||
|
||||
foreign import data RangeRaw :: Type
|
||||
foreign import readRangeRaw :: Raw -> Effect RangeRaw
|
||||
foreign import rangeRawToRecord :: RangeRaw -> RangeRawRecord
|
||||
foreign import rangeRawFromRecord :: RangeRawRecord -> RangeRaw
|
||||
foreign import rangeRawParse :: String -> (String -> Effect Raw) -> Effect RangeRaw
|
||||
foreign import rangeRawSerialize :: RangeRaw -> Effect String
|
||||
|
||||
rangeFromRaw :: forall a. Deserialize a => RangeRawRecord -> RepT (Range a)
|
||||
rangeFromRaw raw = do
|
||||
upper' :: Maybe a <- deserialize raw.upper
|
||||
lower' :: Maybe a <- deserialize raw.lower
|
||||
pure $ Range { upper: makeBound raw.upperIncl <$> upper', lower: makeBound raw.lowerIncl <$> lower' }
|
||||
|
||||
rangeToRaw :: forall a. Serialize a => Range a -> RepT RangeRawRecord
|
||||
rangeToRaw r = do
|
||||
upper' <- serialize $ boundValue <$> upper r
|
||||
lower' <- serialize $ boundValue <$> lower r
|
||||
pure $ { upper: upper', lower: lower', upperIncl: fromMaybe false $ boundIsInclusive <$> upper r, lowerIncl: fromMaybe false $ boundIsInclusive <$> lower r }
|
||||
|
||||
data Bound a = BoundIncl a | BoundExcl a
|
||||
|
||||
derive instance Generic (Bound a) _
|
||||
derive instance Eq a => Eq (Bound a)
|
||||
instance Show a => Show (Bound a) where
|
||||
show = genericShow
|
||||
|
||||
boundValue :: forall a. Bound a -> a
|
||||
boundValue (BoundIncl a) = a
|
||||
boundValue (BoundExcl a) = a
|
||||
|
||||
boundIsInclusive :: forall a. Bound a -> Boolean
|
||||
boundIsInclusive (BoundIncl _) = true
|
||||
boundIsInclusive (BoundExcl _) = false
|
||||
|
||||
upper :: forall a. Range a -> Maybe (Bound a)
|
||||
upper = _.upper <<< unwrap
|
||||
|
||||
lower :: forall a. Range a -> Maybe (Bound a)
|
||||
lower = _.lower <<< unwrap
|
||||
|
||||
makeBound :: forall a. Boolean -> a -> Bound a
|
||||
makeBound i a
|
||||
| i = BoundIncl a
|
||||
| otherwise = BoundExcl a
|
||||
|
||||
newtype Range a = Range { upper :: Maybe (Bound a), lower :: Maybe (Bound a) }
|
||||
|
||||
derive instance Generic (Range a) _
|
||||
derive instance Newtype (Range a) _
|
||||
derive instance Eq a => Eq (Range a)
|
||||
instance Show a => Show (Range a) where
|
||||
show = genericShow
|
||||
|
||||
instance (Ord a, Rep a) => Serialize (Range a) where
|
||||
serialize a = do
|
||||
raw <- rangeToRaw a
|
||||
pure $ Raw.unsafeFromForeign $ unsafeToForeign $ rangeRawFromRecord raw
|
||||
|
||||
instance (Ord a, Rep a) => Deserialize (Range a) where
|
||||
deserialize raw = do
|
||||
range :: RangeRaw <- lift $ readRangeRaw raw
|
||||
rangeFromRaw $ rangeRawToRecord range
|
||||
|
||||
instance Monoid (Range a) where
|
||||
mempty = Range { upper: Nothing, lower: Nothing }
|
||||
|
||||
instance Semigroup (Range a) where
|
||||
append (Range { upper: au, lower: al }) (Range { upper: bu, lower: bl }) = Range ({ upper: bu <|> au, lower: bl <|> al })
|
||||
|
||||
parseSQL :: forall a. Rep a => (String -> RepT a) -> String -> RepT (Range a)
|
||||
parseSQL fromString sql = do
|
||||
range <- lift $ rangeRawParse sql $ smash <<< (serialize <=< fromString)
|
||||
rangeFromRaw $ rangeRawToRecord range
|
||||
|
||||
printSQL :: forall a. Rep a => Range a -> RepT String
|
||||
printSQL range = do
|
||||
record <- rangeToRaw range
|
||||
lift $ rangeRawSerialize $ rangeRawFromRecord record
|
||||
|
||||
contains :: forall a. Ord a => a -> Range a -> Boolean
|
||||
contains a r =
|
||||
let
|
||||
upperOk
|
||||
| Just (BoundIncl u) <- upper r = u >= a
|
||||
| Just (BoundExcl u) <- upper r = u > a
|
||||
| otherwise = true
|
||||
lowerOk
|
||||
| Just (BoundIncl u) <- lower r = u <= a
|
||||
| Just (BoundExcl u) <- lower r = u < a
|
||||
| otherwise = true
|
||||
in
|
||||
upperOk && lowerOk
|
||||
|
||||
gte :: forall a. Ord a => a -> Range a
|
||||
gte a = Range { upper: Just $ BoundIncl a, lower: Nothing }
|
||||
|
||||
gt :: forall a. Ord a => a -> Range a
|
||||
gt a = Range { upper: Just $ BoundExcl a, lower: Nothing }
|
||||
|
||||
lt :: forall a. Ord a => a -> Range a
|
||||
lt a = Range { upper: Nothing, lower: Just $ BoundExcl a }
|
||||
|
||||
lte :: forall a. Ord a => a -> Range a
|
||||
lte a = Range { upper: Nothing, lower: Just $ BoundIncl a }
|
30
src/Data.Postgres.Raw.js
Normal file
30
src/Data.Postgres.Raw.js
Normal file
@ -0,0 +1,30 @@
|
||||
/** @type {(raw: unknown) => string} */
|
||||
export const rawToString = raw =>
|
||||
typeof raw === 'undefined'
|
||||
? 'undefined'
|
||||
: typeof raw === 'string'
|
||||
? raw
|
||||
: typeof raw === 'number' ||
|
||||
typeof raw === 'boolean' ||
|
||||
typeof raw === 'symbol'
|
||||
? raw.toString()
|
||||
: typeof raw === 'object'
|
||||
? raw === null
|
||||
? 'null'
|
||||
: `[${raw.constructor.name}]`
|
||||
: 'unknown'
|
||||
|
||||
/** @type {(a: unknown) => (b: unknown) => boolean} */
|
||||
export const rawEq = a => b =>
|
||||
typeof a === 'undefined' && typeof b === 'undefined'
|
||||
? true
|
||||
: typeof a === typeof b &&
|
||||
['number', 'boolean', 'symbol', 'string'].includes(typeof a)
|
||||
? a === b
|
||||
: typeof a === 'object' && typeof b === 'object'
|
||||
? a === null && b === null
|
||||
? true
|
||||
: a instanceof Array && b instanceof Array
|
||||
? a.every((a_, ix) => rawEq(a_)(b[ix]))
|
||||
: false
|
||||
: false
|
22
src/Data.Postgres.Raw.purs
Normal file
22
src/Data.Postgres.Raw.purs
Normal file
@ -0,0 +1,22 @@
|
||||
module Data.Postgres.Raw where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Foreign (Foreign)
|
||||
import Unsafe.Coerce (unsafeCoerce)
|
||||
|
||||
foreign import data Raw :: Type
|
||||
foreign import rawToString :: Raw -> String
|
||||
foreign import rawEq :: Raw -> Raw -> Boolean
|
||||
|
||||
instance Show Raw where
|
||||
show = rawToString
|
||||
|
||||
instance Eq Raw where
|
||||
eq = rawEq
|
||||
|
||||
unsafeFromForeign :: Foreign -> Raw
|
||||
unsafeFromForeign = unsafeCoerce
|
||||
|
||||
unsafeToForeign :: Raw -> Foreign
|
||||
unsafeToForeign = unsafeCoerce
|
37
src/Data.Postgres.js
Normal file
37
src/Data.Postgres.js
Normal file
@ -0,0 +1,37 @@
|
||||
import { getTypeParser, setTypeParser } from 'pg-types'
|
||||
import * as Range from 'postgres-range'
|
||||
|
||||
export const null_ = null
|
||||
|
||||
export const modifyPgTypes = () => {
|
||||
const oid = {
|
||||
'text[]': 1009,
|
||||
json: 114,
|
||||
jsonb: 3802,
|
||||
'json[]': 199,
|
||||
'jsonb[]': 3807,
|
||||
timestamp: 1114,
|
||||
timestamptz: 1184,
|
||||
'timestamp[]': 1115,
|
||||
'timestamptz[]': 1185,
|
||||
tsrange: 3908,
|
||||
tstzrange: 3910,
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const asString = a => a
|
||||
const asStringArray = getTypeParser(oid['text[]'])
|
||||
const asStringRange = Range.parse
|
||||
|
||||
setTypeParser(oid['json'], asString)
|
||||
setTypeParser(oid['jsonb'], asString)
|
||||
setTypeParser(oid['json[]'], asStringArray)
|
||||
setTypeParser(oid['jsonb[]'], asStringArray)
|
||||
|
||||
setTypeParser(oid['timestamp'], asString)
|
||||
setTypeParser(oid['timestamptz'], asString)
|
||||
setTypeParser(oid['timestamp[]'], asStringArray)
|
||||
setTypeParser(oid['timestamptz[]'], asStringArray)
|
||||
setTypeParser(oid['tsrange'], asStringRange)
|
||||
setTypeParser(oid['tstzrange'], asStringRange)
|
||||
}
|
167
src/Data.Postgres.purs
Normal file
167
src/Data.Postgres.purs
Normal file
@ -0,0 +1,167 @@
|
||||
module Data.Postgres where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Control.Alt ((<|>))
|
||||
import Control.Monad.Error.Class (liftEither, liftMaybe)
|
||||
import Control.Monad.Except (Except, ExceptT, except, runExcept, runExceptT, withExceptT)
|
||||
import Data.Bifunctor (lmap)
|
||||
import Data.DateTime (DateTime)
|
||||
import Data.Generic.Rep (class Generic)
|
||||
import Data.List.NonEmpty (NonEmptyList)
|
||||
import Data.Maybe (Maybe(..))
|
||||
import Data.Newtype (unwrap, wrap)
|
||||
import Data.Postgres.Raw (Raw)
|
||||
import Data.Postgres.Raw (unsafeFromForeign, unsafeToForeign) as Raw
|
||||
import Data.RFC3339String as DateTime.ISO
|
||||
import Data.Show.Generic (genericShow)
|
||||
import Data.Traversable (traverse)
|
||||
import Effect (Effect)
|
||||
import Effect.Exception (error)
|
||||
import Foreign (ForeignError)
|
||||
import Foreign as F
|
||||
import Node.Buffer (Buffer)
|
||||
|
||||
newtype JSON = JSON String
|
||||
|
||||
foreign import null_ :: Raw
|
||||
|
||||
-- | Important! This effect MUST be evaluated to guarantee
|
||||
-- | that (de)serialization will work for timestamp and JSON types.
|
||||
-- |
|
||||
-- | This mutates the `pg-types`, overriding the default deserialization
|
||||
-- | behavior for JSON and timestamp types.
|
||||
foreign import modifyPgTypes :: Effect Unit
|
||||
|
||||
-- | The SQL value NULL
|
||||
data Null = Null
|
||||
|
||||
derive instance Generic Null _
|
||||
derive instance Eq Null
|
||||
derive instance Ord Null
|
||||
instance Show Null where
|
||||
show = genericShow
|
||||
|
||||
-- | The serialization & deserialization monad.
|
||||
type RepT a = ExceptT RepError Effect a
|
||||
|
||||
-- | Errors encounterable while serializing & deserializing.
|
||||
data RepError
|
||||
= RepErrorTypeMismatch { expected :: String, found :: String }
|
||||
| RepErrorInvalid String
|
||||
| RepErrorForeign ForeignError
|
||||
| RepErrorOther String
|
||||
| RepErrorMultiple (NonEmptyList RepError)
|
||||
|
||||
derive instance Generic RepError _
|
||||
derive instance Eq RepError
|
||||
instance Show RepError where
|
||||
show a = genericShow a
|
||||
|
||||
instance Semigroup RepError where
|
||||
append (RepErrorMultiple as) (RepErrorMultiple bs) = RepErrorMultiple (as <> bs)
|
||||
append (RepErrorMultiple as) b = RepErrorMultiple (as <> pure b)
|
||||
append a (RepErrorMultiple bs) = RepErrorMultiple (pure a <> bs)
|
||||
append a b = RepErrorMultiple (pure a <> pure b)
|
||||
|
||||
-- | Flatten to an Effect, rendering any `RepError`s to `String` using `Show`.
|
||||
smash :: forall a. RepT a -> Effect a
|
||||
smash = liftEither <=< map (lmap (error <<< show)) <<< runExceptT
|
||||
|
||||
-- | Lift an `Except` returned by functions in the `Foreign` module to `RepT`
|
||||
liftForeign :: forall a. Except (NonEmptyList ForeignError) a -> RepT a
|
||||
liftForeign = except <<< runExcept <<< withExceptT (RepErrorMultiple <<< map RepErrorForeign)
|
||||
|
||||
-- | Serialize data of type `a` to a `Raw` SQL value.
|
||||
class Serialize a where
|
||||
serialize :: a -> RepT Raw
|
||||
|
||||
-- | Deserialize data of type `a` from a `Raw` SQL value.
|
||||
class Deserialize a where
|
||||
deserialize :: Raw -> RepT a
|
||||
|
||||
-- | A type which is `Rep`resentable as a SQL value.
|
||||
class (Serialize a, Deserialize a) <= Rep a
|
||||
|
||||
instance (Serialize a, Deserialize a) => Rep a
|
||||
|
||||
-- | Coerces the value to `Raw`
|
||||
unsafeSerializeCoerce :: forall m a. Monad m => a -> m Raw
|
||||
unsafeSerializeCoerce = pure <<< Raw.unsafeFromForeign <<< F.unsafeToForeign
|
||||
|
||||
instance Serialize Raw where
|
||||
serialize = pure
|
||||
|
||||
instance Serialize Null where
|
||||
serialize _ = unsafeSerializeCoerce null_
|
||||
|
||||
-- | `bytea`
|
||||
instance Serialize Buffer where
|
||||
serialize = unsafeSerializeCoerce
|
||||
|
||||
instance Serialize Int where
|
||||
serialize = unsafeSerializeCoerce
|
||||
|
||||
instance Serialize Boolean where
|
||||
serialize = unsafeSerializeCoerce
|
||||
|
||||
instance Serialize String where
|
||||
serialize = unsafeSerializeCoerce
|
||||
|
||||
instance Serialize Number where
|
||||
serialize = unsafeSerializeCoerce
|
||||
|
||||
instance Serialize Char where
|
||||
serialize = unsafeSerializeCoerce
|
||||
|
||||
instance Serialize DateTime where
|
||||
serialize = serialize <<< unwrap <<< DateTime.ISO.fromDateTime
|
||||
|
||||
instance Serialize a => Serialize (Maybe a) where
|
||||
serialize (Just a) = serialize a
|
||||
serialize Nothing = unsafeSerializeCoerce null_
|
||||
|
||||
instance Serialize a => Serialize (Array a) where
|
||||
serialize = unsafeSerializeCoerce <=< traverse serialize
|
||||
|
||||
instance Deserialize Raw where
|
||||
deserialize = pure
|
||||
|
||||
-- | `bytea`
|
||||
instance Deserialize Buffer where
|
||||
deserialize = liftForeign <<< (F.unsafeReadTagged "Buffer") <<< Raw.unsafeToForeign
|
||||
|
||||
instance Deserialize Null where
|
||||
deserialize = map (const Null) <<< liftForeign <<< F.readNullOrUndefined <<< Raw.unsafeToForeign
|
||||
|
||||
instance Deserialize Int where
|
||||
deserialize = liftForeign <<< F.readInt <<< Raw.unsafeToForeign
|
||||
|
||||
instance Deserialize Boolean where
|
||||
deserialize = liftForeign <<< F.readBoolean <<< Raw.unsafeToForeign
|
||||
|
||||
instance Deserialize String where
|
||||
deserialize = liftForeign <<< F.readString <<< Raw.unsafeToForeign
|
||||
|
||||
instance Deserialize Number where
|
||||
deserialize = liftForeign <<< F.readNumber <<< Raw.unsafeToForeign
|
||||
|
||||
instance Deserialize Char where
|
||||
deserialize = liftForeign <<< F.readChar <<< Raw.unsafeToForeign
|
||||
|
||||
instance Deserialize DateTime where
|
||||
deserialize raw = do
|
||||
s :: String <- deserialize raw
|
||||
let invalid = RepErrorInvalid $ "Not a valid ISO8601 string: `" <> s <> "`"
|
||||
liftMaybe invalid $ DateTime.ISO.toDateTime $ wrap s
|
||||
|
||||
instance Deserialize a => Deserialize (Array a) where
|
||||
deserialize = traverse (deserialize <<< Raw.unsafeFromForeign) <=< liftForeign <<< F.readArray <<< Raw.unsafeToForeign
|
||||
|
||||
instance Deserialize a => Deserialize (Maybe a) where
|
||||
deserialize raw =
|
||||
let
|
||||
nothing = const Nothing <$> deserialize @Null raw
|
||||
just = Just <$> deserialize raw
|
||||
in
|
||||
just <|> nothing
|
4
src/Effect.Postgres.purs
Normal file
4
src/Effect.Postgres.purs
Normal file
@ -0,0 +1,4 @@
|
||||
module Effect.Pg where
|
||||
|
||||
import Prelude
|
||||
|
@ -1,7 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import Prelude
|
||||
import Effect (Effect)
|
||||
|
||||
main :: Effect Unit
|
||||
main = pure unit
|
74
test/Test.Data.Postgres.purs
Normal file
74
test/Test.Data.Postgres.purs
Normal file
@ -0,0 +1,74 @@
|
||||
module Test.Data.Postgres where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Control.Monad.Error.Class (liftEither)
|
||||
import Control.Monad.Except (runExceptT)
|
||||
import Data.DateTime (DateTime(..))
|
||||
import Data.DateTime.Instant as Instant
|
||||
import Data.Int as Int
|
||||
import Data.Maybe (Maybe, fromJust, fromMaybe, maybe)
|
||||
import Data.Newtype (wrap)
|
||||
import Data.Postgres (class Rep, Null(..), deserialize, null_, serialize, smash)
|
||||
import Data.Postgres.Range as Range
|
||||
import Data.Postgres.Raw (Raw)
|
||||
import Data.Postgres.Raw as Raw
|
||||
import Data.RFC3339String as DateTime.ISO
|
||||
import Data.Tuple.Nested (type (/\), (/\))
|
||||
import Effect.Class (liftEffect)
|
||||
import Effect.Console (log)
|
||||
import Effect.Unsafe (unsafePerformEffect)
|
||||
import Foreign (unsafeToForeign)
|
||||
import Partial.Unsafe (unsafePartial)
|
||||
import Test.QuickCheck (class Arbitrary, (==?))
|
||||
import Test.Spec (Spec, describe, it)
|
||||
import Test.Spec.Assertions (shouldEqual)
|
||||
import Test.Spec.QuickCheck (quickCheck)
|
||||
|
||||
asRaw :: forall a. a -> Raw
|
||||
asRaw = Raw.unsafeFromForeign <<< unsafeToForeign
|
||||
|
||||
spec :: Spec Unit
|
||||
spec =
|
||||
let
|
||||
check :: forall @a @x. Eq a => Show a => Arbitrary x => Rep a => String -> (x -> a) -> (a -> Raw) -> Spec Unit
|
||||
check s xa asRaw_ =
|
||||
describe s do
|
||||
it "serialize" $ quickCheck \(x :: x) -> (unsafePerformEffect $ runExceptT $ serialize $ xa x) ==? pure (asRaw_ $ xa x)
|
||||
it "deserialize" $ quickCheck \(x :: x) -> (unsafePerformEffect $ runExceptT $ deserialize $ asRaw_ $ xa x) ==? pure (xa x)
|
||||
|
||||
check_ :: forall @a. Eq a => Show a => Arbitrary a => Rep a => String -> Spec Unit
|
||||
check_ s = check @a @a s identity asRaw
|
||||
|
||||
dateTimeFromArbitrary :: Int -> DateTime
|
||||
dateTimeFromArbitrary = Instant.toDateTime <<< unsafePartial fromJust <<< Instant.instant <<< wrap <<< Int.toNumber
|
||||
in
|
||||
describe "Data.Postgres" do
|
||||
check_ @Int "Int"
|
||||
check_ @String "String"
|
||||
check_ @Boolean "Boolean"
|
||||
check_ @Number "Number"
|
||||
check_ @Char "Char"
|
||||
|
||||
check @(Maybe String) "Maybe String" identity (maybe null_ asRaw)
|
||||
check @(Array String) "Array String" identity asRaw
|
||||
check @DateTime "DateTime" dateTimeFromArbitrary (asRaw <<< DateTime.ISO.fromDateTime)
|
||||
|
||||
describe "Null" do
|
||||
it "serialize" $ liftEffect $ shouldEqual null_ =<< (smash $ serialize Null)
|
||||
it "deserialize" $ liftEffect $ shouldEqual Null =<< (smash $ deserialize null_)
|
||||
|
||||
describe "Range" do
|
||||
it "deserialize" do
|
||||
quickCheck \(up /\ lo /\ uinc /\ linc :: Int /\ Int /\ Boolean /\ Boolean) -> unsafePerformEffect do
|
||||
let
|
||||
record =
|
||||
{ upper: unsafePerformEffect $ smash $ serialize up
|
||||
, lower: unsafePerformEffect $ smash $ serialize lo
|
||||
, upperIncl: uinc
|
||||
, lowerIncl: linc
|
||||
}
|
||||
raw = asRaw $ Range.rangeRawFromRecord record
|
||||
exp :: Range.Range Int <- smash $ Range.rangeFromRaw record
|
||||
act :: Range.Range Int <- smash $ deserialize raw
|
||||
pure $ exp ==? act
|
13
test/Test.Main.purs
Normal file
13
test/Test.Main.purs
Normal file
@ -0,0 +1,13 @@
|
||||
module Test.Main where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Effect (Effect)
|
||||
import Effect.Aff (launchAff_)
|
||||
import Test.Data.Postgres as Test.Data.Postgres
|
||||
import Test.Spec.Reporter (consoleReporter)
|
||||
import Test.Spec.Runner (runSpec)
|
||||
|
||||
main :: Effect Unit
|
||||
main = launchAff_ $ runSpec [ consoleReporter ] do
|
||||
Test.Data.Postgres.spec
|
Loading…
Reference in New Issue
Block a user