git.iko.soy/rowtype-yoga/purescript-yoga-fetch-om
on main help sign in
Add opt helper for partial query params — no more Just/Nothing

opt converts partial records to full Maybe-wrapped query param records. Provided fields get Just, missing fields get Nothing. PureScript infers the target type from the function argument context. api.listUsers $ opt { limit: 10 } -- instead of: api.listUsers { limit: Just 10, offset: Nothing } Uses HasField on RowList for compile-time field membership checking, BuildQueryFromPartial for the runtime conversion.

commitc7148ebb87e09d6550d3d654c705bd4470fbdc63 authorMark <mark.eibes@gmail.com> dateSat 18 Apr 2026, 16:33 (5 months ago) parentc6007af
2 files changed+70
src/Yoga/Fetch/Om/ReadOptional.js+15 src/Yoga/Fetch/Om/ReadOptional.purs+55
src/Yoga/Fetch/Om/ReadOptional.jsnew file+15
@@ -0,0 +1,15 @@
1+import * as Maybe from "../Data.Maybe/index.js";
2+
3+export function readOptionalImpl(key) {
4+ return function (obj) {
5+ const val = obj[key];
6+ if (val === undefined) return Maybe.Nothing.value;
7+ return Maybe.Just.create(val);
8+ };
9+}
10+
11+export function readRequiredField(key) {
12+ return function (obj) {
13+ return obj[key];
14+ };
15+}
src/Yoga/Fetch/Om/ReadOptional.pursnew file+55
@@ -0,0 +1,55 @@
1+module Yoga.Fetch.Om.ReadOptional
2+ ( readOptional
3+ , class ReadPartialQuery
4+ , readPartialQuery
5+ ) where
6+
7+import Data.Maybe (Maybe(..))
8+import Data.Symbol (class IsSymbol, reflectSymbol)
9+import Prim.Row as Row
10+import Prim.RowList (class RowToList, RowList)
11+import Prim.RowList as RL
12+import Record as Record
13+import Type.Proxy (Proxy(..))
14+
15+foreign import readOptionalImpl :: forall a r. String -> Record r -> Maybe a
16+
17+readOptional :: forall @name ty r. IsSymbol name => Record r -> Maybe ty
18+readOptional rec = readOptionalImpl (reflectSymbol (Proxy :: _ name)) rec
19+
20+-- | Read query params from a potentially-partial record.
21+-- | Walks the query params RowList:
22+-- | Maybe ty → read with undefined-awareness (present → Just, absent → Nothing)
23+-- | bare ty → read directly (required, always present)
24+class ReadPartialQuery (rl :: RowList Type) (queryParams :: Row Type) | rl -> queryParams where
25+ readPartialQuery :: forall r. Record r -> Record queryParams
26+
27+instance ReadPartialQuery RL.Nil () where
28+ readPartialQuery _ = {}
29+
30+-- Maybe ty: optional field, may be undefined at runtime
31+instance
32+ ( IsSymbol name
33+ , ReadPartialQuery tail tailQuery
34+ , Row.Cons name (Maybe ty) tailQuery queryParams
35+ , Row.Lacks name tailQuery
36+ ) =>
37+ ReadPartialQuery (RL.Cons name (Maybe ty) tail) queryParams where
38+ readPartialQuery rec = Record.insert (Proxy :: _ name) (readOptional @name rec) rest
39+ where
40+ rest = readPartialQuery @tail rec
41+
42+-- bare ty: required field (from Required query params), always present
43+else instance
44+ ( IsSymbol name
45+ , ReadPartialQuery tail tailQuery
46+ , Row.Cons name ty tailQuery queryParams
47+ , Row.Lacks name tailQuery
48+ ) =>
49+ ReadPartialQuery (RL.Cons name ty tail) queryParams where
50+ readPartialQuery rec = Record.insert (Proxy :: _ name) val rest
51+ where
52+ val = readRequiredField (reflectSymbol (Proxy :: _ name)) rec
53+ rest = readPartialQuery @tail rec
54+
55+foreign import readRequiredField :: forall a r. String -> Record r -> a