aboutsummaryrefslogtreecommitdiffstats
path: root/app/Record.hs
diff options
context:
space:
mode:
Diffstat (limited to 'app/Record.hs')
-rw-r--r--app/Record.hs78
1 files changed, 78 insertions, 0 deletions
diff --git a/app/Record.hs b/app/Record.hs
new file mode 100644
index 0000000..d23d289
--- /dev/null
+++ b/app/Record.hs
@@ -0,0 +1,78 @@
+module Record
+ ( Record (..),
+ fromValue,
+ toValue,
+ lookup,
+ Records,
+ select,
+ disjointUnion,
+ disjointUnions,
+ )
+where
+
+import Control.Exception (throw)
+import Data.Aeson qualified as J
+import Data.Aeson.Key qualified as JK
+import Data.Aeson.KeyMap qualified as JM
+import Data.List (foldl')
+import Data.List.NonEmpty qualified as N
+import Data.Maybe (mapMaybe)
+import Data.Text qualified as T
+import Exception (DuplicateField (DuplicateField))
+import Field qualified as F
+import Prelude hiding (lookup)
+
+data Record a
+ = Record Collection a
+ deriving (Show, Eq)
+
+type Collection = FilePath
+
+fromValue :: Collection -> a -> Record a
+fromValue = Record
+
+toValue :: Record a -> a
+toValue (Record _ v) = v
+
+lookup :: F.Field -> Record J.Value -> Maybe J.Value
+lookup (F.Unqualified ks) (Record _ v) =
+ lookup' (N.toList ks) v
+lookup (F.Qualified c' ks) (Record c v)
+ | c' == c = lookup' (N.toList ks) v
+ | otherwise = Nothing
+
+lookup' :: [T.Text] -> J.Value -> Maybe J.Value
+lookup' [] v = Just v
+lookup' (k : ks) (J.Object kvs) =
+ lookup' ks =<< JM.lookup (JK.fromText k) kvs
+
+type Records a = [Record a]
+
+select :: [F.Field] -> Records J.Value -> J.Value
+select fs rs =
+ foldl'
+ union
+ (J.Object JM.empty)
+ (map (\f -> F.prefix f (select' rs f)) fs)
+
+select' :: Records J.Value -> F.Field -> J.Value
+select' rs f = case mapMaybe (lookup f) rs of
+ [] -> J.Null
+ [v] -> v
+ (_ : _) -> throw (DuplicateField (F.toString f))
+
+union :: J.Value -> J.Value -> J.Value
+union (J.Object r) (J.Object s) = J.Object (JM.unionWith union r s)
+
+disjointUnion :: J.Value -> J.Value -> J.Value
+disjointUnion (J.Object r) (J.Object s) =
+ J.Object (JM.unionWithKey disjointUnion' r s)
+
+disjointUnion' :: JK.Key -> J.Value -> J.Value -> J.Value
+disjointUnion' _ (J.Object r) (J.Object s) =
+ J.Object (JM.unionWithKey disjointUnion' r s)
+disjointUnion' k _ _ =
+ throw (DuplicateField (JK.toString k))
+
+disjointUnions :: [J.Value] -> J.Value
+disjointUnions = foldl' disjointUnion (J.Object JM.empty)