Skip to content

Commit 4e864ba

Browse files
authored
Override existing fields with Record.Builder.merge and union (#73)
1 parent 4bf2f06 commit 4e864ba

File tree

2 files changed

+55
-14
lines changed

2 files changed

+55
-14
lines changed

src/Record/Builder.purs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module Record.Builder
22
( Builder
33
, build
44
, buildFromScratch
5+
, flip
56
, insert
67
, modify
78
, delete
@@ -12,8 +13,9 @@ module Record.Builder
1213
, nub
1314
) where
1415

15-
import Prelude
16+
import Prelude hiding (flip)
1617

18+
import Data.Function (flip) as Function
1719
import Data.Function.Uncurried (runFn2)
1820
import Data.Symbol (class IsSymbol, reflectSymbol)
1921
import Prim.Row as Row
@@ -48,7 +50,11 @@ build (Builder b) r1 = b (copyRecord r1)
4850

4951
-- | Build a record from scratch.
5052
buildFromScratch :: forall r. Builder (Record ()) (Record r) -> Record r
51-
buildFromScratch = flip build {}
53+
buildFromScratch = Function.flip build {}
54+
55+
-- | Flip a function of one argument returning a builder.
56+
flip :: forall r1 r2 r3. (Record r1 -> Builder (Record r2) (Record r3)) -> Record r2 -> Builder (Record r1) (Record r3)
57+
flip f b = Builder \a -> build (f a) b
5258

5359
derive newtype instance semigroupoidBuilder :: Semigroupoid Builder
5460
derive newtype instance categoryBuilder :: Category Builder
@@ -98,25 +104,40 @@ rename :: forall proxy l1 l2 a r1 r2 r3
98104
-> Builder (Record r1) (Record r3)
99105
rename l1 l2 = Builder \r1 -> unsafeRename (reflectSymbol l1) (reflectSymbol l2) r1
100106

101-
-- | Build by merging existing fields from another record.
107+
-- | Build by merging existing fields from another record, taking precedence
108+
-- | in the case of overlaps.
109+
-- |
110+
-- | For example:
111+
-- |
112+
-- | ```purescript
113+
-- | build (merge { x: 1, y: "y" }) { y: 2, z: true }
114+
-- | :: { x :: Int, y :: String, z :: Boolean }
115+
-- | ```
102116
merge
103117
:: forall r1 r2 r3 r4
104118
. Row.Union r1 r2 r3
105119
=> Row.Nub r3 r4
106-
=> Record r2
107-
-> Builder (Record r1) (Record r4)
108-
merge r2 = Builder \r1 -> runFn2 unsafeUnionFn r1 r2
109-
110-
-- | Build by merging existing fields from another record. Unlike `merge`,
111-
-- | this does not remove duplicate labels from the resulting record type.
112-
-- | This can result in better inference for some pipelines, deferring the
113-
-- | need for a `Nub` constraint.
120+
=> Record r1
121+
-> Builder (Record r2) (Record r4)
122+
merge r1 = Builder \r2 -> runFn2 unsafeUnionFn r1 r2
123+
124+
-- | Build by merging existing fields from another record, taking precedence
125+
-- | in the case of overlaps. Unlike `merge`, this does not remove duplicate
126+
-- | labels from the resulting record type. This can result in better inference
127+
-- | for some pipelines, deferring the need for a `Nub` constraint.
128+
-- |
129+
-- | For example:
130+
-- |
131+
-- | ```purescript
132+
-- | build (union { x: 1, y: "y" }) { y: 2, z: true }
133+
-- | :: { x :: Int, y :: String, y :: Int, z :: Boolean }
134+
-- | ```
114135
union
115136
:: forall r1 r2 r3
116137
. Row.Union r1 r2 r3
117-
=> Record r2
118-
-> Builder (Record r1) (Record r3)
119-
union r2 = Builder \r1 -> runFn2 unsafeUnionFn r1 r2
138+
=> Record r1
139+
-> Builder (Record r2) (Record r3)
140+
union r1 = Builder \r2 -> runFn2 unsafeUnionFn r1 r2
120141

121142
-- | Build by merging some disjoint set of fields from another record.
122143
disjointUnion

test/Main.purs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,23 @@ main = do
6363

6464
assert' "Record.Builder" $
6565
testBuilder.x == "42" && testBuilder.y == "testing"
66+
67+
assert' "Record.Builder.merge" $
68+
let { x, y, z } = Builder.build (Builder.merge { x: 1, y: "y" }) { y: 2, z: true }
69+
:: { x :: Int, y :: String, z :: Boolean }
70+
in x == 1 && y == "y" && z
71+
72+
assert' "Record.Builder.union" $
73+
let { x, y, z } = Builder.build (Builder.union { x: 1, y: "y" }) { y: 2, z: true }
74+
:: { x :: Int, y :: String, y :: Int, z :: Boolean }
75+
in x == 1 && y == "y" && z
76+
77+
assert' "Record.Builder.flip merge" $
78+
let { x, y, z } = Builder.build (Builder.flip Builder.merge { x: 1, y: "y" }) { y: 2, z: true }
79+
:: { x :: Int, y :: Int, z :: Boolean }
80+
in x == 1 && y == 2 && z
81+
82+
assert' "Record.Builder.flip union" $
83+
let { x, y, z } = Builder.build (Builder.flip Builder.union { x: 1, y: "y" }) { y: 2, z: true }
84+
:: { x :: Int, y :: Int, y :: String, z :: Boolean }
85+
in x == 1 && y == 2 && z

0 commit comments

Comments
 (0)