Skip to content

Commit 4b85ac3

Browse files
committed
Record codec from record of codecs
1 parent e7270d2 commit 4b85ac3

File tree

4 files changed

+128
-1
lines changed

4 files changed

+128
-1
lines changed

bower.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
"purescript-argonaut-core": "^3.1.0",
2020
"purescript-codec": "^2.0.0",
2121
"purescript-generics-rep": "^5.1.0",
22-
"purescript-variant": "^1.1.0"
22+
"purescript-variant": "^1.1.0",
23+
"purescript-typelevel-prelude": "^2.4.0",
24+
"purescript-record": "^0.2.0",
25+
"purescript-type-equality": "^2.1.0"
2326
},
2427
"devDependencies": {
2528
"purescript-argonaut-codecs": "^3.1.0",

src/Data/Codec/Argonaut/Record.purs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
module Data.Codec.Argonaut.Record
2+
( class RowListCodec
3+
, rowListCodec
4+
, record
5+
) where
6+
7+
import Data.Codec.Argonaut as CA
8+
import Data.Record as Rec
9+
import Data.Symbol (class IsSymbol, SProxy(..))
10+
import Type.Equality as TE
11+
import Type.Row as R
12+
import Unsafe.Coerce (unsafeCoerce)
13+
14+
class RowListCodec (rlR.RowList) (ri ∷ # Type) (ro ∷ # Type) | rl ri ro where
15+
rowListCodec R.RLProxy rl Record ri CA.JPropCodec (Record ro)
16+
17+
instance rowListCodecNilRowListCodec R.Nil () () where
18+
rowListCodec _ _ = CA.record
19+
20+
instance rowListCodecCons
21+
( RowListCodec rs ri' ro'
22+
, RowCons sym (CA.JsonCodec a) ri' ri
23+
, RowCons sym a ro' ro
24+
, IsSymbol sym
25+
, TE.TypeEquals co (CA.JsonCodec a)
26+
) RowListCodec (R.Cons sym co rs) ri ro where
27+
rowListCodec _ codecs =
28+
CA.recordProp (SProxy SProxy sym) codec tail
29+
where
30+
codec CA.JsonCodec a
31+
codec = TE.from (Rec.get (SProxy SProxy sym) codecs)
32+
33+
tail CA.JPropCodec (Record ro')
34+
tail = rowListCodec (R.RLProxy R.RLProxy rs) ((unsafeCoerce Record ri Record ri') codecs)
35+
36+
-- | Constructs a record codec from a record of codecs.
37+
record
38+
ri ro rl
39+
. R.RowToList ri rl
40+
RowListCodec rl ri ro
41+
Record ri
42+
CA.JPropCodec (Record ro)
43+
record = rowListCodec (R.RLProxy R.RLProxy rl)

test/Test/Main.purs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Test.Migration as Migration
99
import Test.Prim as Prim
1010
import Test.QuickCheck (QC)
1111
import Test.Variant as Variant
12+
import Test.Record as Record
1213

1314
main :: QC () Unit
1415
main = do
@@ -28,6 +29,10 @@ main = do
2829
log "------------------------------------------------------------"
2930
Variant.main
3031
log ""
32+
log "Checking Record codecs"
33+
log "------------------------------------------------------------"
34+
Record.main
35+
log ""
3136
log "Checking Migration codecs"
3237
log "------------------------------------------------------------"
3338
Migration.main

test/Test/Record.purs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
module Test.Record where
2+
3+
import Prelude
4+
5+
import Control.Monad.Eff.Console (log)
6+
import Control.Monad.Gen as Gen
7+
import Control.Monad.Gen.Common as GenC
8+
import Data.Codec.Argonaut.Common as JA
9+
import Data.Codec.Argonaut.Record as JAR
10+
import Data.Maybe (Maybe(..))
11+
import Data.Newtype (class Newtype, unwrap, wrap)
12+
import Data.Profunctor (dimap)
13+
import Data.String.Gen (genAsciiString)
14+
import Test.QuickCheck (QC, quickCheck)
15+
import Test.QuickCheck.Gen (Gen)
16+
import Test.Util (genInt, propCodec)
17+
18+
type OuterR =
19+
{ a Int
20+
, b String
21+
, c Maybe InnerR
22+
}
23+
24+
type InnerR =
25+
{ n Int
26+
, m Boolean
27+
}
28+
29+
newtype Outer = Outer OuterR
30+
31+
derive instance newtypeOuterNewtype Outer _
32+
33+
instance showOuterShow Outer where
34+
show (Outer r) = "Outer " <> show (JA.encode outerCodec r)
35+
36+
instance eqOuterEq Outer where
37+
eq (Outer o1) (Outer o2) =
38+
o1.a == o2.a
39+
&& o1.b == o2.b
40+
&& case o1.c, o2.c of
41+
Nothing, Nothingtrue
42+
Just i1, Just i2 → i1.n == i2.n && i1.m == i2.m
43+
_, _ → false
44+
45+
outerCodec JA.JsonCodec OuterR
46+
outerCodec =
47+
JA.object "Outer" $ JAR.record
48+
{ a: JA.int
49+
, b: JA.string
50+
, c: JA.maybe innerCodec
51+
}
52+
53+
innerCodec JA.JsonCodec InnerR
54+
innerCodec =
55+
JA.object "Inner" $ JAR.record
56+
{ n: JA.int
57+
, m: JA.boolean
58+
}
59+
60+
genOuter Gen OuterR
61+
genOuter = do
62+
a ← genInt
63+
b ← genAsciiString
64+
c ← GenC.genMaybe genInner
65+
pure { a, b, c }
66+
67+
genInner Gen InnerR
68+
genInner = do
69+
n ← genInt
70+
m ← Gen.chooseBool
71+
pure { n, m }
72+
73+
main QC () Unit
74+
main = do
75+
log "Checking record codec"
76+
quickCheck $ propCodec (Outer <$> genOuter) (dimap unwrap wrap outerCodec)

0 commit comments

Comments
 (0)