@@ -2,6 +2,7 @@
22{-# language FlexibleContexts #-}
33{-# language FlexibleInstances #-}
44{-# language InstanceSigs #-}
5+{-# language LambdaCase #-}
56{-# language MultiParamTypeClasses #-}
67{-# language NamedFieldPuns #-}
78{-# language ScopedTypeVariables #-}
@@ -12,29 +13,37 @@
1213module Rel8.Schema.Context.Nullify
1314 ( Nullifiable( ConstrainTag, encodeTag, decodeTag, nullifier, unnullifier )
1415 , HNullifiable( HConstrainTag, hencodeTag, hdecodeTag, hnullifier, hunnullifier )
15− , unnull, runTag
16+ , runTag, runTagExpr, unnull, unnullExpr
1617 )
1718where
1819
1920-- base
21+import Control.Monad ( guard )
22+import Data.Functor.Identity ( Identity )
2023import Data.Kind ( Constraint, Type )
24+import GHC.TypeLits ( KnownSymbol )
2125import Prelude hiding ( null )
2226
2327-- opaleye
2428import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
2529
2630-- rel8
27−import {-# SOURCE #-} Rel8.Expr ( Expr )
31+import Rel8.Aggregate
32+ ( Aggregate, Col(..)
33+ , mapInputs
34+ , unsafeMakeAggregate
35+ )
36+import Rel8.Expr ( Expr, Col(..) )
2837import Rel8.Expr.Bool ( boolExpr )
2938import Rel8.Expr.Null ( nullify, unsafeUnnullify )
30−import Rel8.Expr.Opaleye ( fromPrimExpr )
31−import Rel8.Kind.Labels ( KnownLabels )
39+import Rel8.Expr.Opaleye ( fromPrimExpr, toPrimExpr )
3240import Rel8.Kind.Necessity ( Necessity( Required ) )
3341import Rel8.Schema.Context ( Interpretation, Col(..) )
3442import qualified Rel8.Schema.Kind as K
43+import Rel8.Schema.Name ( Name( Name ), Col(..) )
3544import Rel8.Schema.Nullability
3645 ( Nullify
37− , Nullability( Nullable, NonNullable ), nullabilization
46+ , Nullability( Nullable, NonNullable )
3847 , Sql
3948 )
4049import Rel8.Schema.Dict ( Dict( Dict ) )
@@ -43,8 +52,10 @@ import Rel8.Schema.Spec.ConstrainDBType
4352 ( ConstrainDBType
4453 , dbTypeDict, dbTypeNullability, fromNullabilityDict
4554 )
46−import Rel8.Type.Eq ( DBEq )
47−import Rel8.Type.Monoid ( DBMonoid, memptyExpr )
55+import Rel8.Table.Tag
56+ ( Tag(..), Taggable
57+ , fromAggregate, fromExpr, fromIdentity, fromName
58+ )
4859
4960
5061type Nullifiable :: K.Context -> Constraint
@@ -52,65 +63,150 @@ class Interpretation context => Nullifiable context where
5263 type ConstrainTag context :: Type -> Constraint
5364 type ConstrainTag _context = DefaultConstrainTag
5465
55− encodeTag :: (Sql (ConstrainTag context) a, Sql DBEq a, KnownLabels labels)
56− => Expr a
66+ encodeTag ::
67+ ( Sql (ConstrainTag context) a
68+ , KnownSymbol label
69+ , Taggable a
70+ )
71+ => Tag label a
5772 -> Col context ('Spec labels 'Required a)
5873
59− decodeTag :: (Sql (ConstrainTag context) a, Sql DBMonoid a)
74+ decodeTag ::
75+ ( Sql (ConstrainTag context) a
76+ , KnownSymbol label
77+ , Taggable a
78+ )
6079 => Col context ('Spec labels 'Required a)
61− -> Expr a
80+ -> Tag label a
6281
6382 nullifier :: ()
64− => Expr Bool
65− -> SSpec ('Spec labels necessity a)
66− -> Col context ('Spec labels necessity a)
67− -> Col context ('Spec labels necessity (Nullify a))
83+ => Tag label a
84+ -> (a -> Bool)
85+ -> (Expr a -> Expr Bool)
86+ -> SSpec ('Spec labels necessity x)
87+ -> Col context ('Spec labels necessity x)
88+ -> Col context ('Spec labels necessity (Nullify x))
6889
6990 unnullifier :: ()
70− => Expr Bool
71− -> SSpec ('Spec labels necessity a)
72− -> Col context ('Spec labels necessity (Nullify a))
73− -> Col context ('Spec labels necessity a)
91+ => SSpec ('Spec labels necessity x)
92+ -> Col context ('Spec labels necessity (Nullify x))
93+ -> Col context ('Spec labels necessity x)
7494
7595
76−runTag :: Nullability a -> Expr Bool -> Expr a -> Expr (Nullify a)
77−runTag nullability tag a = case nullability of
96+instance Nullifiable Aggregate where
97+ encodeTag Tag {aggregator, expr} =
98+ Aggregation $ unsafeMakeAggregate toPrimExpr fromPrimExpr aggregator expr
99+
100+ decodeTag (Aggregation aggregate) = fromAggregate aggregate
101+
102+ nullifier Tag {expr} _ test SSpec {nullability} (Aggregation aggregate) =
103+ Aggregation $
104+ mapInputs (toPrimExpr . runTagExpr nullability condition . fromPrimExpr) $
105+ runTagExpr nullability condition <$> aggregate
106+ where
107+ condition = test expr
108+
109+ unnullifier SSpec {nullability} (Aggregation aggregate) =
110+ Aggregation $ unnullExpr nullability <$> aggregate
111+
112+ {-# INLINABLE encodeTag #-}
113+ {-# INLINABLE decodeTag #-}
114+ {-# INLINABLE nullifier #-}
115+ {-# INLINABLE unnullifier #-}
116+
117+
118+instance Nullifiable Expr where
119+ encodeTag Tag {expr} = DB expr
120+ decodeTag (DB a) = fromExpr a
121+ nullifier Tag {expr} _ test SSpec {nullability} (DB a) =
122+ DB $ runTagExpr nullability (test expr) a
123+ unnullifier SSpec {nullability} (DB a) = DB $ unnullExpr nullability a
124+
125+ {-# INLINABLE encodeTag #-}
126+ {-# INLINABLE decodeTag #-}
127+ {-# INLINABLE nullifier #-}
128+ {-# INLINABLE unnullifier #-}
129+
130+
131+instance Nullifiable Identity where
132+ encodeTag Tag {identity} = Result identity
133+ decodeTag (Result a) = fromIdentity a
134+ nullifier Tag {identity} test _ SSpec {nullability} (Result a) =
135+ Result $ runTag nullability (test identity) a
136+ unnullifier SSpec {nullability} (Result a) = Result $ unnull nullability a
137+
138+ {-# INLINABLE encodeTag #-}
139+ {-# INLINABLE decodeTag #-}
140+ {-# INLINABLE nullifier #-}
141+ {-# INLINABLE unnullifier #-}
142+
143+
144+instance Nullifiable Name where
145+ encodeTag Tag {name = Name name} = NameCol name
146+ decodeTag (NameCol name) = fromName (Name name)
147+ nullifier _ _ _ _ (NameCol name) = NameCol name
148+ unnullifier _ (NameCol name) = NameCol name
149+
150+ {-# INLINABLE encodeTag #-}
151+ {-# INLINABLE decodeTag #-}
152+ {-# INLINABLE nullifier #-}
153+ {-# INLINABLE unnullifier #-}
154+
155+
156+runTagExpr :: Nullability a -> Expr Bool -> Expr a -> Expr (Nullify a)
157+runTagExpr nullability tag a = case nullability of
78158 Nullable -> boolExpr null a tag
79159 NonNullable -> boolExpr null (nullify a) tag
80160 where
81161 null = fromPrimExpr $ Opaleye.ConstExpr Opaleye.NullLit
82162
83163
84−unnull :: Nullability a -> Expr (Nullify a) -> Expr a
85−unnull nullability a = case nullability of
164+unnullExpr :: Nullability a -> Expr (Nullify a) -> Expr a
165+unnullExpr nullability a = case nullability of
86166 Nullable -> a
87167 NonNullable -> unsafeUnnullify a
88168
89169
170+runTag :: Nullability a -> Bool -> a -> Nullify a
171+runTag nullability tag a = case nullability of
172+ Nullable -> a <* guard tag
173+ NonNullable -> a <$ guard tag
174+
175+
176+unnull :: Nullability a -> Nullify a -> a
177+unnull nullability ma = case nullability of
178+ Nullable -> ma
179+ NonNullable -> case ma of
180+ Just a -> a
181+ Nothing ->
182+ error "Rel8.Schema.Context.Nullify.unnull: mismatch between tag and data"
183+
184+
90185type HNullifiable :: K.HContext -> Constraint
91186class HNullifiable context where
92187 type HConstrainTag context :: Type -> Constraint
93188 type HConstrainTag _context = DefaultConstrainTag
94189
95− hencodeTag :: (Sql (HConstrainTag context) a, Sql DBEq a, KnownLabels labels)
96− => Expr a
190+ hencodeTag :: (Sql (HConstrainTag context) a, KnownSymbol label, Taggable a)
191+ => Tag label a
97192 -> context ('Spec labels 'Required a)
98193
99− hdecodeTag :: (Sql (HConstrainTag context) a, Sql DBMonoid a)
194+ hdecodeTag :: (Sql (HConstrainTag context) a, KnownSymbol label, Taggable a)
100195 => context ('Spec labels 'Required a)
101− -> Expr a
196+ -> Tag label a
102197
103198 hnullifier :: ()
104− => Expr Bool
105− -> SSpec ('Spec labels necessity a)
106− -> context ('Spec labels necessity a)
107− -> context ('Spec labels necessity (Nullify a))
199+ => Tag label a
200+ -> (a -> Bool)
201+ -> (Expr a -> Expr Bool)
202+ -> SSpec ('Spec labels necessity x)
203+ -> context ('Spec labels necessity x)
204+ -> context ('Spec labels necessity (Nullify x))
108205
109206 hunnullifier :: ()
110− => Expr Bool
111− -> SSpec ('Spec labels necessity a)
112− -> context ('Spec labels necessity (Nullify a))
113− -> context ('Spec labels necessity a)
207+ => SSpec ('Spec labels necessity x)
208+ -> context ('Spec labels necessity (Nullify x))
209+ -> context ('Spec labels necessity x)
114210
115211
116212instance Nullifiable context => HNullifiable (Col context) where
@@ -125,21 +221,14 @@ instance HNullifiable (Dict (ConstrainDBType constraint)) where
125221 type HConstrainTag (Dict (ConstrainDBType constraint)) = constraint
126222
127223 hencodeTag _ = Dict
224+ hdecodeTag = mempty
128225
129− hdecodeTag :: forall a context labels. (Sql (HConstrainTag context) a, Sql DBMonoid a)
130− => context ('Spec labels 'Required a)
131− -> Expr a
132− hdecodeTag _ = case nullabilization @a of
133− Nullable -> nullify memptyExpr
134− NonNullable -> memptyExpr
135−
136−
137− hnullifier _ SSpec {} dict = case dbTypeDict dict of
226+ hnullifier _ _ _ SSpec {} dict = case dbTypeDict dict of
138227 Dict -> case dbTypeNullability dict of
139228 Nullable -> Dict
140229 NonNullable -> Dict
141230
142− hunnullifier _ SSpec {nullability} dict = case dbTypeDict dict of
231+ hunnullifier SSpec {nullability} dict = case dbTypeDict dict of
143232 Dict -> case nullability of
144233 Nullable -> Dict
145234 NonNullable -> case dbTypeNullability dict of