@@ -2,6 +2,7 @@
2{-# language FlexibleContexts #-}
2{-# language FlexibleContexts #-}
3{-# language FlexibleInstances #-}
3{-# language FlexibleInstances #-}
4{-# language InstanceSigs #-}
4{-# language InstanceSigs #-}
5+{-# language LambdaCase #-}
5{-# language MultiParamTypeClasses #-}
6{-# language MultiParamTypeClasses #-}
6{-# language NamedFieldPuns #-}
7{-# language NamedFieldPuns #-}
7{-# language ScopedTypeVariables #-}
8{-# language ScopedTypeVariables #-}
@@ -12,29 +13,37 @@
12module Rel8.Schema.Context.Nullify
13module Rel8.Schema.Context.Nullify
13 ( Nullifiable( ConstrainTag, encodeTag, decodeTag, nullifier, unnullifier )
14 ( Nullifiable( ConstrainTag, encodeTag, decodeTag, nullifier, unnullifier )
14 , HNullifiable( HConstrainTag, hencodeTag, hdecodeTag, hnullifier, hunnullifier )
15 , HNullifiable( HConstrainTag, hencodeTag, hdecodeTag, hnullifier, hunnullifier )
15− , unnull, runTag
16+ , runTag, runTagExpr, unnull, unnullExpr
21+import Control.Monad ( guard )
22+import Data.Functor.Identity ( Identity )
20import Data.Kind ( Constraint, Type )
23import Data.Kind ( Constraint, Type )
24+import GHC.TypeLits ( KnownSymbol )
21import Prelude hiding ( null )
25import Prelude hiding ( null )
24import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
28import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
34+ , unsafeMakeAggregate
27−import {-# SOURCE #-} Rel8.Expr ( Expr )
36+import Rel8.Expr ( Expr, Col(..) )
28import Rel8.Expr.Bool ( boolExpr )
37import Rel8.Expr.Bool ( boolExpr )
29import Rel8.Expr.Null ( nullify, unsafeUnnullify )
38import Rel8.Expr.Null ( nullify, unsafeUnnullify )
30−import Rel8.Expr.Opaleye ( fromPrimExpr )
39+import Rel8.Expr.Opaleye ( fromPrimExpr, toPrimExpr )
31−import Rel8.Kind.Labels ( KnownLabels )
32import Rel8.Kind.Necessity ( Necessity( Required ) )
40import Rel8.Kind.Necessity ( Necessity( Required ) )
33import Rel8.Schema.Context ( Interpretation, Col(..) )
41import Rel8.Schema.Context ( Interpretation, Col(..) )
34import qualified Rel8.Schema.Kind as K
42import qualified Rel8.Schema.Kind as K
43+import Rel8.Schema.Name ( Name( Name ), Col(..) )
35import Rel8.Schema.Nullability
44import Rel8.Schema.Nullability
37− , Nullability( Nullable, NonNullable ), nullabilization
46+ , Nullability( Nullable, NonNullable )
40import Rel8.Schema.Dict ( Dict( Dict ) )
49import Rel8.Schema.Dict ( Dict( Dict ) )
@@ -43,8 +52,10 @@ import Rel8.Schema.Spec.ConstrainDBType
43 ( ConstrainDBType
52 ( ConstrainDBType
44 , dbTypeDict, dbTypeNullability, fromNullabilityDict
53 , dbTypeDict, dbTypeNullability, fromNullabilityDict
46−import Rel8.Type.Eq ( DBEq )
55+import Rel8.Table.Tag
47−import Rel8.Type.Monoid ( DBMonoid, memptyExpr )
56+ ( Tag(..), Taggable
57+ , fromAggregate, fromExpr, fromIdentity, fromName
50type Nullifiable :: K.Context -> Constraint
61type Nullifiable :: K.Context -> Constraint
@@ -52,65 +63,150 @@ class Interpretation context => Nullifiable context where
52 type ConstrainTag context :: Type -> Constraint
63 type ConstrainTag context :: Type -> Constraint
53 type ConstrainTag _context = DefaultConstrainTag
64 type ConstrainTag _context = DefaultConstrainTag
55− encodeTag :: (Sql (ConstrainTag context) a, Sql DBEq a, KnownLabels labels)
67+ ( Sql (ConstrainTag context) a
56− => Expr a
68+ , KnownSymbol label
57 -> Col context ('Spec labels 'Required a)
72 -> Col context ('Spec labels 'Required a)
59− decodeTag :: (Sql (ConstrainTag context) a, Sql DBMonoid a)
75+ ( Sql (ConstrainTag context) a
60 => Col context ('Spec labels 'Required a)
79 => Col context ('Spec labels 'Required a)
61− -> Expr a
80+ -> Tag label a
63 nullifier :: ()
82 nullifier :: ()
64− => Expr Bool
85+ -> (Expr a -> Expr Bool)
65− -> SSpec ('Spec labels necessity a)
86+ -> SSpec ('Spec labels necessity x)
66− -> Col context ('Spec labels necessity a)
87+ -> Col context ('Spec labels necessity x)
67− -> Col context ('Spec labels necessity (Nullify a))
88+ -> Col context ('Spec labels necessity (Nullify x))
69 unnullifier :: ()
90 unnullifier :: ()
71− -> SSpec ('Spec labels necessity a)
91+ => SSpec ('Spec labels necessity x)
72− -> Col context ('Spec labels necessity (Nullify a))
92+ -> Col context ('Spec labels necessity (Nullify x))
73− -> Col context ('Spec labels necessity a)
93+ -> Col context ('Spec labels necessity x)
96+instance Nullifiable Aggregate where
97+ encodeTag Tag {aggregator, expr} =
98+ Aggregation $ unsafeMakeAggregate toPrimExpr fromPrimExpr aggregator expr
100+ decodeTag (Aggregation aggregate) = fromAggregate aggregate
102+ nullifier Tag {expr} _ test SSpec {nullability} (Aggregation aggregate) =
104+ mapInputs (toPrimExpr . runTagExpr nullability condition . fromPrimExpr) $
105+ runTagExpr nullability condition <$> aggregate
107+ condition = test expr
109+ unnullifier SSpec {nullability} (Aggregation aggregate) =
110+ Aggregation $ unnullExpr nullability <$> aggregate
112+ {-# INLINABLE encodeTag #-}
113+ {-# INLINABLE decodeTag #-}
114+ {-# INLINABLE nullifier #-}
115+ {-# INLINABLE unnullifier #-}
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
125+ {-# INLINABLE encodeTag #-}
126+ {-# INLINABLE decodeTag #-}
127+ {-# INLINABLE nullifier #-}
128+ {-# INLINABLE unnullifier #-}
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
138+ {-# INLINABLE encodeTag #-}
139+ {-# INLINABLE decodeTag #-}
140+ {-# INLINABLE nullifier #-}
141+ {-# INLINABLE unnullifier #-}
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
150+ {-# INLINABLE encodeTag #-}
151+ {-# INLINABLE decodeTag #-}
152+ {-# INLINABLE nullifier #-}
153+ {-# INLINABLE unnullifier #-}
76−runTag :: Nullability a -> Expr Bool -> Expr a -> Expr (Nullify a)
156+runTagExpr :: Nullability a -> Expr Bool -> Expr a -> Expr (Nullify a)
77−runTag nullability tag a = case nullability of
157+runTagExpr nullability tag a = case nullability of
78 Nullable -> boolExpr null a tag
158 Nullable -> boolExpr null a tag
79 NonNullable -> boolExpr null (nullify a) tag
159 NonNullable -> boolExpr null (nullify a) tag
81 null = fromPrimExpr $ Opaleye.ConstExpr Opaleye.NullLit
161 null = fromPrimExpr $ Opaleye.ConstExpr Opaleye.NullLit
84−unnull :: Nullability a -> Expr (Nullify a) -> Expr a
164+unnullExpr :: Nullability a -> Expr (Nullify a) -> Expr a
85−unnull nullability a = case nullability of
165+unnullExpr nullability a = case nullability of
86 Nullable -> a
166 Nullable -> a
87 NonNullable -> unsafeUnnullify a
167 NonNullable -> unsafeUnnullify a
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
176+unnull :: Nullability a -> Nullify a -> a
177+unnull nullability ma = case nullability of
179+ NonNullable -> case ma of
182+ error "Rel8.Schema.Context.Nullify.unnull: mismatch between tag and data"
90type HNullifiable :: K.HContext -> Constraint
185type HNullifiable :: K.HContext -> Constraint
91class HNullifiable context where
186class HNullifiable context where
92 type HConstrainTag context :: Type -> Constraint
187 type HConstrainTag context :: Type -> Constraint
93 type HConstrainTag _context = DefaultConstrainTag
188 type HConstrainTag _context = DefaultConstrainTag
95− hencodeTag :: (Sql (HConstrainTag context) a, Sql DBEq a, KnownLabels labels)
190+ hencodeTag :: (Sql (HConstrainTag context) a, KnownSymbol label, Taggable a)
96− => Expr a
191+ => Tag label a
97 -> context ('Spec labels 'Required a)
192 -> context ('Spec labels 'Required a)
99− hdecodeTag :: (Sql (HConstrainTag context) a, Sql DBMonoid a)
194+ hdecodeTag :: (Sql (HConstrainTag context) a, KnownSymbol label, Taggable a)
100 => context ('Spec labels 'Required a)
195 => context ('Spec labels 'Required a)
101− -> Expr a
196+ -> Tag label a
103 hnullifier :: ()
198 hnullifier :: ()
104− => Expr Bool
201+ -> (Expr a -> Expr Bool)
105− -> SSpec ('Spec labels necessity a)
202+ -> SSpec ('Spec labels necessity x)
106− -> context ('Spec labels necessity a)
203+ -> context ('Spec labels necessity x)
107− -> context ('Spec labels necessity (Nullify a))
204+ -> context ('Spec labels necessity (Nullify x))
109 hunnullifier :: ()
206 hunnullifier :: ()
111− -> SSpec ('Spec labels necessity a)
207+ => SSpec ('Spec labels necessity x)
112− -> context ('Spec labels necessity (Nullify a))
208+ -> context ('Spec labels necessity (Nullify x))
113− -> context ('Spec labels necessity a)
209+ -> context ('Spec labels necessity x)
116instance Nullifiable context => HNullifiable (Col context) where
212instance Nullifiable context => HNullifiable (Col context) where
@@ -125,21 +221,14 @@ instance HNullifiable (Dict (ConstrainDBType constraint)) where
125 type HConstrainTag (Dict (ConstrainDBType constraint)) = constraint
221 type HConstrainTag (Dict (ConstrainDBType constraint)) = constraint
127 hencodeTag _ = Dict
223 hencodeTag _ = Dict
129− hdecodeTag :: forall a context labels. (Sql (HConstrainTag context) a, Sql DBMonoid a)
130− => context ('Spec labels 'Required a)
132− hdecodeTag _ = case nullabilization @a of
133− Nullable -> nullify memptyExpr
134− NonNullable -> memptyExpr
137− hnullifier _ SSpec {} dict = case dbTypeDict dict of
226+ hnullifier _ _ _ SSpec {} dict = case dbTypeDict dict of
138 Dict -> case dbTypeNullability dict of
227 Dict -> case dbTypeNullability dict of
139 Nullable -> Dict
228 Nullable -> Dict
140 NonNullable -> Dict
229 NonNullable -> Dict
142− hunnullifier _ SSpec {nullability} dict = case dbTypeDict dict of
231+ hunnullifier SSpec {nullability} dict = case dbTypeDict dict of
143 Dict -> case nullability of
232 Dict -> case nullability of
144 Nullable -> Dict
233 Nullable -> Dict
145 NonNullable -> case dbTypeNullability dict of
234 NonNullable -> case dbTypeNullability dict of