@@ -1,5 +1,6 @@
11{-# language AllowAmbiguousTypes #-}
22{-# language DataKinds #-}
3+{-# language DefaultSignatures #-}
34{-# language DisambiguateRecordFields #-}
45{-# language FlexibleContexts #-}
56{-# language FlexibleInstances #-}
@@ -9,6 +10,7 @@
910{-# language StandaloneKindSignatures #-}
1011{-# language TypeApplications #-}
1112{-# language TypeFamilies #-}
13+{-# language TypeOperators #-}
1214{-# language UndecidableInstances #-}
1315
1416module Rel8.Table.Serialize
@@ -23,6 +25,11 @@ where
2325import Data.Bifunctor ( bimap )
2426import Data.Kind ( Constraint, Type )
2527import Data.List.NonEmpty ( NonEmpty )
28+import GHC.Generics
29+ ( Generic, Rep, from, to
30+ , (:*:)( (:*:) ), K1( K1 ), M1( M1 ), Meta( MetaSel ), D, C, S
31+ )
32+import GHC.TypeLits ( KnownSymbol )
2633import Prelude
2734
2835-- hasql
@@ -31,19 +38,17 @@ import qualified Hasql.Decoders as Hasql
3138-- rel8
3239import Rel8.Expr ( Expr, Col(..) )
3340import Rel8.Expr.Serialize ( slitExpr, sparseValue )
41+import Rel8.Generic.Record ( Record(..) )
3442import Rel8.Schema.Context ( Col(..) )
3543import Rel8.Schema.Context.Label ( labeler, unlabeler )
3644import Rel8.Schema.HTable ( HTable, htabulate, htabulateA, hfield, hspecs )
37−import Rel8.Schema.HTable.Label ( hlabel, hunlabel )
38−import Rel8.Schema.HTable.Quartet ( HQuartet(..) )
39−import Rel8.Schema.HTable.Quintet ( HQuintet(..) )
40−import Rel8.Schema.HTable.Pair ( HPair(..) )
41−import Rel8.Schema.HTable.Trio ( HTrio(..) )
45+import Rel8.Schema.HTable.Label ( HLabel, hlabel, hunlabel )
46+import Rel8.Schema.HTable.Product ( HProduct(..) )
4247import Rel8.Schema.HTable.Type ( HType(..) )
4348import Rel8.Schema.Null ( NotNull, Sql )
4449import Rel8.Schema.Result ( Result )
4550import Rel8.Schema.Spec ( SSpec(..), KnownSpec )
46−import Rel8.Table ( Table, Columns, fromColumns, toColumns )
51+import Rel8.Table ( Table, Columns, fromColumns, toColumns, GColumns )
4752import Rel8.Table.Either ( EitherTable )
4853import Rel8.Table.List ( ListTable )
4954import Rel8.Table.Maybe ( MaybeTable )
@@ -64,6 +69,59 @@ class Table Expr exprs => ToExprs exprs a where
6469 fromResult :: Columns exprs (Col Result) -> a
6570 toResult :: a -> Columns exprs (Col Result)
6671
72+ default fromResult ::
73+ ( Generic (Record a)
74+ , GToExprs (Rep (Record exprs)) (Rep (Record a))
75+ , Columns exprs ~ GColumns (Rep (Record exprs))
76+ )
77+ => Columns exprs (Col Result) -> a
78+ fromResult = unrecord . to . gfromResult @(Rep (Record exprs))
79+
80+ default toResult ::
81+ ( Generic (Record a)
82+ , GToExprs (Rep (Record exprs)) (Rep (Record a))
83+ , Columns exprs ~ GColumns (Rep (Record exprs))
84+ )
85+ => a -> Columns exprs (Col Result)
86+ toResult = gtoResult @(Rep (Record exprs)) . from . Record
87+
88+
89+type GToExprs :: (Type -> Type) -> (Type -> Type) -> Constraint
90+class GToExprs exprs rep where
91+ gfromResult :: GColumns exprs (Col Result) -> rep x
92+ gtoResult :: rep x -> GColumns exprs (Col Result)
93+
94+
95+instance GToExprs exprs rep => GToExprs (M1 D c exprs) (M1 D c rep) where
96+ gfromResult = M1 . gfromResult @exprs
97+ gtoResult (M1 a) = gtoResult @exprs a
98+
99+
100+instance GToExprs exprs rep => GToExprs (M1 C c exprs) (M1 C c rep) where
101+ gfromResult = M1 . gfromResult @exprs
102+ gtoResult (M1 a) = gtoResult @exprs a
103+
104+
105+instance (GToExprs exprs1 rep1, GToExprs exprs2 rep2) =>
106+ GToExprs (exprs1 :*: exprs2) (rep1 :*: rep2)
107+ where
108+ gfromResult (HProduct a b) = gfromResult @exprs1 a :*: gfromResult @exprs2 b
109+ gtoResult (a :*: b) = HProduct (gtoResult @exprs1 a) (gtoResult @exprs2 b)
110+
111+
112+instance
113+ ( ToExprs exprs a
114+ , KnownSymbol label
115+ , GColumns (M1 S meta k1) ~ HLabel label (Columns exprs)
116+ , meta ~ 'MetaSel ('Just label) _su _ss _ds
117+ , k1 ~ K1 i exprs
118+ , k1' ~ K1 i a
119+ )
120+ => GToExprs (M1 S meta k1) (M1 S meta k1')
121+ where
122+ gfromResult = M1 . K1 . fromResult @exprs . hunlabel unlabeler
123+ gtoResult (M1 (K1 a)) = hlabel labeler (toResult @exprs a)
124+
67125
68126instance {-# OVERLAPPABLE #-} (Sql DBType a, x ~ Expr a) => ToExprs x a where
69127 fromResult (HType (Result a)) = a
@@ -127,15 +185,6 @@ instance (ToExprs exprs1 a, ToExprs exprs2 b, x ~ TheseTable exprs1 exprs2) =>
127185
128186instance (ToExprs exprs1 a, ToExprs exprs2 b, x ~ (exprs1, exprs2)) =>
129187 ToExprs x (a, b)
130− where
131− fromResult (HPair a b) =
132− ( fromResult @exprs1 $ hunlabel unlabeler a
133− , fromResult @exprs2 $ hunlabel unlabeler b
134− )
135− toResult (a, b) = HPair
136− { hfst = hlabel labeler $ toResult @exprs1 a
137− , hsnd = hlabel labeler $ toResult @exprs2 b
138− }
139188
140189
141190instance
@@ -143,18 +192,8 @@ instance
143192 , ToExprs exprs2 b
144193 , ToExprs exprs3 c
145194 , x ~ (exprs1, exprs2, exprs3)
146− ) => ToExprs x (a, b, c)
147− where
148− fromResult (HTrio a b c) =
149− ( fromResult @exprs1 $ hunlabel unlabeler a
150− , fromResult @exprs2 $ hunlabel unlabeler b
151− , fromResult @exprs3 $ hunlabel unlabeler c
152− )
153− toResult (a, b, c) = HTrio
154− { hfst = hlabel labeler $ toResult @exprs1 a
155− , hsnd = hlabel labeler $ toResult @exprs2 b
156− , htrd = hlabel labeler $ toResult @exprs3 c
157− }
195+ )
196+ => ToExprs x (a, b, c)
158197
159198
160199instance
@@ -163,20 +202,8 @@ instance
163202 , ToExprs exprs3 c
164203 , ToExprs exprs4 d
165204 , x ~ (exprs1, exprs2, exprs3, exprs4)
166− ) => ToExprs x (a, b, c, d)
167− where
168− fromResult (HQuartet a b c d) =
169− ( fromResult @exprs1 $ hunlabel unlabeler a
170− , fromResult @exprs2 $ hunlabel unlabeler b
171− , fromResult @exprs3 $ hunlabel unlabeler c
172− , fromResult @exprs4 $ hunlabel unlabeler d
173− )
174− toResult (a, b, c, d) = HQuartet
175− { hfst = hlabel labeler $ toResult @exprs1 a
176− , hsnd = hlabel labeler $ toResult @exprs2 b
177− , htrd = hlabel labeler $ toResult @exprs3 c
178− , hfrt = hlabel labeler $ toResult @exprs4 d
179− }
205+ )
206+ => ToExprs x (a, b, c, d)
180207
181208
182209instance
@@ -186,22 +213,8 @@ instance
186213 , ToExprs exprs4 d
187214 , ToExprs exprs5 e
188215 , x ~ (exprs1, exprs2, exprs3, exprs4, exprs5)
189− ) => ToExprs x (a, b, c, d, e)
190− where
191− fromResult (HQuintet a b c d e) =
192− ( fromResult @exprs1 $ hunlabel unlabeler a
193− , fromResult @exprs2 $ hunlabel unlabeler b
194− , fromResult @exprs3 $ hunlabel unlabeler c
195− , fromResult @exprs4 $ hunlabel unlabeler d
196− , fromResult @exprs5 $ hunlabel unlabeler e
197− )
198− toResult (a, b, c, d, e) = HQuintet
199− { hfst = hlabel labeler $ toResult @exprs1 a
200− , hsnd = hlabel labeler $ toResult @exprs2 b
201− , htrd = hlabel labeler $ toResult @exprs3 c
202− , hfrt = hlabel labeler $ toResult @exprs4 d
203− , hfft = hlabel labeler $ toResult @exprs5 e
204− }
216+ )
217+ => ToExprs x (a, b, c, d, e)
205218
206219
207220instance (HTable t, result ~ Col Result, x ~ t (Col Expr)) =>