From 753d14fdd91c2ed3d112b12b70757e0835c0a1d4 Mon Sep 17 00:00:00 2001 From: Orion Kindel Date: Wed, 27 Mar 2024 12:20:33 -0500 Subject: [PATCH] fix: JSON support --- .tool-versions | 2 +- bun.lockb | Bin 56385 -> 0 bytes package-lock.json | 202 +++++++++++++++++++++++++++++++++++ package.json | 9 +- spago.lock | 58 ++++++++++ spago.yaml | 3 + src/Data.Postgres.js | 24 ++--- src/Data.Postgres.purs | 74 ++++++------- test/Test.Data.Postgres.purs | 21 +++- 9 files changed, 329 insertions(+), 64 deletions(-) delete mode 100755 bun.lockb create mode 100644 package-lock.json diff --git a/.tool-versions b/.tool-versions index 11affa2..4e03911 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -bun 1.0.35 +bun 1.0.11 purescript 0.15.15 diff --git a/bun.lockb b/bun.lockb deleted file mode 100755 index 8179e335b409e2e7eb6b791248bdb8b0f84b11c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56385 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" + } + }, + "node_modules/bun-types": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.0.11.tgz", + "integrity": "sha512-XaDwjnBlkdTOtBEAcXhDnPSKFMlwFK/526z0iyairYIDhZJMzZM1QU4D7XRiEI2SpKQWexn0S/LN9Mwx5xSJNg==", + "dev": true + }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, + "node_modules/pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-range": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", + "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", + "peer": true + }, + "node_modules/purs-tidy": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/purs-tidy/-/purs-tidy-0.10.1.tgz", + "integrity": "sha512-i1QvMaDEaZXv/GWZNFWs5CISiBOkwPhG4D1S4Rw6zUCGaE+NQNWTjvwY21rifynGa2N2TiBJRC61LkORbmGxrA==", + "dev": true, + "bin": { + "purs-tidy": "bin/index.js" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/typescript": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", + "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + } + } +} diff --git a/package.json b/package.json index c21954b..cae51fa 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,11 @@ }, "devDependencies": { "bun-types": "1.0.11", - "postgres-range": "^1.1.4", "purs-tidy": "^0.10.0", - "spago": "next" - }, - "peerDependencies": { "typescript": "^5.0.0" }, - "dependencies": { "pg-types": "^4.0.2" } + "dependencies": { + "postgres-range": "^1.1.4", + "pg": "^8.11.3" + } } diff --git a/spago.lock b/spago.lock index 1b9e047..d50ce4f 100644 --- a/spago.lock +++ b/spago.lock @@ -12,13 +12,16 @@ workspace: - foreign - lists - maybe + - mmorph - newtype - node-buffer - precise-datetime - prelude + - simple-json - transformers - unsafe-coerce test_dependencies: + - foreign-object - quickcheck - spec - spec-quickcheck @@ -45,6 +48,7 @@ workspace: - fixed-points - foldable-traversable - foreign + - foreign-object - fork - formatters - free @@ -80,6 +84,7 @@ workspace: - record - refs - safe-coerce + - simple-json - spec - spec-quickcheck - st @@ -88,9 +93,11 @@ workspace: - transformers - tuples - type-equality + - typelevel-prelude - unfoldable - unicode - unsafe-coerce + - variant extra_packages: {} packages: aff: @@ -333,6 +340,23 @@ packages: - prelude - strings - transformers + foreign-object: + type: registry + version: 4.1.0 + integrity: sha256-q24okj6mT+yGHYQ+ei/pYPj5ih6sTbu7eDv/WU56JVo= + dependencies: + - arrays + - foldable-traversable + - functions + - gen + - lists + - maybe + - prelude + - st + - tailrec + - tuples + - typelevel-prelude + - unfoldable fork: type: registry version: 6.0.0 @@ -735,6 +759,20 @@ packages: integrity: sha256-a1ibQkiUcbODbLE/WAq7Ttbbh9ex+x33VCQ7GngKudU= dependencies: - unsafe-coerce + simple-json: + type: registry + version: 9.0.0 + integrity: sha256-K3RJaThqsszTd+TEklzZmAdDqvIHWgXIfKqlsoykU1c= + dependencies: + - arrays + - exceptions + - foreign + - foreign-object + - nullable + - prelude + - record + - typelevel-prelude + - variant spec: type: registry version: 7.6.0 @@ -852,6 +890,13 @@ packages: version: 4.0.1 integrity: sha256-Hs9D6Y71zFi/b+qu5NSbuadUQXe5iv5iWx0226vOHUw= dependencies: [] + typelevel-prelude: + type: registry + version: 7.0.0 + integrity: sha256-uFF2ph+vHcQpfPuPf2a3ukJDFmLhApmkpTMviHIWgJM= + dependencies: + - prelude + - type-equality unfoldable: type: registry version: 6.0.0 @@ -875,3 +920,16 @@ packages: version: 6.0.0 integrity: sha256-IqIYW4Vkevn8sI+6aUwRGvd87tVL36BBeOr0cGAE7t0= dependencies: [] + variant: + type: registry + version: 8.0.0 + integrity: sha256-SR//zQDg2dnbB8ZHslcxieUkCeNlbMToapvmh9onTtw= + dependencies: + - enums + - lists + - maybe + - partial + - prelude + - record + - tuples + - unsafe-coerce diff --git a/spago.yaml b/spago.yaml index c7cd20c..6ecf5b9 100644 --- a/spago.yaml +++ b/spago.yaml @@ -13,15 +13,18 @@ package: - foreign - lists - maybe + - mmorph - newtype - node-buffer - precise-datetime - prelude + - simple-json - transformers - unsafe-coerce test: main: Test.Main dependencies: + - foreign-object - quickcheck - spec - spec-quickcheck diff --git a/src/Data.Postgres.js b/src/Data.Postgres.js index a833d11..58bb6f0 100644 --- a/src/Data.Postgres.js +++ b/src/Data.Postgres.js @@ -1,4 +1,4 @@ -import { getTypeParser, setTypeParser } from 'pg-types' +import * as Pg from 'pg' import * as Range from 'postgres-range' export const null_ = null @@ -20,18 +20,18 @@ export const modifyPgTypes = () => { // @ts-ignore const asString = a => a - const asStringArray = getTypeParser(oid['text[]']) + const asStringArray = Pg.types.getTypeParser(oid['text[]']) const asStringRange = Range.parse - setTypeParser(oid['json'], asString) - setTypeParser(oid['jsonb'], asString) - setTypeParser(oid['json[]'], asStringArray) - setTypeParser(oid['jsonb[]'], asStringArray) + Pg.types.setTypeParser(oid['json'], asString) + Pg.types.setTypeParser(oid['jsonb'], asString) + Pg.types.setTypeParser(oid['json[]'], asStringArray) + Pg.types.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) + Pg.types.setTypeParser(oid['timestamp'], asString) + Pg.types.setTypeParser(oid['timestamptz'], asString) + Pg.types.setTypeParser(oid['timestamp[]'], asStringArray) + Pg.types.setTypeParser(oid['timestamptz[]'], asStringArray) + Pg.types.setTypeParser(oid['tsrange'], asStringRange) + Pg.types.setTypeParser(oid['tstzrange'], asStringRange) } diff --git a/src/Data.Postgres.purs b/src/Data.Postgres.purs index 75e9fbc..1ddf643 100644 --- a/src/Data.Postgres.purs +++ b/src/Data.Postgres.purs @@ -4,13 +4,14 @@ import Prelude import Control.Alt ((<|>)) import Control.Monad.Error.Class (liftEither, liftMaybe) -import Control.Monad.Except (Except, ExceptT, except, runExcept, runExceptT, withExceptT) +import Control.Monad.Except (ExceptT, runExceptT) +import Control.Monad.Morph (hoist) 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.Newtype (class Newtype, unwrap, wrap) import Data.Postgres.Raw (Raw) import Data.Postgres.Raw (unsafeFromForeign, unsafeToForeign) as Raw import Data.RFC3339String as DateTime.ISO @@ -18,19 +19,21 @@ import Data.Show.Generic (genericShow) import Data.Traversable (traverse) import Effect (Effect) import Effect.Exception (error) -import Foreign (ForeignError) +import Foreign (ForeignError(..)) import Foreign as F import Node.Buffer (Buffer) +import Simple.JSON (class ReadForeign, class WriteForeign, readJSON', writeJSON) -newtype JSON = JSON String +newtype JSON a = JSON a + +derive instance Newtype (JSON a) _ +derive newtype instance WriteForeign a => WriteForeign (JSON a) +derive newtype instance ReadForeign a => ReadForeign (JSON a) 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. +-- | This mutates `import('pg').types`, setting deserialization +-- | for some types to unmarshal as strings rather than JS values. foreign import modifyPgTypes :: Effect Unit -- | The SQL value NULL @@ -43,35 +46,12 @@ 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) +type RepT a = ExceptT (NonEmptyList ForeignError) Effect a -- | 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 @@ -95,6 +75,9 @@ instance Serialize Raw where instance Serialize Null where serialize _ = unsafeSerializeCoerce null_ +instance WriteForeign a => Serialize (JSON a) where + serialize = serialize <<< writeJSON <<< unwrap + -- | `bytea` instance Serialize Buffer where serialize = unsafeSerializeCoerce @@ -127,36 +110,39 @@ instance Serialize a => Serialize (Array a) where instance Deserialize Raw where deserialize = pure +instance Deserialize Null where + deserialize = map (const Null) <<< F.readNullOrUndefined <<< Raw.unsafeToForeign + +instance ReadForeign a => Deserialize (JSON a) where + deserialize = map wrap <<< (hoist (pure <<< unwrap) <<< readJSON') <=< deserialize @String + -- | `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 + deserialize = (F.unsafeReadTagged "Buffer") <<< Raw.unsafeToForeign instance Deserialize Int where - deserialize = liftForeign <<< F.readInt <<< Raw.unsafeToForeign + deserialize = F.readInt <<< Raw.unsafeToForeign instance Deserialize Boolean where - deserialize = liftForeign <<< F.readBoolean <<< Raw.unsafeToForeign + deserialize = F.readBoolean <<< Raw.unsafeToForeign instance Deserialize String where - deserialize = liftForeign <<< F.readString <<< Raw.unsafeToForeign + deserialize = F.readString <<< Raw.unsafeToForeign instance Deserialize Number where - deserialize = liftForeign <<< F.readNumber <<< Raw.unsafeToForeign + deserialize = F.readNumber <<< Raw.unsafeToForeign instance Deserialize Char where - deserialize = liftForeign <<< F.readChar <<< Raw.unsafeToForeign + deserialize = F.readChar <<< Raw.unsafeToForeign instance Deserialize DateTime where deserialize raw = do s :: String <- deserialize raw - let invalid = RepErrorInvalid $ "Not a valid ISO8601 string: `" <> s <> "`" + let invalid = pure $ ForeignError $ "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 + deserialize = traverse (deserialize <<< Raw.unsafeFromForeign) <=< F.readArray <<< Raw.unsafeToForeign instance Deserialize a => Deserialize (Maybe a) where deserialize raw = diff --git a/test/Test.Data.Postgres.purs b/test/Test.Data.Postgres.purs index 2a1858f..5a0a36f 100644 --- a/test/Test.Data.Postgres.purs +++ b/test/Test.Data.Postgres.purs @@ -8,8 +8,8 @@ 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.Newtype (unwrap, wrap) +import Data.Postgres (class Rep, JSON(..), Null(..), deserialize, null_, serialize, smash) import Data.Postgres.Range as Range import Data.Postgres.Raw (Raw) import Data.Postgres.Raw as Raw @@ -19,7 +19,9 @@ import Effect.Class (liftEffect) import Effect.Console (log) import Effect.Unsafe (unsafePerformEffect) import Foreign (unsafeToForeign) +import Foreign.Object as Object import Partial.Unsafe (unsafePartial) +import Simple.JSON (writeImpl, writeJSON) import Test.QuickCheck (class Arbitrary, (==?)) import Test.Spec (Spec, describe, it) import Test.Spec.Assertions (shouldEqual) @@ -54,6 +56,21 @@ spec = check @(Array String) "Array String" identity asRaw check @DateTime "DateTime" dateTimeFromArbitrary (asRaw <<< DateTime.ISO.fromDateTime) + describe "JSON" do + describe "Record" do + it "deserialize" $ + quickCheck \(a /\ b /\ c :: Int /\ String /\ Array {"foo" :: String}) -> unsafePerformEffect do + let + obj = {a, b, c} + json = writeJSON obj + act :: JSON _ <- smash $ deserialize $ asRaw json + pure $ obj ==? unwrap act + it "serialize" $ + quickCheck \(a /\ b /\ c :: Int /\ String /\ Array {"foo" :: String}) -> unsafePerformEffect do + let obj = {a, b, c} + act <- smash $ serialize $ JSON obj + pure $ asRaw (writeJSON obj) ==? act + describe "Null" do it "serialize" $ liftEffect $ shouldEqual null_ =<< (smash $ serialize Null) it "deserialize" $ liftEffect $ shouldEqual Null =<< (smash $ deserialize null_)