1{-# language DataKinds #-}
2{-# language DisambiguateRecordFields #-}
3{-# language FlexibleContexts #-}
4{-# language FlexibleInstances #-}
5{-# language FunctionalDependencies #-}
6{-# language LambdaCase #-}
7{-# language NamedFieldPuns #-}
8{-# language StandaloneKindSignatures #-}
9{-# language TypeFamilies #-}
10{-# language TypeOperators #-}
11{-# language UndecidableInstances #-}
14 ( Table (Columns, Context)
15 , toColumns, fromColumns
21import Data.Functor ( ($>) )
22import Data.Functor.Identity ( Identity( Identity ) )
23import Data.Kind ( Constraint, Type )
24import Data.List.NonEmpty ( NonEmpty )
25import Prelude hiding ( null )
28import Rel8.Schema.Context ( Col(..) )
29import Rel8.Schema.Context.Label ( Labelable, labeler, unlabeler )
30import Rel8.Schema.HTable ( HTable )
31import Rel8.Schema.HTable.Either ( HEitherTable(..) )
32import Rel8.Schema.HTable.Identity ( HIdentity(..) )
33import Rel8.Schema.HTable.Label ( HLabel, hlabel, hunlabel )
34import Rel8.Schema.HTable.List ( HListTable )
35import Rel8.Schema.HTable.Maybe ( HMaybeTable(..) )
36import Rel8.Schema.HTable.NonEmpty ( HNonEmptyTable )
37import Rel8.Schema.HTable.Nullify ( hnulls, hnullify, hunnullify )
38import Rel8.Schema.HTable.Pair ( HPair(..) )
39import Rel8.Schema.HTable.Quartet ( HQuartet(..) )
40import Rel8.Schema.HTable.Quintet ( HQuintet(..) )
41import Rel8.Schema.HTable.These ( HTheseTable(..) )
42import Rel8.Schema.HTable.Trio ( HTrio(..) )
43import Rel8.Schema.HTable.Type ( HType( HType ) )
44import Rel8.Schema.HTable.Vectorize ( hvectorize, hunvectorize )
45import qualified Rel8.Schema.Kind as K
46import Rel8.Schema.Null ( Nullify, Nullity( Null, NotNull ), Sql )
47import Rel8.Schema.Spec ( Spec( Spec ), SSpec(..), KnownSpec )
48import Rel8.Type ( DBType )
49import Rel8.Type.Tag ( EitherTag( IsLeft, IsRight ), MaybeTag( IsJust ) )
52import Data.These ( These( This, That, These ) )
53import Data.These.Combinators ( justHere, justThere )
56-- | @Table@s are one of the foundational elements of Rel8, and describe data
57-- types that have a finite number of columns. Each of these columns contains
58-- data under a shared context, and contexts describe how to interpret the
59-- metadata about a column to a particular Haskell type. In Rel8, we have
60-- contexts for expressions (the 'Rel8.Expr' context), aggregations (the
61-- 'Rel8.Aggregate' context), insert values (the 'Rel8.Insert' contex), among
64-- In typical usage of Rel8 you don't need to derive instances of 'Table'
65-- yourself, as anything that's an instance of 'Rel8.Rel8able' is always a
67type Table :: K.Context -> Type -> Constraint
68class (HTable (Columns a), context ~ Context a) => Table context a | a -> context where
69 -- | The 'HTable' functor that describes the schema of this table.
70 type Columns a :: K.HTable
72 -- | The common context that all columns use as an interpretation.
73 type Context a :: K.Context
75 toColumns :: a -> Columns a (Col (Context a))
76 fromColumns :: Columns a (Col (Context a)) -> a
79-- | Any 'HTable' is also a 'Table'.
80instance HTable t => Table context (t (Col context)) where
81 type Columns (t (Col context)) = t
82 type Context (t (Col context)) = context
88-- | Any context is trivially a table.
89instance KnownSpec spec => Table context (Col context spec) where
90 type Columns (Col context spec) = HIdentity spec
91 type Context (Col context spec) = context
94 fromColumns = unHIdentity
97instance Sql DBType a => Table Identity (Identity a) where
98 type Columns (Identity a) = HType a
99 type Context (Identity a) = Identity
101 toColumns (Identity a) = HType (Result a)
102 fromColumns (HType (Result a)) = Identity a
105instance (Table Identity a, Table Identity b) => Table Identity (Either a b)
107 type Columns (Either a b) = HEitherTable (Columns a) (Columns b)
108 type Context (Either a b) = Identity
111 Left table -> HEitherTable
112 { htag = HIdentity (Result IsLeft)
113 , hleft = hlabel labeler (hnullify nullifier (toColumns table))
114 , hright = hlabel labeler (hnulls null)
116 Right table -> HEitherTable
117 { htag = HIdentity (Result IsRight)
118 , hleft = hlabel labeler (hnulls null)
119 , hright = hlabel labeler (hnullify nullifier (toColumns table))
122 fromColumns HEitherTable {htag, hleft, hright} = case htag of
123 HIdentity (Result tag) -> case tag of
124 IsLeft -> maybe err (Left . fromColumns) $ hunnullify unnullifier (hunlabel unlabeler hleft)
125 IsRight -> maybe err (Right . fromColumns) $ hunnullify unnullifier (hunlabel unlabeler hright)
127 err = error "Either.fromColumns: mismatch between tag and data"
130instance Table Identity a => Table Identity [a] where
131 type Columns [a] = HListTable (Columns a)
132 type Context [a] = Identity
134 toColumns = hvectorize vectorizer . fmap toColumns
135 fromColumns = fmap fromColumns . hunvectorize unvectorizer
138instance Table Identity a => Table Identity (Maybe a) where
139 type Columns (Maybe a) = HMaybeTable (Columns a)
140 type Context (Maybe a) = Identity
143 Nothing -> HMaybeTable
144 { htag = HIdentity (Result Nothing)
145 , hjust = hlabel labeler (hnulls null)
147 Just table -> HMaybeTable
148 { htag = HIdentity (Result (Just IsJust))
149 , hjust = hlabel labeler (hnullify nullifier (toColumns table))
152 fromColumns HMaybeTable {htag, hjust} = case htag of
153 HIdentity (Result tag) -> tag $>
154 case hunnullify unnullifier (hunlabel unlabeler hjust) of
155 Nothing -> error "Maybe.fromColumns: mismatch between tag and data"
156 Just just -> fromColumns just
159instance Table Identity a => Table Identity (NonEmpty a) where
160 type Columns (NonEmpty a) = HNonEmptyTable (Columns a)
161 type Context (NonEmpty a) = Identity
163 toColumns = hvectorize vectorizer . fmap toColumns
164 fromColumns = fmap fromColumns . hunvectorize unvectorizer
167instance (Table Identity a, Table Identity b) => Table Identity (These a b)
169 type Columns (These a b) = HTheseTable (Columns a) (Columns b)
170 type Context (These a b) = Identity
172 toColumns tables = HTheseTable
173 { hhereTag = relabel hhereTag
174 , hhere = hlabel labeler (hunlabel unlabeler (toColumns hhere))
175 , hthereTag = relabel hthereTag
176 , hthere = hlabel labeler (hunlabel unlabeler (toColumns hthere))
182 } = toColumns (justHere tables)
186 } = toColumns (justThere tables)
188 fromColumns HTheseTable {hhereTag, hhere, hthereTag, hthere} =
189 case (fromColumns mhere, fromColumns mthere) of
190 (Just a, Nothing) -> This (fromColumns a)
191 (Nothing, Just b) -> That (fromColumns b)
192 (Just a, Just b) -> These (fromColumns a) (fromColumns b)
193 _ -> error "These.fromColumns: mismatch between tags and data"
196 { htag = relabel hhereTag
197 , hjust = hlabel labeler (hunlabel unlabeler hhere)
200 { htag = relabel hthereTag
201 , hjust = hlabel labeler (hunlabel unlabeler hthere)
206 ( Table context a, Table context b
211 type Columns (a, b) =
213 (HLabel "fst" (Columns a))
214 (HLabel "snd" (Columns b))
215 type Context (a, b) = Context a
217 toColumns (a, b) = HPair
218 { hfst = hlabel labeler $ toColumns a
219 , hsnd = hlabel labeler $ toColumns b
221 fromColumns (HPair a b) =
222 ( fromColumns $ hunlabel unlabeler a
223 , fromColumns $ hunlabel unlabeler b
228 ( Table context a, Table context b, Table context c
230 ) => Table context (a, b, c)
232 type Columns (a, b, c) =
234 (HLabel "fst" (Columns a))
235 (HLabel "snd" (Columns b))
236 (HLabel "trd" (Columns c))
237 type Context (a, b, c) = Context a
239 toColumns (a, b, c) = HTrio
240 { hfst = hlabel labeler $ toColumns a
241 , hsnd = hlabel labeler $ toColumns b
242 , htrd = hlabel labeler $ toColumns c
244 fromColumns (HTrio a b c) =
245 ( fromColumns $ hunlabel unlabeler a
246 , fromColumns $ hunlabel unlabeler b
247 , fromColumns $ hunlabel unlabeler c
252 ( Table context a, Table context b, Table context c, Table context d
254 ) => Table context (a, b, c, d)
256 type Columns (a, b, c, d) =
258 (HLabel "fst" (Columns a))
259 (HLabel "snd" (Columns b))
260 (HLabel "trd" (Columns c))
261 (HLabel "frt" (Columns d))
262 type Context (a, b, c, d) = Context a
264 toColumns (a, b, c, d) = HQuartet
265 { hfst = hlabel labeler $ toColumns a
266 , hsnd = hlabel labeler $ toColumns b
267 , htrd = hlabel labeler $ toColumns c
268 , hfrt = hlabel labeler $ toColumns d
270 fromColumns (HQuartet a b c d) =
271 ( fromColumns $ hunlabel unlabeler a
272 , fromColumns $ hunlabel unlabeler b
273 , fromColumns $ hunlabel unlabeler c
274 , fromColumns $ hunlabel unlabeler d
279 ( Table context a, Table context b, Table context c, Table context d
282 ) => Table context (a, b, c, d, e)
284 type Columns (a, b, c, d, e) =
286 (HLabel "fst" (Columns a))
287 (HLabel "snd" (Columns b))
288 (HLabel "trd" (Columns c))
289 (HLabel "frt" (Columns d))
290 (HLabel "fft" (Columns e))
291 type Context (a, b, c, d, e) = Context a
293 toColumns (a, b, c, d, e) = HQuintet
294 { hfst = hlabel labeler $ toColumns a
295 , hsnd = hlabel labeler $ toColumns b
296 , htrd = hlabel labeler $ toColumns c
297 , hfrt = hlabel labeler $ toColumns d
298 , hfft = hlabel labeler $ toColumns e
300 fromColumns (HQuintet a b c d e) =
301 ( fromColumns $ hunlabel unlabeler a
302 , fromColumns $ hunlabel unlabeler b
303 , fromColumns $ hunlabel unlabeler c
304 , fromColumns $ hunlabel unlabeler d
305 , fromColumns $ hunlabel unlabeler e
309type Congruent :: Type -> Type -> Constraint
310class Columns a ~ Columns b => Congruent a b
311instance Columns a ~ Columns b => Congruent a b
314null :: Col Identity ('Spec labels necessity (Maybe a))
319 => SSpec ('Spec labels necessity a)
320 -> Col Identity ('Spec labels necessity a)
321 -> Col Identity ('Spec labels necessity (Nullify a))
322nullifier SSpec {nullity} (Result a) = Result $ case nullity of
328 => SSpec ('Spec labels necessity a)
329 -> Col Identity ('Spec labels necessity (Nullify a))
330 -> Maybe (Col Identity ('Spec labels necessity a))
331unnullifier SSpec {nullity} (Result a) =
333 Null -> pure $ Result a
334 NotNull -> Result <$> a
337vectorizer :: Functor f
338 => SSpec ('Spec labels necessity a)
339 -> f (Col Identity ('Spec labels necessity a))
340 -> Col Identity ('Spec labels necessity (f a))
341vectorizer _ = Result . fmap (\(Result a) -> a)
344unvectorizer :: Functor f
345 => SSpec ('Spec labels necessity a)
346 -> Col Identity ('Spec labels necessity (f a))
347 -> f (Col Identity ('Spec labels necessity a))
348unvectorizer _ (Result results) = Result <$> results
352 => HIdentity ('Spec labels necessity a) (Col Identity)
353 -> HIdentity ('Spec relabels necessity a) (Col Identity)
354relabel (HIdentity (Result a)) = HIdentity (Result a)
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