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.Result ( Result )
48import Rel8.Schema.Spec ( Spec( Spec ), SSpec(..), KnownSpec )
49import Rel8.Type ( DBType )
50import Rel8.Type.Tag ( EitherTag( IsLeft, IsRight ), MaybeTag( IsJust ) )
53import Data.These ( These( This, That, These ) )
54import Data.These.Combinators ( justHere, justThere )
57-- | @Table@s are one of the foundational elements of Rel8, and describe data
58-- types that have a finite number of columns. Each of these columns contains
59-- data under a shared context, and contexts describe how to interpret the
60-- metadata about a column to a particular Haskell type. In Rel8, we have
61-- contexts for expressions (the 'Rel8.Expr' context), aggregations (the
62-- 'Rel8.Aggregate' context), insert values (the 'Rel8.Insert' contex), among
65-- In typical usage of Rel8 you don't need to derive instances of 'Table'
66-- yourself, as anything that's an instance of 'Rel8.Rel8able' is always a
68type Table :: K.Context -> Type -> Constraint
69class (HTable (Columns a), context ~ Context a) => Table context a | a -> context where
70 -- | The 'HTable' functor that describes the schema of this table.
71 type Columns a :: K.HTable
73 -- | The common context that all columns use as an interpretation.
74 type Context a :: K.Context
76 toColumns :: a -> Columns a (Col (Context a))
77 fromColumns :: Columns a (Col (Context a)) -> a
80-- | Any 'HTable' is also a 'Table'.
81instance HTable t => Table context (t (Col context)) where
82 type Columns (t (Col context)) = t
83 type Context (t (Col context)) = context
89-- | Any context is trivially a table.
90instance KnownSpec spec => Table context (Col context spec) where
91 type Columns (Col context spec) = HIdentity spec
92 type Context (Col context spec) = context
95 fromColumns = unHIdentity
98instance Sql DBType a => Table Result (Identity a) where
99 type Columns (Identity a) = HType a
100 type Context (Identity a) = Result
102 toColumns (Identity a) = HType (Result a)
103 fromColumns (HType (Result a)) = Identity a
106instance (Table Result a, Table Result b) => Table Result (Either a b) where
107 type Columns (Either a b) = HEitherTable (Columns a) (Columns b)
108 type Context (Either a b) = Result
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 Result a => Table Result [a] where
131 type Columns [a] = HListTable (Columns a)
132 type Context [a] = Result
134 toColumns = hvectorize vectorizer . fmap toColumns
135 fromColumns = fmap fromColumns . hunvectorize unvectorizer
138instance Table Result a => Table Result (Maybe a) where
139 type Columns (Maybe a) = HMaybeTable (Columns a)
140 type Context (Maybe a) = Result
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 Result a => Table Result (NonEmpty a) where
160 type Columns (NonEmpty a) = HNonEmptyTable (Columns a)
161 type Context (NonEmpty a) = Result
163 toColumns = hvectorize vectorizer . fmap toColumns
164 fromColumns = fmap fromColumns . hunvectorize unvectorizer
167instance (Table Result a, Table Result b) => Table Result (These a b) where
168 type Columns (These a b) = HTheseTable (Columns a) (Columns b)
169 type Context (These a b) = Result
171 toColumns tables = HTheseTable
172 { hhereTag = relabel hhereTag
173 , hhere = hlabel labeler (hunlabel unlabeler (toColumns hhere))
174 , hthereTag = relabel hthereTag
175 , hthere = hlabel labeler (hunlabel unlabeler (toColumns hthere))
181 } = toColumns (justHere tables)
185 } = toColumns (justThere tables)
187 fromColumns HTheseTable {hhereTag, hhere, hthereTag, hthere} =
188 case (fromColumns mhere, fromColumns mthere) of
189 (Just a, Nothing) -> This (fromColumns a)
190 (Nothing, Just b) -> That (fromColumns b)
191 (Just a, Just b) -> These (fromColumns a) (fromColumns b)
192 _ -> error "These.fromColumns: mismatch between tags and data"
195 { htag = relabel hhereTag
196 , hjust = hlabel labeler (hunlabel unlabeler hhere)
199 { htag = relabel hthereTag
200 , hjust = hlabel labeler (hunlabel unlabeler hthere)
205 ( Table context a, Table context b
210 type Columns (a, b) =
212 (HLabel "fst" (Columns a))
213 (HLabel "snd" (Columns b))
214 type Context (a, b) = Context a
216 toColumns (a, b) = HPair
217 { hfst = hlabel labeler $ toColumns a
218 , hsnd = hlabel labeler $ toColumns b
220 fromColumns (HPair a b) =
221 ( fromColumns $ hunlabel unlabeler a
222 , fromColumns $ hunlabel unlabeler b
227 ( Table context a, Table context b, Table context c
229 ) => Table context (a, b, c)
231 type Columns (a, b, c) =
233 (HLabel "fst" (Columns a))
234 (HLabel "snd" (Columns b))
235 (HLabel "trd" (Columns c))
236 type Context (a, b, c) = Context a
238 toColumns (a, b, c) = HTrio
239 { hfst = hlabel labeler $ toColumns a
240 , hsnd = hlabel labeler $ toColumns b
241 , htrd = hlabel labeler $ toColumns c
243 fromColumns (HTrio a b c) =
244 ( fromColumns $ hunlabel unlabeler a
245 , fromColumns $ hunlabel unlabeler b
246 , fromColumns $ hunlabel unlabeler c
251 ( Table context a, Table context b, Table context c, Table context d
253 ) => Table context (a, b, c, d)
255 type Columns (a, b, c, d) =
257 (HLabel "fst" (Columns a))
258 (HLabel "snd" (Columns b))
259 (HLabel "trd" (Columns c))
260 (HLabel "frt" (Columns d))
261 type Context (a, b, c, d) = Context a
263 toColumns (a, b, c, d) = HQuartet
264 { hfst = hlabel labeler $ toColumns a
265 , hsnd = hlabel labeler $ toColumns b
266 , htrd = hlabel labeler $ toColumns c
267 , hfrt = hlabel labeler $ toColumns d
269 fromColumns (HQuartet a b c d) =
270 ( fromColumns $ hunlabel unlabeler a
271 , fromColumns $ hunlabel unlabeler b
272 , fromColumns $ hunlabel unlabeler c
273 , fromColumns $ hunlabel unlabeler d
278 ( Table context a, Table context b, Table context c, Table context d
281 ) => Table context (a, b, c, d, e)
283 type Columns (a, b, c, d, e) =
285 (HLabel "fst" (Columns a))
286 (HLabel "snd" (Columns b))
287 (HLabel "trd" (Columns c))
288 (HLabel "frt" (Columns d))
289 (HLabel "fft" (Columns e))
290 type Context (a, b, c, d, e) = Context a
292 toColumns (a, b, c, d, e) = HQuintet
293 { hfst = hlabel labeler $ toColumns a
294 , hsnd = hlabel labeler $ toColumns b
295 , htrd = hlabel labeler $ toColumns c
296 , hfrt = hlabel labeler $ toColumns d
297 , hfft = hlabel labeler $ toColumns e
299 fromColumns (HQuintet a b c d e) =
300 ( fromColumns $ hunlabel unlabeler a
301 , fromColumns $ hunlabel unlabeler b
302 , fromColumns $ hunlabel unlabeler c
303 , fromColumns $ hunlabel unlabeler d
304 , fromColumns $ hunlabel unlabeler e
308type Congruent :: Type -> Type -> Constraint
309class Columns a ~ Columns b => Congruent a b
310instance Columns a ~ Columns b => Congruent a b
313null :: Col Result ('Spec labels necessity (Maybe a))
318 => SSpec ('Spec labels necessity a)
319 -> Col Result ('Spec labels necessity a)
320 -> Col Result ('Spec labels necessity (Nullify a))
321nullifier SSpec {nullity} (Result a) = Result $ case nullity of
327 => SSpec ('Spec labels necessity a)
328 -> Col Result ('Spec labels necessity (Nullify a))
329 -> Maybe (Col Result ('Spec labels necessity a))
330unnullifier SSpec {nullity} (Result a) =
332 Null -> pure $ Result a
333 NotNull -> Result <$> a
336vectorizer :: Functor f
337 => SSpec ('Spec labels necessity a)
338 -> f (Col Result ('Spec labels necessity a))
339 -> Col Result ('Spec labels necessity (f a))
340vectorizer _ = Result . fmap (\(Result a) -> a)
343unvectorizer :: Functor f
344 => SSpec ('Spec labels necessity a)
345 -> Col Result ('Spec labels necessity (f a))
346 -> f (Col Result ('Spec labels necessity a))
347unvectorizer _ (Result results) = Result <$> results
351 => HIdentity ('Spec labels necessity a) (Col Result)
352 -> HIdentity ('Spec relabels necessity a) (Col Result)
353relabel (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