1{-# language DataKinds #-}
2{-# language LambdaCase #-}
3{-# language FlexibleContexts #-}
4{-# language FlexibleInstances #-}
5{-# language MultiParamTypeClasses #-}
6{-# language NamedFieldPuns #-}
7{-# language ScopedTypeVariables #-}
8{-# language StandaloneKindSignatures #-}
9{-# language TypeApplications #-}
10{-# language TypeFamilies #-}
12module Rel8.Schema.Context.Nullify
13 ( Nullifiable( encodeTag, decodeTag, nullifier, unnullifier )
19import Control.Applicative ( empty )
20import Data.Foldable ( fold )
21import Data.Kind ( Constraint )
22import qualified Data.List.NonEmpty as NonEmpty
23import Data.Monoid ( First( First ), getFirst )
24import Prelude hiding ( null )
27import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
30import Rel8.Aggregate ( Aggregate, foldInputs, mapInputs )
31import Rel8.Expr ( Expr( Expr ) )
32import Rel8.Expr.Aggregate ( groupByExpr )
33import Rel8.Expr.Bool ( boolExpr )
34import Rel8.Expr.Null ( nullify, unsafeUnnullify )
35import Rel8.Expr.Opaleye ( fromPrimExpr, toPrimExpr )
36import Rel8.Kind.Labels ( KnownLabels, labelsSing, renderLabels )
37import Rel8.Kind.Necessity ( Necessity( Required ) )
38import Rel8.Schema.Context
39 ( Aggregation( Aggregation )
41 , Insertion( RequiredInsert, OptionalInsert )
44import Rel8.Schema.Nullability
45 ( Nullability( Nullable, NonNullable )
48import Rel8.Schema.Spec ( Context, Spec( Spec ), SSpec(..) )
49import Rel8.Type.Eq ( DBEq )
50import Rel8.Type.Monoid ( DBMonoid )
53type Nullifiable :: Context -> Constraint
54class Nullifiable context where
55 encodeTag :: (DBEq db, Nullabilizes db a, KnownLabels labels)
57 -> context ('Spec labels 'Required db a)
59 decodeTag :: (DBMonoid db, Nullabilizes db a)
60 => context ('Spec labels 'Required db a)
65 -> SSpec ('Spec labels necessity db a)
66 -> context ('Spec labels necessity db a)
67 -> context ('Spec labels necessity db (Maybe db))
71 -> SSpec ('Spec labels necessity db a)
72 -> context ('Spec labels necessity db (Maybe db))
73 -> context ('Spec labels necessity db a)
76instance Nullifiable Aggregation where
77 encodeTag = Aggregation . groupByExpr
78 decodeTag (Aggregation aggregate) = fold $ undoGroupBy aggregate
80 nullifier tag SSpec {nullability} (Aggregation aggregate) = Aggregation $
81 mapInputs (toPrimExpr . runTag nullability tag . fromPrimExpr) $
82 runTag nullability tag <$> aggregate
84 unnullifier _ SSpec {nullability} (Aggregation aggregate) =
85 Aggregation $ unnull nullability <$> aggregate
87 {-# INLINABLE encodeTag #-}
88 {-# INLINABLE decodeTag #-}
89 {-# INLINABLE nullifier #-}
90 {-# INLINABLE unnullifier #-}
93instance Nullifiable DB where
96 nullifier tag SSpec {nullability} (DB a) = DB $ runTag nullability tag a
97 unnullifier _ SSpec {nullability} (DB a) = DB $ unnull nullability a
99 {-# INLINABLE encodeTag #-}
100 {-# INLINABLE decodeTag #-}
101 {-# INLINABLE nullifier #-}
102 {-# INLINABLE unnullifier #-}
105instance Nullifiable Insertion where
106 encodeTag = RequiredInsert
107 decodeTag (RequiredInsert a) = a
109 nullifier tag SSpec {nullability} = \case
110 RequiredInsert a -> RequiredInsert $ runTag nullability tag a
111 OptionalInsert ma -> OptionalInsert $ runTag nullability tag <$> ma
113 unnullifier _ SSpec {nullability} = \case
114 RequiredInsert a -> RequiredInsert $ unnull nullability a
115 OptionalInsert ma -> OptionalInsert $ unnull nullability <$> ma
117 {-# INLINABLE encodeTag #-}
118 {-# INLINABLE decodeTag #-}
119 {-# INLINABLE nullifier #-}
120 {-# INLINABLE unnullifier #-}
123instance Nullifiable Name where
124 encodeTag _ = nameFromLabel
126 nullifier _ _ (Name name) = Name name
127 unnullifier _ _ (Name name) = Name name
129 {-# INLINABLE encodeTag #-}
130 {-# INLINABLE decodeTag #-}
131 {-# INLINABLE nullifier #-}
132 {-# INLINABLE unnullifier #-}
135type NullifiableEq :: Context -> Context -> Constraint
136class (a ~ b, Nullifiable b) => NullifiableEq a b
137instance (a ~ b, Nullifiable b) => NullifiableEq a b
140runTag :: Nullability db a -> Expr Bool -> Expr a -> Expr (Maybe db)
141runTag nullability tag a = case nullability of
142 Nullable -> boolExpr null a tag
143 NonNullable -> boolExpr null (nullify a) tag
145 null = Expr (Opaleye.ConstExpr Opaleye.NullLit)
148unnull :: Nullability db a -> Expr (Maybe db) -> Expr a
149unnull nullability a = case nullability of
151 NonNullable -> unsafeUnnullify a
155undoGroupBy :: Aggregate (Expr _a) -> Maybe (Expr a)
156undoGroupBy = getFirst . foldInputs go
158 go Nothing a = pure (Expr a)
162nameFromLabel :: forall labels necessity db a.
163 KnownLabels labels => Name ('Spec labels necessity db a)
164nameFromLabel = case labelsSing @labels of
165 labels -> Name (NonEmpty.last (renderLabels labels))
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list