on da76712 help sign in
rel8/src/Rel8/Table/Null.hs
147 lines 4.8 kB history raw
1{-# language DataKinds #-}
2{-# language FlexibleContexts #-}
3{-# language FlexibleInstances #-}
4{-# language MultiParamTypeClasses #-}
5{-# language ScopedTypeVariables #-}
6{-# language StandaloneKindSignatures #-}
7{-# language TypeApplications #-}
8{-# language TypeFamilies #-}
9{-# language UndecidableInstances #-}
11module Rel8.Table.Null
12 ( NullTable(..)
13 , nullableTable, nullTable, nullifyTable, unsafeUnnullifyTable
14 , isNullTable, isNonNullTable
15 , nameNullTable
16 , toMaybeTable, toNullTable
17 )
18where
20-- base
21import Data.Kind ( Type )
22import Prelude hiding ( null, undefined )
24-- comonad
25import Control.Comonad ( extract )
27-- rel8
28import Rel8.Expr ( Expr )
29import Rel8.Expr.Bool ( not_ )
30import Rel8.Kind.Context ( Reifiable )
31import qualified Rel8.Schema.Kind as K
32import Rel8.Schema.Name ( Name )
33import Rel8.Table
34 ( Table, Columns, Context, fromColumns, toColumns
35 , FromExprs, fromResult, toResult
36 , Transpose
37 )
38import Rel8.Table.Alternative
39 ( AltTable, (<|>:)
40 , AlternativeTable, emptyTable
41 )
42import Rel8.Table.Bool ( bool )
43import Rel8.Table.Eq ( EqTable, eqTable )
44import Rel8.Table.Maybe ( MaybeTable, justTable, maybeTable, nothingTable )
45import Rel8.Table.Nullify ( Nullify, isNull )
46import Rel8.Table.Ord ( OrdTable, ordTable )
47import Rel8.Table.Projection ( Projectable, project )
48import Rel8.Table.Serialize ( ToExprs )
49import Rel8.Table.Undefined ( undefined )
52-- | @NullTable t@ is the table @t@, but where all the columns in @t@ have the
53-- possibility of being 'Rel8.null'. This is very similar to
54-- 'Rel8.MaybeTable', except that it does not use an extra tag field, so it
55-- cannot distinguish between @Nothing@ and @Just Nothing@ if nested. In other
56-- words, if all of the columns of the @t@ passed to @NullTable@ are already
57-- nullable, then @NullTable@ has no effect.
58type NullTable :: K.Context -> Type -> Type
59newtype NullTable context a = NullTable (Nullify context a)
62instance Projectable (NullTable context) where
63 project f (NullTable a) = NullTable (project f a)
66instance context ~ Expr => AltTable (NullTable context) where
67 ma <|>: mb = bool ma mb (isNullTable ma)
70instance context ~ Expr => AlternativeTable (NullTable context) where
71 emptyTable = nullTable
74instance (Table context a, Reifiable context, context ~ context') =>
75 Table context' (NullTable context a)
76 where
77 type Columns (NullTable context a) = Columns (Nullify context a)
78 type Context (NullTable context a) = Context (Nullify context a)
79 type FromExprs (NullTable context a) = FromExprs (Nullify context a)
80 type Transpose to (NullTable context a) = NullTable to (Transpose to a)
82 toColumns (NullTable a) = toColumns a
83 fromColumns = NullTable . fromColumns
85 toResult = toResult @_ @(Nullify context a)
86 fromResult = fromResult @_ @(Nullify context a)
89instance (EqTable a, context ~ Expr) => EqTable (NullTable context a) where
90 eqTable = eqTable @(Nullify context a)
93instance (OrdTable a, context ~ Expr) => OrdTable (NullTable context a) where
94 ordTable = ordTable @(Nullify context a)
97instance (ToExprs exprs a, context ~ Expr) =>
98 ToExprs (NullTable context exprs) (Maybe a)
101-- | Check if any of the non-nullable fields of @a@ are 'Rel8.null' under the
102-- 'NullTable'. Returns 'Rel8.false' if @a@ has no non-nullable fields.
103isNullTable :: Table Expr a => NullTable Expr a -> Expr Bool
104isNullTable (NullTable a) = isNull a
107-- | The inverse of 'isNullTable'.
108isNonNullTable :: Table Expr a => NullTable Expr a -> Expr Bool
109isNonNullTable = not_ . isNullTable
112-- | Like 'Rel8.nullable'.
113nullableTable :: (Table Expr a, Table Expr b)
114 => b -> (a -> b) -> NullTable Expr a -> b
115nullableTable b f ma@(NullTable a) = bool (f (extract a)) b (isNullTable ma)
118-- | The null table. Like 'Rel8.null'.
119nullTable :: Table Expr a => NullTable Expr a
120nullTable = NullTable (pure undefined)
123-- | Lift any table into 'NullTable'. Like 'Rel8.nullify'.
124nullifyTable :: a -> NullTable Expr a
125nullifyTable = NullTable . pure
128unsafeUnnullifyTable :: NullTable Expr a -> a
129unsafeUnnullifyTable (NullTable a) = extract a
132-- | Construct a 'NullTable' in the 'Name' context. This can be useful if you
133-- have a 'NullTable' that you are storing in a table and need to construct a
134-- 'TableSchema'.
135nameNullTable :: a -> NullTable Name a
136nameNullTable = NullTable . pure
139-- | Convert a 'NullTable' to a 'MaybeTable'.
140toMaybeTable :: Table Expr a => NullTable Expr a -> MaybeTable Expr a
141toMaybeTable = nullableTable nothingTable justTable
144-- | Convert a 'MaybeTable' to a 'NullTable'. Note that if the underlying @a@
145-- has no non-nullable fields, this is a lossy conversion.
146toNullTable :: Table Expr a => MaybeTable Expr a -> NullTable Expr a
147toNullTable = maybeTable nullTable nullifyTable