@@ -0,0 +1,135 @@
1+module Yoga.Fetch.Om.QueryDefaults
2+ ( class BuildMaybeQuery
5+ , class BuildMaybeQueryField
6+ , buildMaybeQueryField
8+ , class SplitQueryRowRL
9+ , class BuildQueryFromPartial
10+ , buildQueryFromPartial
11+ , class BuildQueryFromPartialRL
12+ , buildQueryFromPartialRL
15+import Data.Maybe (Maybe(..))
16+import Data.Symbol (class IsSymbol)
17+import Prim.Boolean (True, False)
18+import Prim.Row as Row
19+import Prim.RowList (class RowToList, RowList)
20+import Prim.RowList as RL
21+import Record as Record
22+import Type.Proxy (Proxy(..))
24+-- | Check whether a label exists in a RowList
25+class HasField (name :: Symbol) (rl :: RowList Type) (has :: Boolean) | name rl -> has
27+instance HasField name RL.Nil False
28+instance HasField name (RL.Cons name ty tail) True
29+else instance HasField name tail has => HasField name (RL.Cons other ty tail) has
31+-- | Get a Maybe-wrapped value from a record, based on whether the field exists
32+class BuildMaybeQueryField (has :: Boolean) (name :: Symbol) (ty :: Type) (provided :: Row Type) where
33+ buildMaybeQueryField :: Proxy has -> Proxy name -> Record provided -> Maybe ty
35+instance (IsSymbol name, Row.Cons name ty rest provided) =>
36+ BuildMaybeQueryField True name ty provided where
37+ buildMaybeQueryField _ _ provided = Just (Record.get (Proxy :: _ name) provided)
39+instance BuildMaybeQueryField False name ty provided where
40+ buildMaybeQueryField _ _ _ = Nothing
42+-- | Build a full Maybe-wrapped query record from a partial provided record.
43+-- | Fields present in provided get Just, missing fields get Nothing.
44+class BuildMaybeQuery (rl :: RowList Type) (providedRL :: RowList Type) (provided :: Row Type) (queryParams :: Row Type) | rl -> queryParams where
45+ buildMaybeQuery :: Proxy rl -> Proxy providedRL -> Record provided -> Record queryParams
47+instance BuildMaybeQuery RL.Nil providedRL provided () where
48+ buildMaybeQuery _ _ _ = {}
52+ , HasField name providedRL has
53+ , BuildMaybeQueryField has name ty provided
54+ , BuildMaybeQuery tail providedRL provided tailQuery
55+ , Row.Cons name (Maybe ty) tailQuery queryParams
56+ , Row.Lacks name tailQuery
58+ BuildMaybeQuery (RL.Cons name ty tail) providedRL provided queryParams where
59+ buildMaybeQuery _ prl provided = Record.insert (Proxy :: _ name) val rest
61+ val = buildMaybeQueryField (Proxy :: _ has) (Proxy :: _ name) provided
62+ rest = buildMaybeQuery (Proxy :: _ tail) prl provided
64+-- | Split a query params row into optional raw types and required raw types.
65+-- | Maybe ty → optional with raw type ty
66+-- | ty (no Maybe) → required with raw type ty (from Required query params)
67+class SplitQueryRow (queryParams :: Row Type) (optionalRaw :: Row Type) (requiredRaw :: Row Type) | queryParams -> optionalRaw requiredRaw
69+instance (RowToList queryParams rl, SplitQueryRowRL rl optionalRaw requiredRaw) => SplitQueryRow queryParams optionalRaw requiredRaw
71+class SplitQueryRowRL (rl :: RowList Type) (optionalRaw :: Row Type) (requiredRaw :: Row Type) | rl -> optionalRaw requiredRaw
73+instance SplitQueryRowRL RL.Nil () ()
75+-- Maybe ty field → optional
77+ ( SplitQueryRowRL tail optTail reqTail
78+ , Row.Cons name ty optTail optionalRaw
79+ , Row.Lacks name optTail
81+ SplitQueryRowRL (RL.Cons name (Maybe ty) tail) optionalRaw reqTail
83+-- Non-Maybe field → required (from Required query params)
85+ ( SplitQueryRowRL tail optTail reqTail
86+ , Row.Cons name ty reqTail requiredRaw
87+ , Row.Lacks name reqTail
89+ SplitQueryRowRL (RL.Cons name ty tail) optTail requiredRaw
91+-- | Build full queryParams from a partial record that contains path params,
92+-- | required query params, and optionally some optional query params.
93+-- | Walks the queryParams RowList:
94+-- | Maybe ty field → check if raw value provided, wrap in Just or Nothing
95+-- | bare ty field → copy from provided (required, always present)
96+class BuildQueryFromPartial (queryParams :: Row Type) (provided :: Row Type) where
97+ buildQueryFromPartial :: Record provided -> Record queryParams
99+instance (RowToList queryParams rl, RowToList provided prl, BuildQueryFromPartialRL rl prl provided queryParams) => BuildQueryFromPartial queryParams provided where
100+ buildQueryFromPartial = buildQueryFromPartialRL (Proxy :: _ rl) (Proxy :: _ prl)
102+class BuildQueryFromPartialRL (rl :: RowList Type) (providedRL :: RowList Type) (provided :: Row Type) (queryParams :: Row Type) | rl -> queryParams where
103+ buildQueryFromPartialRL :: Proxy rl -> Proxy providedRL -> Record provided -> Record queryParams
105+instance BuildQueryFromPartialRL RL.Nil providedRL provided () where
106+ buildQueryFromPartialRL _ _ _ = {}
108+-- Maybe ty: check if field is provided, wrap in Just or use Nothing
111+ , HasField name providedRL has
112+ , BuildMaybeQueryField has name ty provided
113+ , BuildQueryFromPartialRL tail providedRL provided tailQuery
114+ , Row.Cons name (Maybe ty) tailQuery queryParams
115+ , Row.Lacks name tailQuery
117+ BuildQueryFromPartialRL (RL.Cons name (Maybe ty) tail) providedRL provided queryParams where
118+ buildQueryFromPartialRL _ prl provided = Record.insert (Proxy :: _ name) val rest
120+ val = buildMaybeQueryField (Proxy :: _ has) (Proxy :: _ name) provided
121+ rest = buildQueryFromPartialRL (Proxy :: _ tail) prl provided
123+-- bare ty (Required): always present in provided, copy directly
126+ , Row.Cons name ty rest provided
127+ , BuildQueryFromPartialRL tail providedRL provided tailQuery
128+ , Row.Cons name ty tailQuery queryParams
129+ , Row.Lacks name tailQuery
131+ BuildQueryFromPartialRL (RL.Cons name ty tail) providedRL provided queryParams where
132+ buildQueryFromPartialRL _ prl provided = Record.insert (Proxy :: _ name) val rest
134+ val = Record.get (Proxy :: _ name) provided
135+ rest = buildQueryFromPartialRL (Proxy :: _ tail) prl provided