on be54907 help sign in
.github/workflows/build.yaml+3−3
since splitsnapshots
unifiedsplit
@@ -9,14 +9,14 @@ jobs:
9 persist-credentials: false
9 persist-credentials: false
10 submodules: true
10 submodules: true
11
11
12− - uses: cachix/install-nix-action@v14.1
12+ - uses: cachix/install-nix-action@v12
13 with:
13 with:
14 nix_path: nixpkgs=channel:nixos-unstable
14 nix_path: nixpkgs=channel:nixos-unstable
15 extra_nix_config: |
15 extra_nix_config: |
16 trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=
16 trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=
17− substituters = https://cache.nixos.org/ https://cache.iog.io
17+ substituters = https://cache.nixos.org/ https://hydra.iohk.io
18
18
19− - uses: cachix/cachix-action@v10
19+ - uses: cachix/cachix-action@v8
20 with:
20 with:
21 name: rel8
21 name: rel8
22 authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
22 authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
Changelog.md+1−128
@@ -1,140 +1,13 @@
1−# 1.4.0.0 (2002-08-17)
1+# 1.1.0.0 (??)
2
2
3## Breaking changes
3## Breaking changes
4
4
5−* The behavior of `greatest`/`least` has been corrected, and was previously flipped. ([#183](https://github.com/circuithub/rel8/pull/183))
6−
7−## New features
8−
9−* `NullTable`/`HNull` have been added. This is an alternative to `MaybeTable` that doesn't use a tag columns. It's less flexible (no `Functor` or `Applicative` instance) and is meaningless when used with a table that has no non-nullable columns (so nesting `NullTable` is redundant). But in situations where the underlying `Table` does have non-nullable columns, it can losslessly converted to and from `MaybeTable`. It is useful for embedding into a base table when you don't want to store the extra tag column in your schema. ([#173](https://github.com/circuithub/rel8/pull/173))
10−* Add `fromMaybeTable`. ([#179](https://github.com/circuithub/rel8/pull/179))
11−* Add `alignMaybeTable`. ([#196](https://github.com/circuithub/rel8/pull/196))
12−
13−## Improvements
14−
15−* Optimize implementation of `AltTable` for `Tabulation` ([#178](https://github.com/circuithub/rel8/pull/178))
16−
17−## Other
18−
19−* Documentation improvements for `HADT`. ([#177](https://github.com/circuithub/rel8/pull/177))
20−* Document example usage of `groupBy`. ([#184](https://github.com/circuithub/rel8/pull/184))
21−* Build with and require Opaleye >= 0.9.3.3. ([#190](https://github.com/circuithub/rel8/pull/190))
22−* Build with `hasql` 1.6. ([#195](https://github.com/circuithub/rel8/pull/195))
23−
24−# 1.3.1.0 (2022-01-20)
25−
26−## Other
27−
28−* Rel8 now requires Opaleye >= 0.9.1. ([#165](https://github.com/circuithub/rel8/pull/165))
29−
30−# 1.3.0.0 (2022-01-31)
31−
32−## Breaking changes
33−
34−* `div` and `mod` have been changed to match Haskell semantics. If you need the PostgreSQL `div()` and `mod()` functions, use `quot` and `rem`. While this is not an API change, we feel this is a breaking change in semantics and have bumped the major version number. ([#155](https://github.com/circuithub/rel8/pull/155))
35−
36−## New features
37−
38−* `divMod` and `quotRem` functions have been added, matching Haskell's `Prelude` functions. ([#155](https://github.com/circuithub/rel8/pull/155))
39−* `avg` and `mode` aggregation functions to find the mean value of an expression, or the most common row in a query, respectively. ([#152](https://github.com/circuithub/rel8/pull/152))
40−* The full `EqTable` and `OrdTable` classes have been exported, allowing for instances to be manually created. ([#157](https://github.com/circuithub/rel8/pull/157))
41−* Added `like` and `ilike` (for the `LIKE` and `ILIKE` operators). ([#146](https://github.com/circuithub/rel8/pull/146))
42−
43−## Other
44−
45−* Rel8 now requires Opaleye 0.9. ([#158](https://github.com/circuithub/rel8/pull/158))
46−* Rel8's test suite supports Hedgehog 1.1. ([#160](https://github.com/circuithub/rel8/pull/160))
47−* The documentation for binary operations has been corrected. ([#162](https://github.com/circuithub/rel8/pull/162))
48−
49−# 1.2.2.0 (2021-11-21)
50−
51−## Other
52−
53−* Support GHC 9.2 ([#145](https://github.com/circuithub/rel8/pull/145))
54−* Correct the documentation for `except` ([#147](https://github.com/circuithub/rel8/pull/147))
55−* Support `hasql` 1.5 ([#149](https://github.com/circuithub/rel8/pull/149))
56−
57−# 1.2.1.0 (2021-11-21)
58−
59−## New features
60−
61−* `castTable` has been added, which casts all columns selected from in `Query` according to the types of columns. This can occasionally be useful when using `many`/`some` on older PostgreSQL versions. ([#137](https://github.com/circuithub/rel8/pull/137))
62−
63−* Added `<:`, `<=:`, `>:`, `>=:`, `greatest` and `least`, which sort all columns in a table lexicographically. These operators are like the `<.` operators which operate on `Expr`s, but the `<:` operate on entire tables. ([#139](https://github.com/circuithub/rel8/pull/139))
64−
65−## Other
66−
67−* Support opaleye-0.8 ([#142](https://github.com/circuithub/rel8/pull/142))
68−
69−# 1.2.0.0 (2021-10-22)
70−
71−## New features
72−
73−* New `$*` and `$+` operators for projecting out of `ListTable` and `NonEmptyTable` respectively (analogous to the existing `$?` for `MaybeTable`). ([#125](https://github.com/circuithub/rel8/pull/125))
74−
75−## Bug fixes
76−
77−* Fix `UPSERT` support (and add tests), which was broken due to a typo inside Rel8 that made it impossible to construct `Projection`s which are needed by `UPSERT`. ([#134](https://github.com/circuithub/rel8/pull/134))
78−
79−* Remove `DBMin` and `DBMax` instances for `Bool`, which are invalid as far as Postgres is concerned. `and` and `or` can be used to achieve the same thing. ([#126](https://github.com/circuithub/rel8/pull/126))
80−
81−* Fix `aggregateMaybeTable`, `aggregateEitherTable` and `aggregateTheseTable`, which generated invalid SQL previously. ([#127](https://github.com/circuithub/rel8/pull/127))
82−
83−## Breaking changes
84−
85−* `rebind` now takes an additional argument for the "name" of the binding. ([#128](https://github.com/circuithub/rel8/pull/128))
86−
87−# 1.1.0.0 (2021-07-16)
88−
89−## New features
90−
91−* You can derive `Rel8able` for "vanilla" higher-kinded data types - data types that don't use the `Column` type family. For example, the following is now possible:
92−
93− ```haskell
94− data MyTable f = MyTable
95− { myTableX :: f Int32
96− , myTableY :: f Text
97− } deriving (Generic, Rel8able)
98− ```
99−
100−* The `Projectable` and `Biprojectable` type classes have been introduced. These classes model a type of functors and bifunctors (respectively) on tables, where the mapping function is only able to rearrange columns. For example, the following is now possible:
101−
102− ```haskell
103− x <- project myTableX <$> many ...
104− ```
105−
106−* `Insert`'s `onConflict` field now has a new option - `DoUpdate`. This maps to PostgreSQL's `ON CONFLICT DO UPDATE` syntax, which provides upsert support. ([#85](https://github.com/circuithub/rel8/pull/85))
107−
108−* `Insert`, `Update` and `Delete` has all been expanded to work with `Query`s. In particular:
109−
110− * `Delete` now supports a `USING` sub-query
111− * `Update` now supports a `FROM` sub-query
112− * `Insert` can delete the result of any arbitrary `Query` (providing the types match)
113−
114−* The new `Rel8.Tabulate` module has been added, which gives a `Map`-esque interface to writing and composing queries. ([#70](https://github.com/circuithub/rel8/pull/70))
115−
116−* The new `indexed` `Query -> Query` function was added. This function augments each row in a query with it's 0-based index. ([#117](https://github.com/circuithub/rel8/pull/117))
117−
118−## Breaking changes
119−
120−* `Insert`, `Delete` and `Update` have all changed. In particular, for `Insert` users should now replace `rows = xs` with `rows = values xs`. ([#85](https://github.com/circuithub/rel8/pull/85))
121−
122* Rename `whereExists` and `whereNotExists` to `present` and `absent` respectively. ([#57](https://github.com/circuithub/rel8/pull/57))
5* Rename `whereExists` and `whereNotExists` to `present` and `absent` respectively. ([#57](https://github.com/circuithub/rel8/pull/57))
123
6
124* Simplify `evaluate` to run directly inside the `Query` monad, rendering the `Evaluate` monad unnecessary. ([#56](https://github.com/circuithub/rel8/pull/56))
7* Simplify `evaluate` to run directly inside the `Query` monad, rendering the `Evaluate` monad unnecessary. ([#56](https://github.com/circuithub/rel8/pull/56))
125
8
126* The `Labelable` type class has been removed as it's no longer necessary. This class was mostly internal, though was visible in some public API functions. ([#76](https://github.com/circuithub/rel8/pull/76))
9* The `Labelable` type class has been removed as it's no longer necessary. This class was mostly internal, though was visible in some public API functions. ([#76](https://github.com/circuithub/rel8/pull/76))
127
10
128−* `EitherTable`, `ListTable`, `MaybeTable`, `NonEmptyTable` and `TheseTable` now all have an extra parameter which tracks the context of the table. If you manually specified any types before, you need to provide this parameter - usually `Expr` will be the correct choice. ([#101](https://github.com/circuithub/rel8/pull/101))
129−
130−* We've done a lot of work to simplify the internals of Rel8, but some of these are breaking changes. However, most of these API changes shouldn't affect users as they are mostly types used in type inference, or affect classes where users don't need to define their own instances.
131−
132− * The kind of a `Rel8able` is now `(Type -> Type) -> Type`. Previously it was `(X -> Type) -> Type`.
133− * `Table` has a new associated type - `FromExprs`. This was previously an open type family.
134− * `Table` has a new associated type - `Transpose` - and `Recontextualise` has been renamed to `Transposes`. This `Transposes` class now operates in terms of `Transpose`.
135−
136−* `select`, `insert`, `update` and `delete` now produce Hasql `Statement`s, rather than actually running the statement as IO. This allows Rel8 to be used with transaction/connection-managing monads like [`hasql-transaction`](https://hackage.haskell.org/package/hasql-transaction). ([#94](https://github.com/circuithub/rel8/pull/94))
137−
138## Bug fixes
11## Bug fixes
139
12
140* Fixes a bug where cartesian products of queries using `catListTable`, `catNonEmptyTable`, `catList` and `catNonEmpty` would incorrectly be zipped instead. ([#61](https://github.com/circuithub/rel8/pull/61))
13* Fixes a bug where cartesian products of queries using `catListTable`, `catNonEmptyTable`, `catList` and `catNonEmpty` would incorrectly be zipped instead. ([#61](https://github.com/circuithub/rel8/pull/61))
README.md−4
@@ -10,8 +10,4 @@ The main objectives of Rel8 are:
10
10
11* *Familiar*: writing Rel8 queries should feel like normal Haskell programming.
11* *Familiar*: writing Rel8 queries should feel like normal Haskell programming.
12
12
13−Rel8 was presented at ZuriHac 2021. If you want to have a brief overview of what Rel8 is, and a tour of the API - check out the video below:
14−
15−[![Rel8 presentation at ZuriHac 2021](https://img.youtube.com/vi/3uwrtjxiq6E/hqdefault.jpg)](http://www.youtube.com/watch?v=3uwrtjxiq6E)
16−
17For more details, check out the [official documentation](https://rel8.readthedocs.io/en/latest/).
13For more details, check out the [official documentation](https://rel8.readthedocs.io/en/latest/).
cabal.project+5
@@ -1 +1,6 @@
1packages: .
1packages: .
2+
3+allow-newer: generic-monoid:base
4+allow-newer: cryptohash-sha1:base
5+allow-newer: cryptohash-md5:base
6+allow-newer: entropy:Cabal
cabal.project.haskell-nix+6
@@ -2,3 +2,9 @@
2-- will interpret them as local packages, and try to build them when we cabal
2-- will interpret them as local packages, and try to build them when we cabal
3-- build. The only reason we have to specify these is for Haskell.nix to know to
3-- build. The only reason we have to specify these is for Haskell.nix to know to
4-- override these packages by fetching them rather than using Hackage.
4-- override these packages by fetching them rather than using Hackage.
5+
6+source-repository-package
7+ type: git
8+ location: git://github.com/jcpetruzza/barbies
9+ tag: f99b05454874192e3511bd133555dfb6cc6a6ecb
10+ --sha256: 0yy2i2jbllwavv5d2176rf8lmm4l1ws90lxkmdlfgvfzqxidx0gi
default.nix+2−2
@@ -1,11 +1,11 @@
1let
1let
2 haskellNix = import (import ./nix/sources.nix)."haskell.nix" {};
2 haskellNix = import (import ./nix/sources.nix)."haskell.nix" {};
3
3
4− nixpkgsSrc = haskellNix.sources.nixpkgs-unstable;
4+ nixpkgsSrc = haskellNix.sources.nixpkgs-2009;
5
5
6 nixpkgsArgs = haskellNix.nixpkgsArgs;
6 nixpkgsArgs = haskellNix.nixpkgsArgs;
7
7
8− compiler-nix-name = "ghc924";
8+ compiler-nix-name = "ghc901";
9
9
10 pkgs = import nixpkgsSrc nixpkgsArgs;
10 pkgs = import nixpkgsSrc nixpkgsArgs;
11
11
docs/concepts/insert.rst+10−37
@@ -21,16 +21,9 @@ using ``delete``. ``Delete`` takes:
21``from``
21``from``
22 The ``TableSchema`` for the table to delete rows from.
22 The ``TableSchema`` for the table to delete rows from.
23
23
24−``using``
25− This is a simple ``Query`` that forms the ``USING`` clause of the ``DELETE``
26− statement. This can be used to join against other tables, and the results
27− can be referenced in the ``deleteWhere`` parameter. For simple ``DELETE``\s
28− where you don't need to do this, you can set ``using = pure ()``.
29−
30``deleteWhere``
24``deleteWhere``
31 The ``WHERE`` clause of the ``DELETE`` statement. This is a function that
25 The ``WHERE`` clause of the ``DELETE`` statement. This is a function that
32− takes two inputs: the result of the ``using`` query, and the current value
26+ takes a single ``Expr`` table as input.
33− of the row.
34
27
35``returning``
28``returning``
36 What to return - see :ref:`returning`.
29 What to return - see :ref:`returning`.
@@ -44,23 +37,16 @@ using ``update``. ``Update`` takes:
44``target``
37``target``
45 The ``TableSchema`` for the table to update rows in.
38 The ``TableSchema`` for the table to update rows in.
46
39
47−``from``
40+``updateWhere``
48− This is a simple ``Query`` that forms the ``FROM`` clause of the ``UPDATE``
41+ The ``WHERE`` clause of the ``UPDATE`` statement. This is a function that
49− statement. This can be used to join against other tables, and the results
42+ takes a single ``Expr`` table as input.
50− can be referenced in the ``set`` and ``updateWhere`` parameters. For simple
51− ``UPDATE``\s where you don't need to do this, you can set ``from = pure ()``.
52
43
53``set``
44``set``
54 A row to row transformation function, indicating how to update selected rows.
45 A row to row transformation function, indicating how to update selected rows.
55 This function takes rows of the same shape as ``target`` but in the ``Expr``
46 This function takes rows of the same shape as ``target`` but in the ``Expr``
56 context. One way to write this function is to use record update syntax::
47 context. One way to write this function is to use record update syntax::
57
48
58− set = \from row -> row { rowName = "new name" }
49+ set = \row -> row { rowName = "new name" }
59−
60−``updateWhere``
61− The ``WHERE`` clause of the ``UPDATE`` statement. This is a function that
62− takes two inputs: the result of the ``from`` query, and the current value of
63− the row.
64
50
65``returning``
51``returning``
66 What to return - see :ref:`returning`.
52 What to return - see :ref:`returning`.
@@ -78,11 +64,11 @@ using ``insert``. ``Insert`` takes:
78 The rows to insert. These are the same as ``into``, but in the ``Expr``
64 The rows to insert. These are the same as ``into``, but in the ``Expr``
79 context. You can construct rows from their individual fields::
65 context. You can construct rows from their individual fields::
80
66
81− rows = values [ MyTable { myTableA = lit "A", myTableB = lit 42 }
67+ rows = [ MyTable { myTableA = lit "A", myTableB = lit 42 }
82
68
83 or you can use ``lit`` on a table value in the ``Result`` context::
69 or you can use ``lit`` on a table value in the ``Result`` context::
84
70
85− rows = values [ lit MyTable { myTableA = "A", myTableB = 42 }
71+ rows = [ lit MyTable { myTableA = "A", myTableB = 42 }
86
72
87``onConflict``
73``onConflict``
88 What should happen if an insert clashes with rows that already exist. This
74 What should happen if an insert clashes with rows that already exist. This
@@ -94,10 +80,6 @@ using ``insert``. ``Insert`` takes:
94 ``DoNothing``
80 ``DoNothing``
95 PostgreSQL should not insert the duplicate rows.
81 PostgreSQL should not insert the duplicate rows.
96
82
97− ``DoUpdate``
98− PostgreSQL should instead try to update any existing rows that conflict
99− with rows proposed for insertion.
100−
101``returning``
83``returning``
102 What to return - see :ref:`returning`.
84 What to return - see :ref:`returning`.
103
85
@@ -117,20 +99,11 @@ For example, if we are inserting orders, we might want the order ids returned::
117
99
118 insert Insert
100 insert Insert
119 { into = orderSchema
101 { into = orderSchema
120− , rows = values [ order ]
102+ , rows = [ order ]
121 , onConflict = Abort
103 , onConflict = Abort
122 , returning = Projection orderId
104 , returning = Projection orderId
123 }
105 }
124
106
125−If we don't want to return anything, we can use ``pure ()``::
126−
127− insert Insert
128− { into = orderSchema
129− , rows = values [ order ]
130− , onConflict = Abort
131− , returning = pure ()
132− }
133−
134Default values
107Default values
135--------------
108--------------
136
109
@@ -146,7 +119,7 @@ construct the ``DEFAULT`` expression::
146
119
147 insert Insert
120 insert Insert
148 { into = orderSchema
121 { into = orderSchema
149− , rows = values [ Order { orderId = unsafeDefault, ... } ]
122+ , rows = [ Order { orderId = unsafeDefault, ... } ]
150 , onConflict = Abort
123 , onConflict = Abort
151 , returning = Projection orderId
124 , returning = Projection orderId
152 }
125 }
@@ -175,7 +148,7 @@ them in Rel8, rather than in your database schema.
175
148
176 insert Insert
149 insert Insert
177 { into = orderSchema
150 { into = orderSchema
178− , rows = values [ Order { orderId = nextval "order_id_seq", ... } ]
151+ , rows = [ Order { orderId = nextval "order_id_seq", ... } ]
179 , onConflict = Abort
152 , onConflict = Abort
180 , returning = Projection orderId
153 , returning = Projection orderId
181 }
154 }
docs/cookbook.rst+7−9
@@ -142,25 +142,23 @@ rows, but can also return *tree*\s.
142To understand what this means, we'll consider a small example query for blog
142To understand what this means, we'll consider a small example query for blog
143posts. We want our query to return:
143posts. We want our query to return:
144
144
145−1. The latest 5 blog posts that have at least one tag each.
145+1. The latest 5 blog posts.
1462. For each blog post, all tags.
1462. For each blog post, all tags.
147−3. For each blog post, the latest 3 comments if they exist.
147+3. For each blog post, the latest 3 comments.
148
148
149In Rel8, we can write this query as::
149In Rel8, we can write this query as::
150
150
151 latestBlogPosts = do
151 latestBlogPosts = do
152 post <- each postSchema
152 post <- each postSchema
153
153
154− -- Returns a `NonEmptyTable a` which ends up as a `Data.List.NonEmpty a` after the query is run
155− tags <- some $ do
154+ tags <- aggregate do
156 tag <- each tagSchema
155 tag <- each tagSchema
157 where_ (tagPostId tag ==. postId post)
156 where_ (tagPostId tag ==. postId post)
158− return (tagName tag)
157+ return (listAgg (tagName tag))
159
158
160− -- Returns a `ListTable a` which ends up as a `[a]` after the query is run
161− latestComments <-
159+ latestComments <-
162− many $
160+ many $
163− limit 3 $
161+ limit 3 $
164 orderBy (commentCreatedAt >$< desc) do
162 orderBy (commentCreatedAt >$< desc) do
165 comment <- each commentSchema
163 comment <- each commentSchema
166 where_ (commentPostId comment ==. postId post)
164 where_ (commentPostId comment ==. postId post)
nix/sources.json+9−9
@@ -5,10 +5,10 @@
5 "homepage": "https://input-output-hk.github.io/haskell.nix",
5 "homepage": "https://input-output-hk.github.io/haskell.nix",
6 "owner": "input-output-hk",
6 "owner": "input-output-hk",
7 "repo": "haskell.nix",
7 "repo": "haskell.nix",
8− "rev": "0837156c56cb5350dd9bd84eb424187e00aa1e8a",
8+ "rev": "3856d2d24dca0ecc71fcfc314253a2a2d07a3c4f",
9− "sha256": "1djmv5a0vfj78csw2cad6nicrs8iqrp928b9b3v4h7lwwhhzliwl",
9+ "sha256": "0s69nasqhkv8n0qmdv075k83p3z584ja9vkzdnp2291mymghvx87",
10 "type": "tarball",
10 "type": "tarball",
11− "url": "https://github.com/input-output-hk/haskell.nix/archive/0837156c56cb5350dd9bd84eb424187e00aa1e8a.tar.gz",
11+ "url": "https://github.com/input-output-hk/haskell.nix/archive/3856d2d24dca0ecc71fcfc314253a2a2d07a3c4f.tar.gz",
12 "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
12 "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
13 },
13 },
14 "niv": {
14 "niv": {
@@ -17,10 +17,10 @@
17 "homepage": "https://github.com/nmattia/niv",
17 "homepage": "https://github.com/nmattia/niv",
18 "owner": "nmattia",
18 "owner": "nmattia",
19 "repo": "niv",
19 "repo": "niv",
20− "rev": "acdb1726783637852c01e0ad639ac9cbec28d8c8",
20+ "rev": "e0ca65c81a2d7a4d82a189f1e23a48d59ad42070",
21− "sha256": "1wszl8q70z6wfgkh2dvgmhhry6qp9nar421qq2ifd17hq2jj9ck3",
21+ "sha256": "1pq9nh1d8nn3xvbdny8fafzw87mj7gsmp6pxkdl65w2g18rmcmzx",
22 "type": "tarball",
22 "type": "tarball",
23− "url": "https://github.com/nmattia/niv/archive/acdb1726783637852c01e0ad639ac9cbec28d8c8.tar.gz",
23+ "url": "https://github.com/nmattia/niv/archive/e0ca65c81a2d7a4d82a189f1e23a48d59ad42070.tar.gz",
24 "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
24 "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
25 },
25 },
26 "nixpkgs": {
26 "nixpkgs": {
@@ -29,10 +29,10 @@
29 "homepage": null,
29 "homepage": null,
30 "owner": "nixos",
30 "owner": "nixos",
31 "repo": "nixpkgs",
31 "repo": "nixpkgs",
32− "rev": "1c1f5649bb9c1b0d98637c8c365228f57126f361",
32+ "rev": "59b8d9cf24e9fcf10341a0923c9bdca088dca8c8",
33− "sha256": "0f2nvdijyxfgl5kwyb4465pppd5vkhqxddx6v40k2s0z9jfhj0xl",
33+ "sha256": "08f38v4b2kcxnbapdwrb54bglka92cxj9qlnqlk5px206jyq9v4c",
34 "type": "tarball",
34 "type": "tarball",
35− "url": "https://github.com/nixos/nixpkgs/archive/1c1f5649bb9c1b0d98637c8c365228f57126f361.tar.gz",
35+ "url": "https://github.com/nixos/nixpkgs/archive/59b8d9cf24e9fcf10341a0923c9bdca088dca8c8.tar.gz",
36 "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
36 "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
37 }
37 }
38}
38}
nix/sources.nix+1−21
@@ -31,28 +31,8 @@ let
31 if spec ? branch then "refs/heads/${spec.branch}" else
31 if spec ? branch then "refs/heads/${spec.branch}" else
32 if spec ? tag then "refs/tags/${spec.tag}" else
32 if spec ? tag then "refs/tags/${spec.tag}" else
33 abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
33 abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
34− submodules = if spec ? submodules then spec.submodules else false;
35− submoduleArg =
36− let
37− nixSupportsSubmodules = builtins.compareVersions builtins.nixVersion "2.4" >= 0;
38− emptyArgWithWarning =
39− if submodules == true
40− then
41− builtins.trace
42− (
43− "The niv input \"${name}\" uses submodules "
44− + "but your nix's (${builtins.nixVersion}) builtins.fetchGit "
45− + "does not support them"
46− )
47− {}
48− else {};
49− in
50− if nixSupportsSubmodules
51− then { inherit submodules; }
52− else emptyArgWithWarning;
53 in
34 in
54− builtins.fetchGit
55− ({ url = spec.repo; inherit (spec) rev; inherit ref; } // submoduleArg);
35+ builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; };
56
36
57 fetch_local = spec: spec.path;
37 fetch_local = spec: spec.path;
58
38
rel8.cabal+15−33
@@ -1,6 +1,6 @@
1cabal-version: 2.0
1cabal-version: 2.0
2name: rel8
2name: rel8
3−version: 1.4.0.0
3+version: 1.0.0.1
4synopsis: Hey! Hey! Can u rel8?
4synopsis: Hey! Hey! Can u rel8?
5license: BSD3
5license: BSD3
6license-file: LICENSE
6license-file: LICENSE
@@ -20,33 +20,29 @@ source-repository head
20library
20library
21 build-depends:
21 build-depends:
22 aeson
22 aeson
23− , base ^>= 4.14 || ^>=4.15 || ^>=4.16
23+ , base ^>= 4.14 || ^>=4.15
24− , bifunctors
25 , bytestring
24 , bytestring
26 , case-insensitive
25 , case-insensitive
27 , comonad
26 , comonad
28 , contravariant
27 , contravariant
29− , hasql ^>= 1.4.5.1 || ^>= 1.5.0.0 || ^>= 1.6.0.0
28+ , hasql ^>= 1.4.5.1
30− , opaleye ^>= 0.9.6.1
29+ , opaleye ^>= 0.7.3.0
31− , pretty
32 , profunctors
30 , profunctors
33− , product-profunctors
34 , scientific
31 , scientific
35 , semialign
32 , semialign
36 , semigroupoids
33 , semigroupoids
37 , text
34 , text
38 , these
35 , these
39 , time
36 , time
37+ , transformers
40 , uuid
38 , uuid
41 default-language:
39 default-language:
42 Haskell2010
40 Haskell2010
43 ghc-options:
41 ghc-options:
44− -Werror=missing-methods -Werror=incomplete-patterns -Werror=missing-fields
45 -Weverything -Wno-unsafe -Wno-safe -Wno-missing-safe-haskell-mode
42 -Weverything -Wno-unsafe -Wno-safe -Wno-missing-safe-haskell-mode
46 -Wno-missing-import-lists -Wno-prepositive-qualified-module
43 -Wno-missing-import-lists -Wno-prepositive-qualified-module
47 -Wno-monomorphism-restriction
44 -Wno-monomorphism-restriction
48 -Wno-missing-local-signatures
45 -Wno-missing-local-signatures
49− -Wno-missing-kind-signatures
50 hs-source-dirs:
46 hs-source-dirs:
51 src
47 src
52 exposed-modules:
48 exposed-modules:
@@ -54,7 +50,6 @@ library
54 Rel8.Expr.Num
50 Rel8.Expr.Num
55 Rel8.Expr.Text
51 Rel8.Expr.Text
56 Rel8.Expr.Time
52 Rel8.Expr.Time
57− Rel8.Tabulate
58
53
59 other-modules:
54 other-modules:
60 Rel8.Aggregate
55 Rel8.Aggregate
@@ -66,7 +61,6 @@ library
66 Rel8.Column.List
61 Rel8.Column.List
67 Rel8.Column.Maybe
62 Rel8.Column.Maybe
68 Rel8.Column.NonEmpty
63 Rel8.Column.NonEmpty
69− Rel8.Column.Null
70 Rel8.Column.These
64 Rel8.Column.These
71
65
72 Rel8.Expr
66 Rel8.Expr
@@ -82,18 +76,19 @@ library
82 Rel8.Expr.Order
76 Rel8.Expr.Order
83 Rel8.Expr.Sequence
77 Rel8.Expr.Sequence
84 Rel8.Expr.Serialize
78 Rel8.Expr.Serialize
85− Rel8.Expr.Window
86
79
87 Rel8.FCF
80 Rel8.FCF
88
81
89 Rel8.Kind.Algebra
82 Rel8.Kind.Algebra
90 Rel8.Kind.Context
83 Rel8.Kind.Context
91
84
85+ Rel8.Generic.Coherence
92 Rel8.Generic.Construction
86 Rel8.Generic.Construction
93 Rel8.Generic.Construction.ADT
87 Rel8.Generic.Construction.ADT
94 Rel8.Generic.Construction.Record
88 Rel8.Generic.Construction.Record
95 Rel8.Generic.Map
89 Rel8.Generic.Map
96 Rel8.Generic.Record
90 Rel8.Generic.Record
91+ Rel8.Generic.Reify
97 Rel8.Generic.Rel8able
92 Rel8.Generic.Rel8able
98 Rel8.Generic.Table
93 Rel8.Generic.Table
99 Rel8.Generic.Table.ADT
94 Rel8.Generic.Table.ADT
@@ -109,23 +104,21 @@ library
109 Rel8.Query.Evaluate
104 Rel8.Query.Evaluate
110 Rel8.Query.Exists
105 Rel8.Query.Exists
111 Rel8.Query.Filter
106 Rel8.Query.Filter
112− Rel8.Query.Indexed
113 Rel8.Query.Limit
107 Rel8.Query.Limit
114 Rel8.Query.List
108 Rel8.Query.List
115 Rel8.Query.Maybe
109 Rel8.Query.Maybe
116 Rel8.Query.Null
110 Rel8.Query.Null
117 Rel8.Query.Opaleye
111 Rel8.Query.Opaleye
118 Rel8.Query.Order
112 Rel8.Query.Order
119− Rel8.Query.Rebind
120 Rel8.Query.Set
113 Rel8.Query.Set
121 Rel8.Query.SQL
114 Rel8.Query.SQL
122 Rel8.Query.These
115 Rel8.Query.These
123 Rel8.Query.Values
116 Rel8.Query.Values
124− Rel8.Query.Window
125
117
118+ Rel8.Schema.Context
119+ Rel8.Schema.Context.Abstract
126 Rel8.Schema.Context.Nullify
120 Rel8.Schema.Context.Nullify
127 Rel8.Schema.Dict
121 Rel8.Schema.Dict
128− Rel8.Schema.Field
129 Rel8.Schema.HTable
122 Rel8.Schema.HTable
130 Rel8.Schema.HTable.Either
123 Rel8.Schema.HTable.Either
131 Rel8.Schema.HTable.Identity
124 Rel8.Schema.HTable.Identity
@@ -141,28 +134,24 @@ library
141 Rel8.Schema.Kind
134 Rel8.Schema.Kind
142 Rel8.Schema.Name
135 Rel8.Schema.Name
143 Rel8.Schema.Null
136 Rel8.Schema.Null
137+ Rel8.Schema.Reify
144 Rel8.Schema.Result
138 Rel8.Schema.Result
145 Rel8.Schema.Spec
139 Rel8.Schema.Spec
140+ Rel8.Schema.Spec.Constrain
146 Rel8.Schema.Table
141 Rel8.Schema.Table
147
142
148 Rel8.Statement.Delete
143 Rel8.Statement.Delete
149 Rel8.Statement.Insert
144 Rel8.Statement.Insert
150− Rel8.Statement.OnConflict
151 Rel8.Statement.Returning
145 Rel8.Statement.Returning
152 Rel8.Statement.Select
146 Rel8.Statement.Select
153− Rel8.Statement.Set
154− Rel8.Statement.SQL
155 Rel8.Statement.Update
147 Rel8.Statement.Update
156− Rel8.Statement.Using
157 Rel8.Statement.View
148 Rel8.Statement.View
158− Rel8.Statement.Where
159
149
160 Rel8.Table
150 Rel8.Table
161 Rel8.Table.ADT
151 Rel8.Table.ADT
162 Rel8.Table.Aggregate
152 Rel8.Table.Aggregate
163 Rel8.Table.Alternative
153 Rel8.Table.Alternative
164 Rel8.Table.Bool
154 Rel8.Table.Bool
165− Rel8.Table.Cols
166 Rel8.Table.Either
155 Rel8.Table.Either
167 Rel8.Table.Eq
156 Rel8.Table.Eq
168 Rel8.Table.HKD
157 Rel8.Table.HKD
@@ -170,18 +159,15 @@ library
170 Rel8.Table.Maybe
159 Rel8.Table.Maybe
171 Rel8.Table.Name
160 Rel8.Table.Name
172 Rel8.Table.NonEmpty
161 Rel8.Table.NonEmpty
173− Rel8.Table.Null
174 Rel8.Table.Nullify
162 Rel8.Table.Nullify
175 Rel8.Table.Opaleye
163 Rel8.Table.Opaleye
176 Rel8.Table.Ord
164 Rel8.Table.Ord
177 Rel8.Table.Order
165 Rel8.Table.Order
178− Rel8.Table.Projection
166+ Rel8.Table.Recontextualize
179 Rel8.Table.Rel8able
167 Rel8.Table.Rel8able
180 Rel8.Table.Serialize
168 Rel8.Table.Serialize
181 Rel8.Table.These
169 Rel8.Table.These
182− Rel8.Table.Transpose
183 Rel8.Table.Undefined
170 Rel8.Table.Undefined
184− Rel8.Table.Window
185
171
186 Rel8.Type
172 Rel8.Type
187 Rel8.Type.Array
173 Rel8.Type.Array
@@ -200,9 +186,6 @@ library
200 Rel8.Type.Sum
186 Rel8.Type.Sum
201 Rel8.Type.Tag
187 Rel8.Type.Tag
202
188
203− Rel8.Window
204−
205−
206test-suite tests
189test-suite tests
207 type: exitcode-stdio-1.0
190 type: exitcode-stdio-1.0
208 build-depends:
191 build-depends:
@@ -211,9 +194,9 @@ test-suite tests
211 , case-insensitive
194 , case-insensitive
212 , containers
195 , containers
213 , hasql
196 , hasql
214− , hasql-transaction
215− , hedgehog ^>= 1.0 || ^>= 1.1
197+ , hedgehog ^>=1.0.2
216− , mmorph
198+ , lifted-base ^>=0.2.3.12
199+ , monad-control ^>=1.0.2.3
217 , rel8
200 , rel8
218 , scientific
201 , scientific
219 , tasty
202 , tasty
@@ -221,7 +204,6 @@ test-suite tests
221 , text
204 , text
222 , time
205 , time
223 , tmp-postgres ^>=1.34.1.0
206 , tmp-postgres ^>=1.34.1.0
224− , transformers
225 , uuid
207 , uuid
226
208
227 other-modules:
209 other-modules:
shell.nix+1−1
@@ -1,6 +1,6 @@
1let
1let
2 sources = import ./nix/sources.nix;
2 sources = import ./nix/sources.nix;
3− pkgs = import sources.nixpkgs {overlays = [];};
3+ pkgs = import sources.nixpkgs {};
4 hsPkgs = import ./default.nix;
4 hsPkgs = import ./default.nix;
5in
5in
6 hsPkgs.shellFor {
6 hsPkgs.shellFor {
src/Rel8.hs+15−298
@@ -38,27 +38,24 @@ module Rel8
38 , HMaybe
38 , HMaybe
39 , HList
39 , HList
40 , HNonEmpty
40 , HNonEmpty
41− , HNull
42 , HThese
41 , HThese
43 , Lift
42 , Lift
44
43
45 , Table(..)
44 , Table(..)
46 , HTable
45 , HTable
47− , Transposes
46+ , Recontextualize
48 , AltTable((<|>:))
47 , AltTable((<|>:))
49 , AlternativeTable( emptyTable )
48 , AlternativeTable( emptyTable )
50− , EqTable(..), (==:), (/=:)
49+ , EqTable, (==:), (/=:)
51− , OrdTable(..), (<:), (<=:), (>:), (>=:), ascTable, descTable, greatest, least
50+ , OrdTable, ascTable, descTable
52 , lit
51 , lit
53 , bool
52 , bool
54 , case_
53 , case_
55− , castTable
56
54
57 -- ** @MaybeTable@
55 -- ** @MaybeTable@
58 , MaybeTable
56 , MaybeTable
59 , maybeTable, ($?), nothingTable, justTable
57 , maybeTable, ($?), nothingTable, justTable
60 , isNothingTable, isJustTable
58 , isNothingTable, isJustTable
61− , fromMaybeTable
62 , optional
59 , optional
63 , catMaybeTable
60 , catMaybeTable
64 , traverseMaybeTable
61 , traverseMaybeTable
@@ -81,7 +78,6 @@ module Rel8
81 , isThisTable, isThatTable, isThoseTable
78 , isThisTable, isThatTable, isThoseTable
82 , hasHereTable, hasThereTable
79 , hasHereTable, hasThereTable
83 , justHereTable, justThereTable
80 , justHereTable, justThereTable
84− , alignMaybeTable
85 , alignBy
81 , alignBy
86 , keepHereTable, loseHereTable
82 , keepHereTable, loseHereTable
87 , keepThereTable, loseThereTable
83 , keepThereTable, loseThereTable
@@ -94,7 +90,7 @@ module Rel8
94
90
95 -- ** @ListTable@
91 -- ** @ListTable@
96 , ListTable
92 , ListTable
97− , listTable, ($*)
93+ , listTable
98 , nameListTable
94 , nameListTable
99 , many
95 , many
100 , manyExpr
96 , manyExpr
@@ -103,44 +99,21 @@ module Rel8
103
99
104 -- ** @NonEmptyTable@
100 -- ** @NonEmptyTable@
105 , NonEmptyTable
101 , NonEmptyTable
106− , nonEmptyTable, ($+)
102+ , nonEmptyTable
107 , nameNonEmptyTable
103 , nameNonEmptyTable
108 , some
104 , some
109 , someExpr
105 , someExpr
110 , catNonEmptyTable
106 , catNonEmptyTable
111 , catNonEmpty
107 , catNonEmpty
112
108
113− -- ** @NullTable@
109+ -- ** @ADT@
114− , NullTable
115− , nullableTable, nullTable, nullifyTable
116− , isNullTable, isNonNullTable
117− , catNullTable
118− , nameNullTable
119− , toNullTable, toMaybeTable
120−
121− -- ** Algebraic data types / sum types
122− -- $adts
123−
124− -- *** Naming of ADTs
125− -- $naming
126− , NameADT, nameADT
127 , ADT, ADTable
110 , ADT, ADTable
128−
129− -- *** Deconstruction of ADTs
130− -- $deconstruction
131− , DeconstructADT, deconstructADT
132−
133− -- *** Construction of ADTs
134− -- $construction
135 , BuildADT, buildADT
111 , BuildADT, buildADT
136 , ConstructADT, constructADT
112 , ConstructADT, constructADT
137−
113+ , DeconstructADT, deconstructADT
138− -- *** Other ADT operations
114+ , NameADT, nameADT
139 , AggregateADT, aggregateADT
115 , AggregateADT, aggregateADT
140
116
141− -- *** Miscellaneous notes
142− -- $misc-notes
143−
144 -- ** @HKD@
117 -- ** @HKD@
145 , HKD, HKDable
118 , HKD, HKDable
146 , BuildHKD, buildHKD
119 , BuildHKD, buildHKD
@@ -165,7 +138,6 @@ module Rel8
165 -- ** @null@
138 -- ** @null@
166 , NotNull
139 , NotNull
167 , Nullable
140 , Nullable
168− , Homonullable
169 , null
141 , null
170 , nullify
142 , nullify
171 , nullable
143 , nullable
@@ -184,7 +156,6 @@ module Rel8
184 , (==.), (/=.), (==?), (/=?)
156 , (==.), (/=.), (==?), (/=?)
185 , in_
157 , in_
186 , boolExpr, caseExpr
158 , boolExpr, caseExpr
187− , like, ilike
188
159
189 -- ** Ordering
160 -- ** Ordering
190 , DBOrd
161 , DBOrd
@@ -202,13 +173,6 @@ module Rel8
202 , Query
173 , Query
203 , showQuery
174 , showQuery
204
175
205− -- ** Projection
206− , Projection
207− , Projectable( project )
208− , Biprojectable( biproject )
209− , Projecting
210− , Field
211−
212 -- ** Selecting rows
176 -- ** Selecting rows
213 , Selects
177 , Selects
214 , each
178 , each
@@ -253,11 +217,10 @@ module Rel8
253 , countRows
217 , countRows
254 , groupBy
218 , groupBy
255 , listAgg, listAggExpr
219 , listAgg, listAggExpr
256− , mode
257 , nonEmptyAgg, nonEmptyAggExpr
220 , nonEmptyAgg, nonEmptyAggExpr
258 , DBMax, max
221 , DBMax, max
259 , DBMin, min
222 , DBMin, min
260− , DBSum, sum, sumWhere, avg
223+ , DBSum, sum, sumWhere
261 , DBString, stringAgg
224 , DBString, stringAgg
262 , count
225 , count
263 , countStar
226 , countStar
@@ -274,35 +237,10 @@ module Rel8
274 , nullsFirst
237 , nullsFirst
275 , nullsLast
238 , nullsLast
276
239
277− -- ** Window functions
278− , Window
279− , window
280− , Partition
281− , over
282− , partitionBy
283− , orderPartitionBy
284− , cumulative
285− , cumulative_
286− , currentRow
287− , rowNumber
288− , rank
289− , denseRank
290− , percentRank
291− , cumeDist
292− , ntile
293− , lag
294− , lead
295− , firstValue
296− , lastValue
297− , nthValue
298− , indexed
299−
300− -- ** Bindings
301− , rebind
302−
303 -- * IO
240 -- * IO
304 , Serializable
241 , Serializable
305− , ToExprs
242+ , ToExprs(..)
243+ , FromExprs
306 , Result
244 , Result
307
245
308 -- * Running statements
246 -- * Running statements
@@ -314,31 +252,29 @@ module Rel8
314 -- ** @INSERT@
252 -- ** @INSERT@
315 , Insert(..)
253 , Insert(..)
316 , OnConflict(..)
254 , OnConflict(..)
317− , Upsert(..)
318 , insert
255 , insert
319 , unsafeDefault
256 , unsafeDefault
320− , showInsert
321
257
322 -- ** @DELETE@
258 -- ** @DELETE@
323 , Delete(..)
259 , Delete(..)
324 , delete
260 , delete
325− , showDelete
326
261
327 -- ** @UPDATE@
262 -- ** @UPDATE@
328 , Update(..)
263 , Update(..)
329 , update
264 , update
330− , showUpdate
331
265
332 -- ** @.. RETURNING@
266 -- ** @.. RETURNING@
333 , Returning(..)
267 , Returning(..)
334
268
335 -- ** @CREATE VIEW@
269 -- ** @CREATE VIEW@
336 , createView
270 , createView
337− , createOrReplaceView
338
271
339 -- ** Sequences
272 -- ** Sequences
340 , nextval
273 , nextval
341 , evaluate
274 , evaluate
275+
276+ -- * Implementation details
277+ , HKDT(..)
342 ) where
278 ) where
343
279
344-- base
280-- base
@@ -353,7 +289,6 @@ import Rel8.Column.Lift
353import Rel8.Column.List
289import Rel8.Column.List
354import Rel8.Column.Maybe
290import Rel8.Column.Maybe
355import Rel8.Column.NonEmpty
291import Rel8.Column.NonEmpty
356−import Rel8.Column.Null
357import Rel8.Column.These
292import Rel8.Column.These
358import Rel8.Expr
293import Rel8.Expr
359import Rel8.Expr.Aggregate
294import Rel8.Expr.Aggregate
@@ -367,8 +302,6 @@ import Rel8.Expr.Ord
367import Rel8.Expr.Order
302import Rel8.Expr.Order
368import Rel8.Expr.Serialize
303import Rel8.Expr.Serialize
369import Rel8.Expr.Sequence
304import Rel8.Expr.Sequence
370−import Rel8.Expr.Text ( like, ilike )
371−import Rel8.Expr.Window hiding ( cumulative )
372import Rel8.Generic.Rel8able ( KRel8able, Rel8able )
305import Rel8.Generic.Rel8able ( KRel8able, Rel8able )
373import Rel8.Order
306import Rel8.Order
374import Rel8.Query
307import Rel8.Query
@@ -379,19 +312,15 @@ import Rel8.Query.Either
379import Rel8.Query.Evaluate
312import Rel8.Query.Evaluate
380import Rel8.Query.Exists
313import Rel8.Query.Exists
381import Rel8.Query.Filter
314import Rel8.Query.Filter
382−import Rel8.Query.Indexed
383import Rel8.Query.Limit
315import Rel8.Query.Limit
384import Rel8.Query.List
316import Rel8.Query.List
385import Rel8.Query.Maybe
317import Rel8.Query.Maybe
386import Rel8.Query.Null
318import Rel8.Query.Null
387import Rel8.Query.Order
319import Rel8.Query.Order
388−import Rel8.Query.Rebind
389import Rel8.Query.SQL (showQuery)
320import Rel8.Query.SQL (showQuery)
390import Rel8.Query.Set
321import Rel8.Query.Set
391import Rel8.Query.These
322import Rel8.Query.These
392import Rel8.Query.Values
323import Rel8.Query.Values
393−import Rel8.Query.Window
394−import Rel8.Schema.Field
395import Rel8.Schema.HTable
324import Rel8.Schema.HTable
396import Rel8.Schema.Name
325import Rel8.Schema.Name
397import Rel8.Schema.Null hiding ( nullable )
326import Rel8.Schema.Null hiding ( nullable )
@@ -399,10 +328,8 @@ import Rel8.Schema.Result ( Result )
399import Rel8.Schema.Table
328import Rel8.Schema.Table
400import Rel8.Statement.Delete
329import Rel8.Statement.Delete
401import Rel8.Statement.Insert
330import Rel8.Statement.Insert
402−import Rel8.Statement.OnConflict
403import Rel8.Statement.Returning
331import Rel8.Statement.Returning
404import Rel8.Statement.Select
332import Rel8.Statement.Select
405−import Rel8.Statement.SQL
406import Rel8.Statement.Update
333import Rel8.Statement.Update
407import Rel8.Statement.View
334import Rel8.Statement.View
408import Rel8.Table
335import Rel8.Table
@@ -417,16 +344,12 @@ import Rel8.Table.List
417import Rel8.Table.Maybe
344import Rel8.Table.Maybe
418import Rel8.Table.Name
345import Rel8.Table.Name
419import Rel8.Table.NonEmpty
346import Rel8.Table.NonEmpty
420−import Rel8.Table.Null
421−import Rel8.Table.Opaleye ( castTable )
422import Rel8.Table.Ord
347import Rel8.Table.Ord
423import Rel8.Table.Order
348import Rel8.Table.Order
424−import Rel8.Table.Projection
349+import Rel8.Table.Recontextualize
425import Rel8.Table.Rel8able ()
350import Rel8.Table.Rel8able ()
426import Rel8.Table.Serialize
351import Rel8.Table.Serialize
427import Rel8.Table.These
352import Rel8.Table.These
428−import Rel8.Table.Transpose
429−import Rel8.Table.Window
430import Rel8.Type
353import Rel8.Type
431import Rel8.Type.Composite
354import Rel8.Type.Composite
432import Rel8.Type.Eq
355import Rel8.Type.Eq
@@ -441,7 +364,6 @@ import Rel8.Type.ReadShow
441import Rel8.Type.Semigroup
364import Rel8.Type.Semigroup
442import Rel8.Type.String
365import Rel8.Type.String
443import Rel8.Type.Sum
366import Rel8.Type.Sum
444−import Rel8.Window
445
367
446
368
447-- $running
369-- $running
@@ -449,208 +371,3 @@ import Rel8.Window
449-- provides 'select', 'insert', 'update' and 'delete' functions. Note that
371-- provides 'select', 'insert', 'update' and 'delete' functions. Note that
450-- 'insert', 'update' and 'delete' will generally need the
372-- 'insert', 'update' and 'delete' will generally need the
451-- `DuplicateRecordFields` language extension enabled.
373-- `DuplicateRecordFields` language extension enabled.
452−
453−-- $adts
454−-- Algebraic data types can be modelled between Haskell and SQL.
455−--
456−-- * Your SQL table needs a certain text field that tags which Haskell constructor is in use.
457−-- * You have to use a few combinators to specify the sum type's individual constructors.
458−-- * If you want to do case analysis at the @Expr@ (SQL) level, you can use 'maybe'/'either'-like eliminators.
459−--
460−-- The documentation in this section will assume a set of database types like this:
461−--
462−-- @
463−-- data Thing f = ThingEmployer (Employer f) | ThingPotato (Potato f) | Nullary
464−-- deriving stock Generic
465−--
466−-- data Employer f = Employer { employerId :: f Int32, employerName :: f Text}
467−-- deriving stock Generic
468−-- deriving anyclass Rel8able
469−--
470−-- data Potato f = Potato { size :: f Int32, grower :: f Text }
471−-- deriving stock Generic
472−-- deriving anyclass Rel8able
473−-- @
474−
475−-- $naming
476−--
477−-- First, in your 'TableSchema', name your type like this:
478−--
479−-- @
480−-- thingSchema :: TableSchema (ADT Thing Name)
481−-- thingSchema =
482−-- TableSchema
483−-- { schema = Nothing,
484−-- name = \"thing\",
485−-- columns =
486−-- nameADT @Thing
487−-- \"tag\"
488−-- Employer
489−-- { employerName = \"name\",
490−-- employerId = \"id\"
491−-- }
492−-- Potato {size = \"size\", grower = \"Mary\"}
493−-- }
494−-- @
495−--
496−-- Note that @nameADT \@Thing "tag"@ is variadic: it accepts one
497−-- argument per constructor, except the nullary ones (Nullary) because
498−-- there's nothing to do for them.
499−
500−-- $deconstruction
501−--
502−-- To deconstruct sum types at the SQL level, use 'deconstructADT',
503−-- which is also variadic, and has one argument for each
504−-- constructor. Similar to 'maybe'.
505−--
506−-- @
507−-- query :: Query (ADT Thing Expr)
508−-- query = do
509−-- thingExpr <- each thingSchema
510−-- where_ $
511−-- deconstructADT @Thing
512−-- (\employer -> employerName employer ==. lit \"Mary\")
513−-- (\potato -> grower potato ==. lit \"Mary\")
514−-- (lit False) -- Nullary case
515−-- thingExpr
516−-- pure thingExpr
517−-- @
518−--
519−-- SQL output:
520−--
521−-- @
522−-- SELECT
523−-- CAST("tag0_1" AS text) as "tag",
524−-- CAST("id1_1" AS int4) as "ThingEmployer/_1/employerId",
525−-- CAST("name2_1" AS text) as "ThingEmployer/_1/employerName",
526−-- CAST("size3_1" AS int4) as "ThingPotato/_1/size",
527−-- CAST("Mary4_1" AS text) as "ThingPotato/_1/grower"
528−-- FROM (SELECT
529−-- *
530−-- FROM (SELECT
531−-- "tag" as "tag0_1",
532−-- "id" as "id1_1",
533−-- "name" as "name2_1",
534−-- "size" as "size3_1",
535−-- "Mary" as "Mary4_1"
536−-- FROM "thing" as "T1") as "T1"
537−-- WHERE (CASE WHEN ("tag0_1") = (CAST(E'ThingPotato' AS text)) THEN ("Mary4_1") = (CAST(E'Mary' AS text))
538−-- WHEN ("tag0_1") = (CAST(E'Nullary' AS text)) THEN CAST(FALSE AS bool) ELSE ("name2_1") = (CAST(E'Mary' AS text)) END)) as "T1"
539−-- @
540−
541−-- $construction
542−--
543−-- To construct an ADT, you can use 'buildADT' or 'constructADT'. Consider the following type:
544−--
545−-- @
546−-- data Task f = Pending | Complete (CompletedTask f)
547−-- @
548−--
549−-- 'buildADT' is for constructing values of 'Task' in the 'Expr'
550−-- context. 'buildADT' needs two type-level arguments before its type
551−-- makes any sense. The first argument is the type of the "ADT", which
552−-- in our case is 'Task'. The second is the name of the constructor we
553−-- want to use. So that means we have the following possible
554−-- instantiations of 'buildADT' for 'Task':
555−--
556−-- @
557−-- > :t buildADT @Task @\"Pending\"
558−-- buildADT @Task @\"Pending\" :: ADT Task Expr
559−-- > :t buildADT @Task @\"Complete\"
560−-- buildADT @Task @\"Complete\" :: CompletedTask Expr -> ADT Task Expr
561−-- @
562−--
563−-- Note that as the "Pending" constructor has no fields, @buildADT
564−-- \@Task \@"Pending"@ is equivalent to @lit Pending@. But @buildADT
565−-- \@Task \@"Complete"@ is not the same as @lit . Complete@:
566−--
567−-- @
568−-- > :t lit . Complete
569−-- lit . Complete :: CompletedTask Result -> ADT Task Expr
570−-- @
571−--
572−--
573−-- Note that the former takes a @CompletedTask Expr@ while the latter
574−-- takes a @CompletedTask Result@. The former is more powerful because
575−-- you can construct @Task@s using dynamic values coming a database
576−-- query.
577−--
578−-- To show what this can look like in SQL, consider:
579−--
580−-- @
581−-- > :{
582−-- showQuery $ values
583−-- [ buildADT @Task @\"Pending\"
584−-- , buildADT @Task @\"Complete\" CompletedTask {date = Rel8.Expr.Time.now}
585−-- ]
586−-- :}
587−-- @
588−--
589−-- This produces the following SQL:
590−--
591−-- @
592−-- SELECT
593−-- CAST(\"values0_1\" AS text) as \"tag\",
594−-- CAST(\"values1_1\" AS timestamptz) as \"Complete/_1/date\"
595−-- FROM (SELECT
596−-- *
597−-- FROM (SELECT \"column1\" as \"values0_1\",
598−-- \"column2\" as \"values1_1\"
599−-- FROM
600−-- (VALUES
601−-- (CAST(E'Pending' AS text),CAST(NULL AS timestamptz)),
602−-- (CAST(E'Complete' AS text),CAST(now() AS timestamptz))) as \"V\") as \"T1\") as \"T1\"
603−-- @
604−--
605−-- This is what you get if you run it in @psql@:
606−--
607−--
608−-- @
609−-- tag | Complete/_1/date
610−-- ----------+-------------------------------
611−-- Pending |
612−-- Complete | 2022-05-19 21:28:23.969065+00
613−-- (2 rows)
614−-- @
615−--
616−-- "constructADT" is less convenient but more general alternative to
617−-- "buildADT". It requires only one type-level argument for its type
618−-- to make sense:
619−--
620−-- @
621−-- > :t constructADT @Task
622−-- constructADT @Task
623−-- :: (forall r. r -> (CompletedTask Expr -> r) -> r) -> ADT Task Expr
624−-- @
625−--
626−-- This might still seem a bit opaque, but basically it gives you a
627−-- Church-encoded constructor for arbitrary algebraic data types. You
628−-- might use it as follows:
629−--
630−-- @
631−-- let
632−-- pending :: ADT Task Expr
633−-- pending = constructADT @Task $ \pending _complete -> pending
634−--
635−-- complete :: ADT Task Expr
636−-- complete = constructADT @Task $ \_pending complete -> complete CompletedTask {date = Rel8.Expr.Time.now}
637−-- @
638−--
639−-- These values are otherwise identical to the ones we saw above with
640−-- @buildADT@, it's just a different style of constructing them.
641−--
642−
643−-- $misc-notes
644−--
645−-- 1. Note that the order of the arguments for all of these functions
646−-- is determined by the order of the constructors in the data
647−-- definition. If it were @data Task = Complete (CompletedTask f) |
648−-- Pending@ then the order of all the invocations of @constructADT@
649−-- and @deconstructADT@ would need to change.
650−--
651−-- 2. Maybe this is obvious, but just to spell it out: once you're in
652−-- the @Result@ context, you can of course construct @Task@ values
653−-- normally and use standard Haskell pattern-matching. @constructADT@
654−-- and @deconstructADT@ are specifically only needed in the @Expr@
655−-- context, and they allow you to do the equivalent of pattern
656−-- matching in PostgreSQL.
src/Rel8/Aggregate.hs+105−37
@@ -1,83 +1,151 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2+{-# language DerivingVia #-}
2{-# language FlexibleContexts #-}
3{-# language FlexibleContexts #-}
3{-# language FlexibleInstances #-}
4{-# language FlexibleInstances #-}
5+{-# language GADTs #-}
4{-# language MultiParamTypeClasses #-}
6{-# language MultiParamTypeClasses #-}
5−{-# language RankNTypes #-}
7+{-# language NamedFieldPuns #-}
8+{-# language PolyKinds #-}
6{-# language StandaloneKindSignatures #-}
9{-# language StandaloneKindSignatures #-}
7{-# language TypeFamilies #-}
10{-# language TypeFamilies #-}
8{-# language UndecidableInstances #-}
11{-# language UndecidableInstances #-}
12+{-# language UndecidableSuperClasses #-}
9
13
10module Rel8.Aggregate
14module Rel8.Aggregate
11− ( Aggregate(..), zipOutputs
15+ ( Aggregate(..), foldInputs, mapInputs
12− , unsafeMakeAggregate
16+ , Aggregator(..), unsafeMakeAggregate
13 , Aggregates
17 , Aggregates
18+ , Col( A, unA )
14 )
19 )
15where
20where
16
21
17-- base
22-- base
18−import Control.Applicative ( liftA2 )
23+import Data.Functor.Const ( Const( Const ), getConst )
19−import Data.Functor.Identity ( Identity( Identity ) )
24+import Data.Functor.Identity ( Identity )
20import Data.Kind ( Constraint, Type )
25import Data.Kind ( Constraint, Type )
21import Prelude
26import Prelude
22
27
23−-- profunctors
24−import Data.Profunctor ( dimap )
25−
26-- opaleye
28-- opaleye
27−import qualified Opaleye.Aggregate as Opaleye
29+import qualified Opaleye.Internal.Aggregate as Opaleye
28import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
30import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
29−import qualified Opaleye.Internal.Column as Opaleye
31+import qualified Opaleye.Internal.PackMap as Opaleye
30
32
31-- rel8
33-- rel8
32import Rel8.Expr ( Expr )
34import Rel8.Expr ( Expr )
35+import Rel8.Schema.Context ( Interpretation(..) )
33−import Rel8.Schema.HTable.Identity ( HIdentity(..) )
36+import Rel8.Schema.HTable.Identity ( HIdentity(..), HType )
34−import qualified Rel8.Schema.Kind as K
37+import Rel8.Schema.Name ( Name )
35import Rel8.Schema.Null ( Sql )
38import Rel8.Schema.Null ( Sql )
39+import Rel8.Schema.Reify ( notReify )
40+import Rel8.Schema.Result ( Result )
41+import Rel8.Schema.Spec ( Spec( Spec ) )
36import Rel8.Table
42import Rel8.Table
37 ( Table, Columns, Context, fromColumns, toColumns
43 ( Table, Columns, Context, fromColumns, toColumns
38− , FromExprs, fromResult, toResult
44+ , reify, unreify, coherence, congruence
39− , Transpose
40 )
45 )
41−import Rel8.Table.Transpose ( Transposes )
46+import Rel8.Table.Recontextualize ( Recontextualize )
42import Rel8.Type ( DBType )
47import Rel8.Type ( DBType )
43
48
44
49
45−-- | 'Aggregate' is a special context used by 'Rel8.aggregate'.
50+-- | An @Aggregate a@ describes how to aggregate @Table@s of type @a@. You can
51+-- unpack an @Aggregate@ back to @a@ by running it with 'Rel8.aggregate'. As
52+-- @Aggregate@ is almost an 'Applicative' functor - but there is no 'pure'
53+-- operation. This means 'Aggregate' is an instance of 'Apply', and you can
54+-- combine @Aggregate@s using the @<.>@ combinator.
46−type Aggregate :: K.Context
55+type Aggregate :: k -> Type
56+data Aggregate a where
47−newtype Aggregate a = Aggregate (Opaleye.Aggregator () (Expr a))
57+ Aggregate :: !(Opaleye.Aggregator () (Expr a)) -> Aggregate a
58+
59+
60+instance Interpretation Aggregate where
61+ data Col Aggregate _spec where
62+ A :: ()
63+ => { unA :: !(Aggregate a) }
64+ -> Col Aggregate ('Spec a)
48
65
49
66
50instance Sql DBType a => Table Aggregate (Aggregate a) where
67instance Sql DBType a => Table Aggregate (Aggregate a) where
51− type Columns (Aggregate a) = HIdentity a
68+ type Columns (Aggregate a) = HType a
52 type Context (Aggregate a) = Aggregate
69 type Context (Aggregate a) = Aggregate
53− type FromExprs (Aggregate a) = a
54− type Transpose to (Aggregate a) = to a
55
70
56− toColumns = HIdentity
71+ toColumns = HIdentity . A
57− fromColumns (HIdentity a) = a
72+ fromColumns (HIdentity (A a)) = a
58− toResult = HIdentity . Identity
73+
59− fromResult (HIdentity (Identity a)) = a
74+ reify = notReify
75+ unreify = notReify
76+ coherence = notReify
77+ congruence = notReify
78+
79+
80+instance Sql DBType a =>
81+ Recontextualize Aggregate Aggregate (Aggregate a) (Aggregate a)
82+
83+
84+instance Sql DBType a =>
85+ Recontextualize Aggregate Expr (Aggregate a) (Expr a)
86+
87+
88+instance Sql DBType a =>
89+ Recontextualize Aggregate Result (Aggregate a) (Identity a)
90+
60
91
92+instance Sql DBType a =>
93+ Recontextualize Aggregate Name (Aggregate a) (Name a)
61
94
95+
96+instance Sql DBType a =>
97+ Recontextualize Expr Aggregate (Expr a) (Aggregate a)
98+
99+
100+instance Sql DBType a =>
101+ Recontextualize Result Aggregate (Identity a) (Aggregate a)
102+
103+
104+instance Sql DBType a =>
105+ Recontextualize Name Aggregate (Name a) (Aggregate a)
106+
107+
62−-- | @Aggregates a b@ means that the columns in @a@ are all 'Aggregate's
108+-- | @Aggregates a b@ means that the columns in @a@ are all 'Aggregate' 'Expr's
63−-- for the 'Expr' columns in @b@.
109+-- for the columns in @b@.
64type Aggregates :: Type -> Type -> Constraint
110type Aggregates :: Type -> Type -> Constraint
65−class Transposes Aggregate Expr aggregates exprs => Aggregates aggregates exprs
111+class Recontextualize Aggregate Expr aggregates exprs => Aggregates aggregates exprs
66−instance Transposes Aggregate Expr aggregates exprs => Aggregates aggregates exprs
112+instance Recontextualize Aggregate Expr aggregates exprs => Aggregates aggregates exprs
113+
114+
115+foldInputs :: Monoid b
116+ => (Maybe Aggregator -> Opaleye.PrimExpr -> b) -> Aggregate a -> b
117+foldInputs f (Aggregate (Opaleye.Aggregator (Opaleye.PackMap agg))) =
118+ getConst $ flip agg () $ \(aggregator, a) ->
119+ Const $ f (detuplize <$> aggregator) a
120+ where
121+ detuplize (operation, ordering, distinction) =
122+ Aggregator {operation, ordering, distinction}
123+
124+
125+mapInputs :: ()
126+ => (Opaleye.PrimExpr -> Opaleye.PrimExpr) -> Aggregate a -> Aggregate a
127+mapInputs transform (Aggregate (Opaleye.Aggregator (Opaleye.PackMap agg))) =
128+ Aggregate $ Opaleye.Aggregator $ Opaleye.PackMap $ agg . \f input ->
129+ f (fmap transform input)
67
130
68
131
69−zipOutputs :: ()
132+type Aggregator :: Type
70− => (Expr a -> Expr b -> Expr c) -> Aggregate a -> Aggregate b -> Aggregate c
133+data Aggregator = Aggregator
71−zipOutputs f (Aggregate a) (Aggregate b) = Aggregate (liftA2 f a b)
134+ { operation :: Opaleye.AggrOp
135+ , ordering :: [Opaleye.OrderExpr]
136+ , distinction :: Opaleye.AggrDistinct
137+ }
72
138
73
139
74−unsafeMakeAggregate :: forall (input :: Type) (output :: Type) n n' a a'. ()
140+unsafeMakeAggregate :: ()
75 => (Expr input -> Opaleye.PrimExpr)
141 => (Expr input -> Opaleye.PrimExpr)
76 -> (Opaleye.PrimExpr -> Expr output)
142 -> (Opaleye.PrimExpr -> Expr output)
77− -> Opaleye.Aggregator (Opaleye.Field_ n a) (Opaleye.Field_ n' a')
143+ -> Maybe Aggregator
78 -> Expr input
144 -> Expr input
79 -> Aggregate output
145 -> Aggregate output
80unsafeMakeAggregate input output aggregator expr =
146unsafeMakeAggregate input output aggregator expr =
81− Aggregate $ dimap in_ out aggregator
147+ Aggregate $ Opaleye.Aggregator $ Opaleye.PackMap $ \f _ ->
82− where out = output . Opaleye.unColumn
148+ output <$> f (tuplize <$> aggregator, input expr)
83− in_ = Opaleye.Column . input . const expr
149+ where
150+ tuplize Aggregator {operation, ordering, distinction} =
151+ (operation, ordering, distinction)
src/Rel8/Column.hs+91−5
@@ -1,21 +1,41 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2+{-# language FlexibleContexts #-}
3+{-# language LambdaCase #-}
4+{-# language MultiParamTypeClasses #-}
5+{-# language ScopedTypeVariables #-}
2{-# language StandaloneKindSignatures #-}
6{-# language StandaloneKindSignatures #-}
7+{-# language TypeApplications #-}
3{-# language TypeFamilies #-}
8{-# language TypeFamilies #-}
4
9
5module Rel8.Column
10module Rel8.Column
6− ( Column
11+ ( Column, AColumn(..)
7 , TColumn
12 , TColumn
8 )
13 )
9where
14where
10
15
11-- base
16-- base
12import Data.Kind ( Type )
17import Data.Kind ( Type )
18+import Data.Type.Equality ( (:~:)( Refl ) )
13−import Prelude ()
19+import Prelude
14
20
15-- rel8
21-- rel8
22+import Rel8.Aggregate ( Aggregate, Col( A ) )
23+import Rel8.Expr ( Expr, Col( E ) )
16import Rel8.FCF ( Eval, Exp )
24import Rel8.FCF ( Eval, Exp )
25+import Rel8.Kind.Context ( SContext(..), Reifiable( contextSing ) )
26+import Rel8.Schema.HTable.Identity ( HIdentity(..), HType )
17import qualified Rel8.Schema.Kind as K
27import qualified Rel8.Schema.Kind as K
18−import Rel8.Schema.Result ( Result )
28+import Rel8.Schema.Name ( Name(..), Col( N ) )
29+import Rel8.Schema.Null ( Sql )
30+import Rel8.Schema.Reify ( Reify, Col(..) )
31+import Rel8.Schema.Result ( Col( R ), Result, absurd )
32+import Rel8.Schema.Spec ( Spec( Spec ) )
33+import Rel8.Table
34+ ( Table, Columns, Context, fromColumns, toColumns
35+ , Unreify, reify, unreify, coherence, congruence
36+ )
37+import Rel8.Table.Recontextualize ( Recontextualize )
38+import Rel8.Type ( DBType )
19
39
20
40
21-- | This type family is used to specify columns in 'Rel8able's. In @Column f
41-- | This type family is used to specify columns in 'Rel8able's. In @Column f
@@ -23,8 +43,74 @@ import Rel8.Schema.Result ( Result )
23-- 'Rel8able' definitions), and @a@ is the type of the column.
43-- 'Rel8able' definitions), and @a@ is the type of the column.
24type Column :: K.Context -> Type -> Type
44type Column :: K.Context -> Type -> Type
25type family Column context a where
45type family Column context a where
46+ Column (Reify context) a = AColumn context a
47+ Column Aggregate a = Aggregate a
48+ Column Expr a = Expr a
49+ Column Name a = Name a
26− Column Result a = a
50+ Column Result a = a
51+
52+
53+type AColumn :: K.Context -> Type -> Type
54+newtype AColumn context a = AColumn (Column context a)
55+
56+
57+instance (Reifiable context, Sql DBType a) =>
58+ Table (Reify context) (AColumn context a)
59+ where
60+ type Context (AColumn context a) = Reify context
61+ type Columns (AColumn context a) = HType a
27− Column context a = context a
62+ type Unreify (AColumn context a) = Column context a
63+
64+ fromColumns (HType (Reify a)) = sfromColumn contextSing a
65+ toColumns = HType . Reify . stoColumn contextSing
66+ reify _ = AColumn
67+ unreify _ (AColumn a) = a
68+
69+ coherence Refl = case contextSing @context of
70+ SAggregate -> const Refl
71+ SExpr -> const Refl
72+ SName -> const Refl
73+ SResult -> absurd
74+ SReify _ -> const Refl
75+
76+ congruence Refl = case contextSing @context of
77+ SAggregate -> const Refl
78+ SExpr -> const Refl
79+ SName -> const Refl
80+ SResult -> absurd
81+ SReify _ -> const Refl
82+
83+
84+instance (Reifiable context, Reifiable context', Sql DBType a) =>
85+ Recontextualize
86+ (Reify context)
87+ (Reify context')
88+ (AColumn context a)
89+ (AColumn context' a)
90+
91+
92+sfromColumn :: ()
93+ => SContext context
94+ -> Col context ('Spec a)
95+ -> AColumn context a
96+sfromColumn = \case
97+ SAggregate -> \(A a) -> AColumn a
98+ SExpr -> \(E a) -> AColumn a
99+ SName -> \(N a) -> AColumn a
100+ SResult -> \(R a) -> AColumn a
101+ SReify context -> \(Reify a) -> AColumn (sfromColumn context a)
102+
103+
104+stoColumn :: ()
105+ => SContext context
106+ -> AColumn context a
107+ -> Col context ('Spec a)
108+stoColumn = \case
109+ SAggregate -> \(AColumn a) -> A a
110+ SExpr -> \(AColumn a) -> E a
111+ SName -> \(AColumn a) -> N a
112+ SResult -> \(AColumn a) -> R a
113+ SReify context -> \(AColumn a) -> Reify (stoColumn context a)
28
114
29
115
30data TColumn :: K.Context -> Type -> Exp Type
116data TColumn :: K.Context -> Type -> Exp Type
src/Rel8/Column/ADT.hs+87−4
@@ -1,23 +1,106 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2+{-# language LambdaCase #-}
3+{-# language MultiParamTypeClasses #-}
4+{-# language ScopedTypeVariables #-}
2{-# language StandaloneKindSignatures #-}
5{-# language StandaloneKindSignatures #-}
6+{-# language TypeApplications #-}
3{-# language TypeFamilies #-}
7{-# language TypeFamilies #-}
8+{-# language UndecidableInstances #-}
4
9
5module Rel8.Column.ADT
10module Rel8.Column.ADT
6− ( HADT
11+ ( HADT, AHADT(..)
7 )
12 )
8where
13where
9
14
10-- base
15-- base
11import Data.Kind ( Type )
16import Data.Kind ( Type )
17+import Data.Type.Equality ( (:~:)( Refl ) )
12−import Prelude ()
18+import Prelude
13
19
14-- rel8
20-- rel8
21+import Rel8.Generic.Rel8able ( GColumns )
22+import Rel8.Kind.Context ( SContext(..), Reifiable, contextSing )
23+import Rel8.Schema.Context ( Col )
15import qualified Rel8.Schema.Kind as K
24import qualified Rel8.Schema.Kind as K
16−import Rel8.Schema.Result ( Result )
25+import Rel8.Schema.Reify ( Reify, hreify, hunreify )
26+import Rel8.Schema.Result ( Result, absurd )
17−import Rel8.Table.ADT ( ADT )
27+import Rel8.Table
28+ ( Table, Columns, Context, fromColumns, toColumns
29+ , Unreify, reify, unreify, coherence, congruence
30+ )
31+import Rel8.Table.ADT ( ADT( ADT ), ADTable, fromADT, toADT )
32+import Rel8.Table.Rel8able ()
33+import Rel8.Table.Recontextualize ( Recontextualize )
18
34
19
35
20type HADT :: K.Context -> K.Rel8able -> Type
36type HADT :: K.Context -> K.Rel8able -> Type
21type family HADT context t where
37type family HADT context t where
38+ HADT (Reify context) t = AHADT context t
22 HADT Result t = t Result
39 HADT Result t = t Result
23 HADT context t = ADT t context
40 HADT context t = ADT t context
41+
42+
43+type AHADT :: K.Context -> K.Rel8able -> Type
44+newtype AHADT context t = AHADT (HADT context t)
45+
46+
47+instance (ADTable t, Reifiable context) =>
48+ Table (Reify context) (AHADT context t)
49+ where
50+ type Context (AHADT context t) = Reify context
51+ type Columns (AHADT context t) = GColumns (ADT t)
52+ type Unreify (AHADT context t) = HADT context t
53+
54+ fromColumns = sfromColumnsADT contextSing
55+ toColumns = stoColumnsADT contextSing
56+ reify _ = AHADT
57+ unreify _ (AHADT a) = a
58+
59+ coherence = case contextSing @context of
60+ SAggregate -> \Refl _ -> Refl
61+ SExpr -> \Refl _ -> Refl
62+ SName -> \Refl _ -> Refl
63+ SResult -> \Refl -> absurd
64+ SReify _ -> \Refl _ -> Refl
65+
66+ congruence = case contextSing @context of
67+ SAggregate -> \_ _ -> Refl
68+ SExpr -> \_ _ -> Refl
69+ SName -> \_ _ -> Refl
70+ SResult -> \Refl -> absurd
71+ SReify _ -> \_ _ -> Refl
72+
73+
74+instance
75+ ( Reifiable context, Reifiable context'
76+ , ADTable t, t ~ t'
77+ )
78+ => Recontextualize
79+ (Reify context)
80+ (Reify context')
81+ (AHADT context t)
82+ (AHADT context' t')
83+
84+
85+sfromColumnsADT :: ADTable t
86+ => SContext context
87+ -> GColumns (ADT t) (Col (Reify context))
88+ -> AHADT context t
89+sfromColumnsADT = \case
90+ SAggregate -> AHADT . ADT . hunreify
91+ SExpr -> AHADT . ADT . hunreify
92+ SName -> AHADT . ADT . hunreify
93+ SResult -> AHADT . fromADT . ADT . hunreify
94+ SReify context -> AHADT . sfromColumnsADT context . hunreify
95+
96+
97+stoColumnsADT :: ADTable t
98+ => SContext context
99+ -> AHADT context t
100+ -> GColumns (ADT t) (Col (Reify context))
101+stoColumnsADT = \case
102+ SAggregate -> hreify . (\(AHADT (ADT a)) -> a)
103+ SExpr -> hreify . (\(AHADT (ADT a)) -> a)
104+ SName -> hreify . (\(AHADT (ADT a)) -> a)
105+ SResult -> hreify . (\(ADT a) -> a) . toADT . (\(AHADT a) -> a)
106+ SReify context -> hreify . stoColumnsADT context . (\(AHADT a) -> a)
src/Rel8/Column/Either.hs+170−4
@@ -1,20 +1,42 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2+{-# language FlexibleContexts #-}
3+{-# language LambdaCase #-}
4+{-# language MultiParamTypeClasses #-}
5+{-# language ScopedTypeVariables #-}
2{-# language StandaloneKindSignatures #-}
6{-# language StandaloneKindSignatures #-}
7+{-# language TypeApplications #-}
3{-# language TypeFamilyDependencies #-}
8{-# language TypeFamilyDependencies #-}
9+{-# language UndecidableInstances #-}
4
10
5module Rel8.Column.Either
11module Rel8.Column.Either
6− ( HEither
12+ ( HEither, AHEither(..)
7 )
13 )
8where
14where
9
15
10-- base
16-- base
17+import Control.Applicative ( liftA2 )
18+import Control.Category ( id )
19+import Data.Bifunctor ( Bifunctor, bimap )
11import Data.Kind ( Type )
20import Data.Kind ( Type )
21+import Data.Type.Equality ( (:~:)( Refl ), apply )
12−import Prelude
22+import Prelude hiding ( id )
13
23
14-- rel8
24-- rel8
25+import Rel8.Aggregate ( Aggregate )
26+import Rel8.Expr ( Expr )
27+import Rel8.Kind.Context ( SContext(..), Reifiable( contextSing ) )
28+import Rel8.Schema.Context ( Col )
29+import Rel8.Schema.HTable.Either ( HEitherTable )
15import qualified Rel8.Schema.Kind as K
30import qualified Rel8.Schema.Kind as K
16−import Rel8.Schema.Result ( Result )
31+import Rel8.Schema.Name ( Name(..) )
32+import Rel8.Schema.Reify ( Reify, hreify, hunreify )
33+import Rel8.Schema.Result ( Result, absurd )
34+import Rel8.Table
35+ ( Table, Columns, Context, fromColumns, toColumns
36+ , Unreify, reify, unreify, coherence, congruence
37+ )
17import Rel8.Table.Either ( EitherTable )
38import Rel8.Table.Either ( EitherTable )
39+import Rel8.Table.Recontextualize ( Recontextualize )
18
40
19
41
20-- | Nest an 'Either' value within a 'Rel8able'. @HEither f a b@ will produce a
42-- | Nest an 'Either' value within a 'Rel8able'. @HEither f a b@ will produce a
@@ -22,5 +44,149 @@ import Rel8.Table.Either ( EitherTable )
22-- 'Result' context.
44-- 'Result' context.
23type HEither :: K.Context -> Type -> Type -> Type
45type HEither :: K.Context -> Type -> Type -> Type
24type family HEither context = either | either -> context where
46type family HEither context = either | either -> context where
47+ HEither (Reify context) = AHEither context
48+ HEither Aggregate = EitherTable Aggregate
49+ HEither Expr = EitherTable Expr
50+ HEither Name = EitherTable Name
25 HEither Result = Either
51 HEither Result = Either
26− HEither context = EitherTable context
52+
53+
54+type AHEither :: K.Context -> Type -> Type -> Type
55+newtype AHEither context a b = AHEither (HEither context a b)
56+
57+
58+instance Reifiable context => Bifunctor (AHEither context) where
59+ bimap = sbimapEither contextSing
60+
61+
62+instance Reifiable context => Functor (AHEither context a) where
63+ fmap = bimap id
64+
65+
66+instance (Reifiable context, Table (Reify context) a, Table (Reify context) b)
67+ => Table (Reify context) (AHEither context a b)
68+ where
69+ type Context (AHEither context a b) = Reify context
70+ type Columns (AHEither context a b) = HEitherTable (Columns a) (Columns b)
71+ type Unreify (AHEither context a b) = HEither context (Unreify a) (Unreify b)
72+
73+ fromColumns = sfromColumnsEither contextSing
74+ toColumns = stoColumnsEither contextSing
75+ reify proof = liftA2 bimap reify reify proof . AHEither
76+ unreify proof = (\(AHEither a) -> a) . liftA2 bimap unreify unreify proof
77+
78+ coherence = case contextSing @context of
79+ SAggregate -> coherence @(Reify context) @a
80+ SExpr -> coherence @(Reify context) @a
81+ SName -> coherence @(Reify context) @a
82+ SResult -> \Refl -> absurd
83+ SReify _ -> \Refl _ -> Refl
84+
85+ congruence proof@Refl abstract = case contextSing @context of
86+ SAggregate ->
87+ id `apply`
88+ congruence @(Reify context) @a proof abstract `apply`
89+ congruence @(Reify context) @b proof abstract
90+ SExpr ->
91+ id `apply`
92+ congruence @(Reify context) @a proof abstract `apply`
93+ congruence @(Reify context) @b proof abstract
94+ SName ->
95+ id `apply`
96+ congruence @(Reify context) @a proof abstract `apply`
97+ congruence @(Reify context) @b proof abstract
98+ SResult -> absurd abstract
99+ SReify _ ->
100+ id `apply`
101+ congruence @(Reify context) @a proof abstract `apply`
102+ congruence @(Reify context) @b proof abstract
103+
104+
105+instance
106+ ( Reifiable context, Reifiable context'
107+ , Recontextualize (Reify context) (Reify context') a a'
108+ , Recontextualize (Reify context) (Reify context') b b'
109+ ) =>
110+ Recontextualize
111+ (Reify context)
112+ (Reify context')
113+ (AHEither context a b)
114+ (AHEither context' a' b')
115+
116+
117+sbimapEither :: ()
118+ => SContext context
119+ -> (a -> c)
120+ -> (b -> d)
121+ -> AHEither context a b
122+ -> AHEither context c d
123+sbimapEither = \case
124+ SAggregate -> \f g (AHEither a) -> AHEither (bimap f g a)
125+ SExpr -> \f g (AHEither a) -> AHEither (bimap f g a)
126+ SResult -> \f g (AHEither a) -> AHEither (bimap f g a)
127+ SName -> \f g (AHEither a) -> AHEither (bimap f g a)
128+ SReify context -> \f g (AHEither a) -> AHEither (sbimapEither context f g a)
129+
130+
131+sfromColumnsEither :: (Table (Reify context) a, Table (Reify context) b)
132+ => SContext context
133+ -> HEitherTable (Columns a) (Columns b) (Col (Reify context))
134+ -> AHEither context a b
135+sfromColumnsEither = \case
136+ SAggregate ->
137+ AHEither .
138+ bimap (fromColumns . hreify) (fromColumns . hreify) .
139+ fromColumns .
140+ hunreify
141+ SExpr ->
142+ AHEither .
143+ bimap (fromColumns . hreify) (fromColumns . hreify) .
144+ fromColumns .
145+ hunreify
146+ SResult ->
147+ AHEither .
148+ bimap (fromColumns . hreify) (fromColumns . hreify) .
149+ fromColumns .
150+ hunreify
151+ SName ->
152+ AHEither .
153+ bimap (fromColumns . hreify) (fromColumns . hreify) .
154+ fromColumns .
155+ hunreify
156+ SReify context ->
157+ AHEither .
158+ sbimapEither context (fromColumns . hreify) (fromColumns . hreify) .
159+ sfromColumnsEither context .
160+ hunreify
161+
162+
163+stoColumnsEither :: (Table (Reify context) a, Table (Reify context) b)
164+ => SContext context
165+ -> AHEither context a b
166+ -> HEitherTable (Columns a) (Columns b) (Col (Reify context))
167+stoColumnsEither = \case
168+ SAggregate ->
169+ hreify .
170+ toColumns .
171+ bimap (hunreify . toColumns) (hunreify . toColumns) .
172+ (\(AHEither a) -> a)
173+ SExpr ->
174+ hreify .
175+ toColumns .
176+ bimap (hunreify . toColumns) (hunreify . toColumns) .
177+ (\(AHEither a) -> a)
178+ SResult ->
179+ hreify .
180+ toColumns .
181+ bimap (hunreify . toColumns) (hunreify . toColumns) .
182+ (\(AHEither a) -> a)
183+ SName ->
184+ hreify .
185+ toColumns .
186+ bimap (hunreify . toColumns) (hunreify . toColumns) .
187+ (\(AHEither a) -> a)
188+ SReify context ->
189+ hreify .
190+ stoColumnsEither context .
191+ sbimapEither context (hunreify . toColumns) (hunreify . toColumns) .
192+ (\(AHEither a) -> a)
src/Rel8/Column/Lift.hs+85−4
@@ -1,23 +1,104 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2+{-# language LambdaCase #-}
3+{-# language MultiParamTypeClasses #-}
4+{-# language ScopedTypeVariables #-}
2{-# language StandaloneKindSignatures #-}
5{-# language StandaloneKindSignatures #-}
6+{-# language TypeApplications #-}
3{-# language TypeFamilies #-}
7{-# language TypeFamilies #-}
4
8
5module Rel8.Column.Lift
9module Rel8.Column.Lift
6− ( Lift
10+ ( Lift, ALift(..)
7 )
11 )
8where
12where
9
13
10-- base
14-- base
11import Data.Kind ( Type )
15import Data.Kind ( Type )
16+import Data.Type.Equality ( (:~:)( Refl ) )
12−import Prelude ()
17+import Prelude
13
18
14-- rel8
19-- rel8
20+import Rel8.Generic.Rel8able ( GColumns )
21+import Rel8.Kind.Context ( Reifiable(..), SContext(..) )
22+import Rel8.Schema.Context ( Col )
15import qualified Rel8.Schema.Kind as K
23import qualified Rel8.Schema.Kind as K
16−import Rel8.Schema.Result ( Result )
24+import Rel8.Schema.Reify ( Reify, hreify, hunreify )
25+import Rel8.Schema.Result ( Result, absurd )
17−import Rel8.Table.HKD ( HKD )
26+import Rel8.Table
27+ ( Table, Columns, Context, fromColumns, toColumns
28+ , Unreify, reify, unreify, coherence, congruence
29+ )
30+import Rel8.Table.Rel8able ()
31+import Rel8.Table.HKD ( HKD( HKD ), HKDable, fromHKD, toHKD )
32+import Rel8.Table.Recontextualize ( Recontextualize )
18
33
19
34
20type Lift :: K.Context -> Type -> Type
35type Lift :: K.Context -> Type -> Type
21type family Lift context a where
36type family Lift context a where
37+ Lift (Reify context) a = ALift context a
22 Lift Result a = a
38 Lift Result a = a
23 Lift context a = HKD a context
39 Lift context a = HKD a context
40+
41+
42+type ALift :: K.Context -> Type -> Type
43+newtype ALift context a = ALift
44+ { unALift :: Lift context a
45+ }
46+
47+
48+instance (Reifiable context, HKDable a) =>
49+ Table (Reify context) (ALift context a)
50+ where
51+ type Context (ALift context a) = Reify context
52+ type Columns (ALift context a) = GColumns (HKD a)
53+ type Unreify (ALift context a) = Lift context a
54+
55+ fromColumns = sfromColumnsLift contextSing
56+ toColumns = stoColumnsLift contextSing
57+ reify _ = ALift
58+ unreify _ (ALift a) = a
59+
60+ coherence = case contextSing @context of
61+ SAggregate -> \Refl _ -> Refl
62+ SExpr -> \Refl _ -> Refl
63+ SName -> \Refl _ -> Refl
64+ SResult -> \Refl -> absurd
65+ SReify _ -> \Refl _ -> Refl
66+
67+ congruence = case contextSing @context of
68+ SAggregate -> \_ _ -> Refl
69+ SExpr -> \_ _ -> Refl
70+ SName -> \_ _ -> Refl
71+ SResult -> \Refl -> absurd
72+ SReify _ -> \_ _ -> Refl
73+
74+
75+instance (Reifiable context, Reifiable context', HKDable a) =>
76+ Recontextualize
77+ (Reify context)
78+ (Reify context')
79+ (ALift context a)
80+ (ALift context' a)
81+
82+
83+sfromColumnsLift :: HKDable a
84+ => SContext context
85+ -> GColumns (HKD a) (Col (Reify context))
86+ -> ALift context a
87+sfromColumnsLift = \case
88+ SAggregate -> ALift . fromColumns . hunreify
89+ SExpr -> ALift . fromColumns . hunreify
90+ SName -> ALift . fromColumns . hunreify
91+ SResult -> ALift . fromHKD . HKD . hunreify
92+ SReify context -> ALift . sfromColumnsLift context . hunreify
93+
94+
95+stoColumnsLift :: HKDable a
96+ => SContext context
97+ -> ALift context a
98+ -> GColumns (HKD a) (Col (Reify context))
99+stoColumnsLift = \case
100+ SAggregate -> hreify . toColumns . unALift
101+ SExpr -> hreify . toColumns . unALift
102+ SName -> hreify . toColumns . unALift
103+ SResult -> hreify . (\(HKD a) -> a) . toHKD . unALift
104+ SReify context -> hreify . stoColumnsLift context . unALift
src/Rel8/Column/List.hs+152−5
@@ -1,25 +1,172 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2+{-# language FlexibleContexts #-}
3+{-# language LambdaCase #-}
4+{-# language MultiParamTypeClasses #-}
5+{-# language RankNTypes #-}
6+{-# language ScopedTypeVariables #-}
2{-# language StandaloneKindSignatures #-}
7{-# language StandaloneKindSignatures #-}
8+{-# language TypeApplications #-}
3{-# language TypeFamilyDependencies #-}
9{-# language TypeFamilyDependencies #-}
10+{-# language UndecidableInstances #-}
4
11
5module Rel8.Column.List
12module Rel8.Column.List
6− ( HList
13+ ( HList, AHList(..)
7 )
14 )
8where
15where
9
16
10-- base
17-- base
18+import Control.Category ( id )
11import Data.Kind ( Type )
19import Data.Kind ( Type )
20+import Data.Type.Equality ( (:~:)( Refl ), apply )
12−import Prelude ()
21+import Prelude hiding ( id )
13
22
14-- rel8
23-- rel8
24+import Rel8.Aggregate ( Aggregate )
25+import Rel8.Expr ( Expr )
26+import Rel8.Kind.Context ( SContext(..), Reifiable( contextSing ) )
27+import Rel8.Schema.Context ( Col )
28+import Rel8.Schema.Context.Abstract ( exclusivity, virtualOrResult )
29+import Rel8.Schema.HTable.List ( HListTable )
15import qualified Rel8.Schema.Kind as K
30import qualified Rel8.Schema.Kind as K
16−import Rel8.Schema.Result ( Result )
31+import Rel8.Schema.Name ( Name )
32+import Rel8.Schema.Reify ( Reify, hreify, hunreify )
33+import Rel8.Schema.Result ( Result, absurd )
17−import Rel8.Table.List ( ListTable )
34+import Rel8.Table
35+ ( Table, Columns, Congruent, Context, fromColumns, toColumns
36+ , Unreify, reify, unreify, coherence, congruence
37+ )
38+import Rel8.Table.List ( ListTable( ListTable ) )
39+import Rel8.Table.Recontextualize ( Recontextualize )
18
40
19
41
20-- | Nest a list within a 'Rel8able'. @HList f a@ will produce a 'ListTable'
42-- | Nest a list within a 'Rel8able'. @HList f a@ will produce a 'ListTable'
21-- @a@ in the 'Expr' context, and a @[a]@ in the 'Result' context.
43-- @a@ in the 'Expr' context, and a @[a]@ in the 'Result' context.
22type HList :: K.Context -> Type -> Type
44type HList :: K.Context -> Type -> Type
23type family HList context = list | list -> context where
45type family HList context = list | list -> context where
46+ HList (Reify context) = AHList context
47+ HList Aggregate = ListTable Aggregate
48+ HList Expr = ListTable Expr
49+ HList Name = ListTable Name
24 HList Result = []
50 HList Result = []
25− HList context = ListTable context
51+
52+
53+type AHList :: K.Context -> Type -> Type
54+newtype AHList context a = AHList (HList context a)
55+
56+
57+instance (Reifiable context, Table (Reify context) a) =>
58+ Table (Reify context) (AHList context a)
59+ where
60+ type Context (AHList context a) = Reify context
61+ type Columns (AHList context a) = HListTable (Columns a)
62+ type Unreify (AHList context a) = HList context (Unreify a)
63+
64+ fromColumns = sfromColumnsList contextSing
65+ toColumns = stoColumnsList contextSing
66+
67+ reify _ = sreifyList contextSing
68+ unreify _ = sunreifyList contextSing
69+
70+ coherence = case contextSing @context of
71+ SAggregate -> coherence @(Reify context) @a
72+ SExpr -> coherence @(Reify context) @a
73+ SName -> coherence @(Reify context) @a
74+ SResult -> \Refl -> absurd
75+ SReify _ -> \Refl _ -> Refl
76+
77+ congruence proof@Refl abstract = case contextSing @context of
78+ SAggregate -> id `apply` congruence @(Reify context) @a proof abstract
79+ SExpr -> id `apply` congruence @(Reify context) @a proof abstract
80+ SName -> id `apply` congruence @(Reify context) @a proof abstract
81+ SResult -> absurd abstract
82+ SReify _ -> id `apply` congruence @(Reify context) @a proof abstract
83+
84+
85+instance
86+ ( Reifiable context, Reifiable context'
87+ , Recontextualize (Reify context) (Reify context') a a'
88+ )
89+ => Recontextualize
90+ (Reify context)
91+ (Reify context')
92+ (AHList context a)
93+ (AHList context' a')
94+
95+
96+smapList :: Congruent a b
97+ => SContext context
98+ -> (a -> b)
99+ -> (HListTable (Columns a) (Col (Context a)) -> HListTable (Columns b) (Col (Context b)))
100+ -> AHList context a
101+ -> AHList context b
102+smapList = \case
103+ SAggregate -> \_ f (AHList (ListTable a)) -> AHList (ListTable (f a))
104+ SExpr -> \_ f (AHList (ListTable a)) -> AHList (ListTable (f a))
105+ SResult -> \f _ (AHList as) -> AHList (fmap f as)
106+ SName -> \_ f (AHList (ListTable a)) -> AHList (ListTable (f a))
107+ SReify context -> \f g (AHList as) -> AHList (smapList context f g as)
108+
109+
110+sfromColumnsList :: Table (Reify context) a
111+ => SContext context
112+ -> HListTable (Columns a) (Col (Reify context))
113+ -> AHList context a
114+sfromColumnsList = \case
115+ SAggregate -> AHList . ListTable
116+ SExpr -> AHList . ListTable
117+ SResult -> AHList . fmap (fromColumns . hreify) . fromColumns . hunreify
118+ SName -> AHList . ListTable
119+ SReify context ->
120+ AHList .
121+ smapList context (fromColumns . hreify) hreify .
122+ sfromColumnsList context .
123+ hunreify
124+
125+
126+stoColumnsList :: Table (Reify context) a
127+ => SContext context
128+ -> AHList context a
129+ -> HListTable (Columns a) (Col (Reify context))
130+stoColumnsList = \case
131+ SAggregate -> \(AHList (ListTable a)) -> a
132+ SExpr -> \(AHList (ListTable a)) -> a
133+ SResult ->
134+ hreify . toColumns . fmap (hunreify . toColumns) . (\(AHList a) -> a)
135+ SName -> \(AHList (ListTable a)) -> a
136+ SReify context ->
137+ hreify .
138+ stoColumnsList context .
139+ smapList context (hunreify . toColumns) hunreify .
140+ (\(AHList a) -> a)
141+
142+
143+sreifyList :: forall context a. Table (Reify context) a
144+ => SContext context
145+ -> HList context (Unreify a)
146+ -> AHList context a
147+sreifyList context = case virtualOrResult context of
148+ Left Refl -> AHList . fmap (reify Refl)
149+ Right virtual ->
150+ case coherence @(Reify context) @a Refl abstract of
151+ Refl -> case congruence @(Reify context) @a Refl abstract of
152+ Refl ->
153+ smapList context (reify Refl) hreify .
154+ AHList
155+ where
156+ abstract = exclusivity virtual
157+
158+
159+sunreifyList :: forall context a. Table (Reify context) a
160+ => SContext context
161+ -> AHList context a
162+ -> HList context (Unreify a)
163+sunreifyList context = case virtualOrResult context of
164+ Left Refl -> fmap (unreify Refl) . (\(AHList a) -> a)
165+ Right virtual ->
166+ case coherence @(Reify context) @a Refl abstract of
167+ Refl -> case congruence @(Reify context) @a Refl abstract of
168+ Refl ->
169+ (\(AHList a) -> a) .
170+ smapList context (unreify Refl) hunreify
171+ where
172+ abstract = exclusivity virtual
src/Rel8/Column/Maybe.hs+123−4
@@ -1,20 +1,41 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2+{-# language FlexibleContexts #-}
3+{-# language GADTs #-}
4+{-# language LambdaCase #-}
5+{-# language MultiParamTypeClasses #-}
6+{-# language ScopedTypeVariables #-}
2{-# language StandaloneKindSignatures #-}
7{-# language StandaloneKindSignatures #-}
8+{-# language TypeApplications #-}
3{-# language TypeFamilyDependencies #-}
9{-# language TypeFamilyDependencies #-}
10+{-# language UndecidableInstances #-}
4
11
5module Rel8.Column.Maybe
12module Rel8.Column.Maybe
6− ( HMaybe
13+ ( HMaybe, AHMaybe(..)
7 )
14 )
8where
15where
9
16
10-- base
17-- base
18+import Control.Category ( id )
11import Data.Kind ( Type )
19import Data.Kind ( Type )
20+import Data.Type.Equality ( (:~:)( Refl ), apply )
12−import Prelude
21+import Prelude hiding ( id )
13
22
14-- rel8
23-- rel8
24+import Rel8.Aggregate ( Aggregate )
25+import Rel8.Expr ( Expr )
26+import Rel8.Kind.Context ( SContext(..), Reifiable( contextSing ) )
27+import Rel8.Schema.Context ( Col )
28+import Rel8.Schema.HTable.Maybe ( HMaybeTable )
15import qualified Rel8.Schema.Kind as K
29import qualified Rel8.Schema.Kind as K
16−import Rel8.Schema.Result ( Result )
30+import Rel8.Schema.Name ( Name )
31+import Rel8.Schema.Reify ( Reify, hreify, hunreify )
32+import Rel8.Schema.Result ( Result, absurd )
33+import Rel8.Table
34+ ( Table, Columns, Context, fromColumns, toColumns
35+ , Unreify, reify, unreify, coherence, congruence
36+ )
17import Rel8.Table.Maybe ( MaybeTable )
37import Rel8.Table.Maybe ( MaybeTable )
38+import Rel8.Table.Recontextualize ( Recontextualize )
18
39
19
40
20-- | Nest a 'Maybe' value within a 'Rel8able'. @HMaybe f a@ will produce a
41-- | Nest a 'Maybe' value within a 'Rel8able'. @HMaybe f a@ will produce a
@@ -22,5 +43,103 @@ import Rel8.Table.Maybe ( MaybeTable )
22-- context.
43-- context.
23type HMaybe :: K.Context -> Type -> Type
44type HMaybe :: K.Context -> Type -> Type
24type family HMaybe context = maybe | maybe -> context where
45type family HMaybe context = maybe | maybe -> context where
46+ HMaybe (Reify context) = AHMaybe context
47+ HMaybe Aggregate = MaybeTable Aggregate
48+ HMaybe Expr = MaybeTable Expr
49+ HMaybe Name = MaybeTable Name
25 HMaybe Result = Maybe
50 HMaybe Result = Maybe
26− HMaybe context = MaybeTable context
51+
52+
53+type AHMaybe :: K.Context -> Type -> Type
54+newtype AHMaybe context a = AHMaybe (HMaybe context a)
55+
56+
57+instance Reifiable context => Functor (AHMaybe context) where
58+ fmap = smapMaybe contextSing
59+
60+
61+instance (Reifiable context, Table (Reify context) a) =>
62+ Table (Reify context) (AHMaybe context a)
63+ where
64+ type Context (AHMaybe context a) = Reify context
65+ type Columns (AHMaybe context a) = HMaybeTable (Columns a)
66+ type Unreify (AHMaybe context a) = HMaybe context (Unreify a)
67+
68+ fromColumns = sfromColumnsMaybe contextSing
69+ toColumns = stoColumnsMaybe contextSing
70+ reify proof = fmap fmap reify proof . AHMaybe
71+ unreify proof = (\(AHMaybe a) -> a) . fmap fmap unreify proof
72+
73+ coherence = case contextSing @context of
74+ SAggregate -> coherence @(Reify context) @a
75+ SExpr -> coherence @(Reify context) @a
76+ SName -> coherence @(Reify context) @a
77+ SResult -> \Refl -> absurd
78+ SReify _ -> \Refl _ -> Refl
79+
80+ congruence proof@Refl abstract = case contextSing @context of
81+ SAggregate -> id `apply` congruence @(Reify context) @a proof abstract
82+ SExpr -> id `apply` congruence @(Reify context) @a proof abstract
83+ SName -> id `apply` congruence @(Reify context) @a proof abstract
84+ SResult -> absurd abstract
85+ SReify _ -> id `apply` congruence @(Reify context) @a proof abstract
86+
87+
88+instance
89+ ( Reifiable context, Reifiable context'
90+ , Recontextualize (Reify context) (Reify context') a a'
91+ )
92+ => Recontextualize
93+ (Reify context)
94+ (Reify context')
95+ (AHMaybe context a)
96+ (AHMaybe context' a')
97+
98+
99+smapMaybe :: ()
100+ => SContext context
101+ -> (a -> b)
102+ -> AHMaybe context a
103+ -> AHMaybe context b
104+smapMaybe = \case
105+ SAggregate -> \f (AHMaybe a) -> AHMaybe (fmap f a)
106+ SExpr -> \f (AHMaybe a) -> AHMaybe (fmap f a)
107+ SResult -> \f (AHMaybe a) -> AHMaybe (fmap f a)
108+ SName -> \f (AHMaybe a) -> AHMaybe (fmap f a)
109+ SReify context -> \f (AHMaybe a) -> AHMaybe (smapMaybe context f a)
110+
111+
112+sfromColumnsMaybe :: Table (Reify context) a
113+ => SContext context
114+ -> HMaybeTable (Columns a) (Col (Reify context))
115+ -> AHMaybe context a
116+sfromColumnsMaybe = \case
117+ SAggregate -> AHMaybe . fmap (fromColumns . hreify) . fromColumns . hunreify
118+ SExpr -> AHMaybe . fmap (fromColumns . hreify) . fromColumns . hunreify
119+ SResult -> AHMaybe . fmap (fromColumns . hreify) . fromColumns . hunreify
120+ SName -> AHMaybe . fmap (fromColumns . hreify) . fromColumns . hunreify
121+ SReify context ->
122+ AHMaybe .
123+ smapMaybe context (fromColumns . hreify) .
124+ sfromColumnsMaybe context .
125+ hunreify
126+
127+
128+stoColumnsMaybe :: Table (Reify context) a
129+ => SContext context
130+ -> AHMaybe context a
131+ -> HMaybeTable (Columns a) (Col (Reify context))
132+stoColumnsMaybe = \case
133+ SAggregate ->
134+ hreify . toColumns . fmap (hunreify . toColumns) . (\(AHMaybe a) -> a)
135+ SExpr ->
136+ hreify . toColumns . fmap (hunreify . toColumns) . (\(AHMaybe a) -> a)
137+ SResult ->
138+ hreify . toColumns . fmap (hunreify . toColumns) . (\(AHMaybe a) -> a)
139+ SName ->
140+ hreify . toColumns . fmap (hunreify . toColumns) . (\(AHMaybe a) -> a)
141+ SReify context ->
142+ hreify .
143+ stoColumnsMaybe context .
144+ smapMaybe context (hunreify . toColumns) .
145+ (\(AHMaybe a) -> a)
src/Rel8/Column/NonEmpty.hs+152−5
@@ -1,21 +1,42 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2+{-# language FlexibleContexts #-}
3+{-# language LambdaCase #-}
4+{-# language MultiParamTypeClasses #-}
5+{-# language ScopedTypeVariables #-}
2{-# language StandaloneKindSignatures #-}
6{-# language StandaloneKindSignatures #-}
7+{-# language TypeApplications #-}
3{-# language TypeFamilyDependencies #-}
8{-# language TypeFamilyDependencies #-}
9+{-# language UndecidableInstances #-}
4
10
5module Rel8.Column.NonEmpty
11module Rel8.Column.NonEmpty
6− ( HNonEmpty
12+ ( HNonEmpty, AHNonEmpty(..)
7 )
13 )
8where
14where
9
15
10-- base
16-- base
17+import Control.Category ( id )
11import Data.Kind ( Type )
18import Data.Kind ( Type )
12import Data.List.NonEmpty ( NonEmpty )
19import Data.List.NonEmpty ( NonEmpty )
20+import Data.Type.Equality ( (:~:)( Refl ), apply )
13−import Prelude ()
21+import Prelude hiding ( id )
14
22
15-- rel8
23-- rel8
24+import Rel8.Aggregate ( Aggregate )
25+import Rel8.Expr ( Expr )
26+import Rel8.Kind.Context ( SContext(..), Reifiable( contextSing ) )
27+import Rel8.Schema.Context ( Col )
28+import Rel8.Schema.Context.Abstract ( exclusivity, virtualOrResult )
29+import Rel8.Schema.HTable.NonEmpty ( HNonEmptyTable )
16import qualified Rel8.Schema.Kind as K
30import qualified Rel8.Schema.Kind as K
17−import Rel8.Schema.Result ( Result )
31+import Rel8.Schema.Name ( Name )
32+import Rel8.Schema.Reify ( Reify, hreify, hunreify )
33+import Rel8.Schema.Result ( Result, absurd )
18−import Rel8.Table.NonEmpty ( NonEmptyTable )
34+import Rel8.Table
35+ ( Table, Columns, Congruent, Context, fromColumns, toColumns
36+ , Unreify, reify, unreify, coherence, congruence
37+ )
38+import Rel8.Table.NonEmpty ( NonEmptyTable( NonEmptyTable ) )
39+import Rel8.Table.Recontextualize ( Recontextualize )
19
40
20
41
21-- | Nest a 'NonEmpty' list within a 'Rel8able'. @HNonEmpty f a@ will produce a
42-- | Nest a 'NonEmpty' list within a 'Rel8able'. @HNonEmpty f a@ will produce a
@@ -23,5 +44,131 @@ import Rel8.Table.NonEmpty ( NonEmptyTable )
23-- 'Result' context.
44-- 'Result' context.
24type HNonEmpty :: K.Context -> Type -> Type
45type HNonEmpty :: K.Context -> Type -> Type
25type family HNonEmpty context = nonEmpty | nonEmpty -> context where
46type family HNonEmpty context = nonEmpty | nonEmpty -> context where
47+ HNonEmpty (Reify context) = AHNonEmpty context
48+ HNonEmpty Aggregate = NonEmptyTable Aggregate
49+ HNonEmpty Expr = NonEmptyTable Expr
50+ HNonEmpty Name = NonEmptyTable Name
26 HNonEmpty Result = NonEmpty
51 HNonEmpty Result = NonEmpty
27− HNonEmpty context = NonEmptyTable context
52+
53+
54+type AHNonEmpty :: K.Context -> Type -> Type
55+newtype AHNonEmpty context a = AHNonEmpty (HNonEmpty context a)
56+
57+
58+instance (Reifiable context, Table (Reify context) a) =>
59+ Table (Reify context) (AHNonEmpty context a)
60+ where
61+ type Context (AHNonEmpty context a) = Reify context
62+ type Columns (AHNonEmpty context a) = HNonEmptyTable (Columns a)
63+ type Unreify (AHNonEmpty context a) = HNonEmpty context (Unreify a)
64+
65+ fromColumns = sfromColumnsNonEmpty contextSing
66+ toColumns = stoColumnsNonEmpty contextSing
67+
68+ reify _ = sreifyNonEmpty contextSing
69+ unreify _ = sunreifyNonEmpty contextSing
70+
71+ coherence = case contextSing @context of
72+ SAggregate -> coherence @(Reify context) @a
73+ SExpr -> coherence @(Reify context) @a
74+ SName -> coherence @(Reify context) @a
75+ SResult -> \Refl -> absurd
76+ SReify _ -> \Refl _ -> Refl
77+
78+ congruence proof@Refl abstract = case contextSing @context of
79+ SAggregate -> id `apply` congruence @(Reify context) @a proof abstract
80+ SExpr -> id `apply` congruence @(Reify context) @a proof abstract
81+ SName -> id `apply` congruence @(Reify context) @a proof abstract
82+ SResult -> absurd abstract
83+ SReify _ -> id `apply` congruence @(Reify context) @a proof abstract
84+
85+
86+instance
87+ ( Reifiable context, Reifiable context'
88+ , Recontextualize (Reify context) (Reify context') a a'
89+ )
90+ => Recontextualize
91+ (Reify context)
92+ (Reify context')
93+ (AHNonEmpty context a)
94+ (AHNonEmpty context' a')
95+
96+
97+smapNonEmpty :: Congruent a b
98+ => SContext context
99+ -> (a -> b)
100+ -> (HNonEmptyTable (Columns a) (Col (Context a)) -> HNonEmptyTable (Columns b) (Col (Context b)))
101+ -> AHNonEmpty context a
102+ -> AHNonEmpty context b
103+smapNonEmpty = \case
104+ SAggregate -> \_ f (AHNonEmpty (NonEmptyTable a)) -> AHNonEmpty (NonEmptyTable (f a))
105+ SExpr -> \_ f (AHNonEmpty (NonEmptyTable a)) -> AHNonEmpty (NonEmptyTable (f a))
106+ SResult -> \f _ (AHNonEmpty as) -> AHNonEmpty (fmap f as)
107+ SName -> \_ f (AHNonEmpty (NonEmptyTable a)) -> AHNonEmpty (NonEmptyTable (f a))
108+ SReify context -> \f g (AHNonEmpty as) -> AHNonEmpty (smapNonEmpty context f g as)
109+
110+
111+sfromColumnsNonEmpty :: Table (Reify context) a
112+ => SContext context
113+ -> HNonEmptyTable (Columns a) (Col (Reify context))
114+ -> AHNonEmpty context a
115+sfromColumnsNonEmpty = \case
116+ SAggregate -> AHNonEmpty . NonEmptyTable
117+ SExpr -> AHNonEmpty . NonEmptyTable
118+ SResult ->
119+ AHNonEmpty . fmap (fromColumns . hreify) . fromColumns . hunreify
120+ SName -> AHNonEmpty . NonEmptyTable
121+ SReify context ->
122+ AHNonEmpty .
123+ smapNonEmpty context (fromColumns . hreify) hreify .
124+ sfromColumnsNonEmpty context .
125+ hunreify
126+
127+
128+stoColumnsNonEmpty :: Table (Reify context) a
129+ => SContext context
130+ -> AHNonEmpty context a
131+ -> HNonEmptyTable (Columns a) (Col (Reify context))
132+stoColumnsNonEmpty = \case
133+ SAggregate -> \(AHNonEmpty (NonEmptyTable a)) -> a
134+ SExpr -> \(AHNonEmpty (NonEmptyTable a)) -> a
135+ SResult ->
136+ hreify . toColumns . fmap (hunreify . toColumns) . (\(AHNonEmpty a) -> a)
137+ SName -> \(AHNonEmpty (NonEmptyTable a)) -> a
138+ SReify context ->
139+ hreify .
140+ stoColumnsNonEmpty context .
141+ smapNonEmpty context (hunreify . toColumns) hunreify .
142+ (\(AHNonEmpty a) -> a)
143+
144+
145+sreifyNonEmpty :: forall context a. Table (Reify context) a
146+ => SContext context
147+ -> HNonEmpty context (Unreify a)
148+ -> AHNonEmpty context a
149+sreifyNonEmpty context = case virtualOrResult context of
150+ Left Refl -> AHNonEmpty . fmap (reify Refl)
151+ Right virtual ->
152+ case coherence @(Reify context) @a Refl abstract of
153+ Refl -> case congruence @(Reify context) @a Refl abstract of
154+ Refl ->
155+ smapNonEmpty context (reify Refl) hreify .
156+ AHNonEmpty
157+ where
158+ abstract = exclusivity virtual
159+
160+
161+sunreifyNonEmpty :: forall context a. Table (Reify context) a
162+ => SContext context
163+ -> AHNonEmpty context a
164+ -> HNonEmpty context (Unreify a)
165+sunreifyNonEmpty context = case virtualOrResult context of
166+ Left Refl -> fmap (unreify Refl) . (\(AHNonEmpty a) -> a)
167+ Right virtual ->
168+ case coherence @(Reify context) @a Refl abstract of
169+ Refl -> case congruence @(Reify context) @a Refl abstract of
170+ Refl ->
171+ (\(AHNonEmpty a) -> a) .
172+ smapNonEmpty context (unreify Refl) hunreify
173+ where
174+ abstract = exclusivity virtual
src/Rel8/Column/Null.hsdeleted−26
@@ -1,26 +0,0 @@
1−{-# language DataKinds #-}
2−{-# language StandaloneKindSignatures #-}
3−{-# language TypeFamilyDependencies #-}
4−
5−module Rel8.Column.Null
6− ( HNull
7− )
8−where
9−
10−-- base
11−import Data.Kind ( Type )
12−import Prelude
13−
14−-- rel8
15−import qualified Rel8.Schema.Kind as K
16−import Rel8.Schema.Result ( Result )
17−import Rel8.Table.Null ( NullTable )
18−
19−
20−-- | Nest a 'Null' value within a 'Rel8able'. @HNull f a@ will produce a
21−-- 'NullTable' @a@ in the 'Expr' context, and a @'Maybe' a@ in the 'Result'
22−-- context.
23−type HNull :: K.Context -> Type -> Type
24−type family HNull context = maybe | maybe -> context where
25− HNull Result = Maybe
26− HNull context = NullTable context
src/Rel8/Column/These.hs+171−4
@@ -1,19 +1,42 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2+{-# language FlexibleContexts #-}
3+{-# language GADTs #-}
4+{-# language LambdaCase #-}
5+{-# language MultiParamTypeClasses #-}
6+{-# language ScopedTypeVariables #-}
2{-# language StandaloneKindSignatures #-}
7{-# language StandaloneKindSignatures #-}
8+{-# language TypeApplications #-}
3{-# language TypeFamilyDependencies #-}
9{-# language TypeFamilyDependencies #-}
10+{-# language UndecidableInstances #-}
4
11
5module Rel8.Column.These
12module Rel8.Column.These
6− ( HThese
13+ ( HThese, AHThese(..)
7 )
14 )
8where
15where
9
16
10-- base
17-- base
18+import Control.Applicative ( liftA2 )
19+import Control.Category ( id )
20+import Data.Bifunctor ( Bifunctor, bimap )
11import Data.Kind ( Type )
21import Data.Kind ( Type )
22+import Data.Type.Equality ( (:~:)( Refl ), apply )
12−import Prelude ()
23+import Prelude hiding ( id )
13
24
14-- rel8
25-- rel8
26+import Rel8.Aggregate ( Aggregate )
27+import Rel8.Expr ( Expr )
28+import Rel8.Kind.Context ( SContext(..), Reifiable( contextSing ) )
29+import Rel8.Schema.Context ( Col )
30+import Rel8.Schema.HTable.These ( HTheseTable )
15import qualified Rel8.Schema.Kind as K
31import qualified Rel8.Schema.Kind as K
16−import Rel8.Schema.Result ( Result )
32+import Rel8.Schema.Name ( Name )
33+import Rel8.Schema.Reify ( Reify, hreify, hunreify )
34+import Rel8.Schema.Result ( Result, absurd )
35+import Rel8.Table
36+ ( Table, Columns, Context, fromColumns, toColumns
37+ , Unreify, reify, unreify, coherence, congruence
38+ )
39+import Rel8.Table.Recontextualize ( Recontextualize )
17import Rel8.Table.These ( TheseTable )
40import Rel8.Table.These ( TheseTable )
18
41
19-- these
42-- these
@@ -25,5 +48,149 @@ import Data.These ( These )
25-- 'Result' context.
48-- 'Result' context.
26type HThese :: K.Context -> Type -> Type -> Type
49type HThese :: K.Context -> Type -> Type -> Type
27type family HThese context = these | these -> context where
50type family HThese context = these | these -> context where
51+ HThese (Reify context) = AHThese context
52+ HThese Aggregate = TheseTable Aggregate
53+ HThese Expr = TheseTable Expr
54+ HThese Name = TheseTable Name
28 HThese Result = These
55 HThese Result = These
29− HThese context = TheseTable context
56+
57+
58+type AHThese :: K.Context -> Type -> Type -> Type
59+newtype AHThese context a b = AHThese (HThese context a b)
60+
61+
62+instance Reifiable context => Bifunctor (AHThese context) where
63+ bimap = sbimapThese contextSing
64+
65+
66+instance Reifiable context => Functor (AHThese context a) where
67+ fmap = bimap id
68+
69+
70+instance (Reifiable context, Table (Reify context) a, Table (Reify context) b)
71+ => Table (Reify context) (AHThese context a b)
72+ where
73+ type Context (AHThese context a b) = Reify context
74+ type Columns (AHThese context a b) = HTheseTable (Columns a) (Columns b)
75+ type Unreify (AHThese context a b) = HThese context (Unreify a) (Unreify b)
76+
77+ fromColumns = sfromColumnsThese contextSing
78+ toColumns = stoColumnsThese contextSing
79+ reify proof = liftA2 bimap reify reify proof . AHThese
80+ unreify proof = (\(AHThese a) -> a) . liftA2 bimap unreify unreify proof
81+
82+ coherence = case contextSing @context of
83+ SAggregate -> coherence @(Reify context) @a
84+ SExpr -> coherence @(Reify context) @a
85+ SName -> coherence @(Reify context) @a
86+ SResult -> \Refl -> absurd
87+ SReify _ -> \Refl _ -> Refl
88+
89+ congruence proof@Refl abstract = case contextSing @context of
90+ SAggregate ->
91+ id `apply`
92+ congruence @(Reify context) @a proof abstract `apply`
93+ congruence @(Reify context) @b proof abstract
94+ SExpr ->
95+ id `apply`
96+ congruence @(Reify context) @a proof abstract `apply`
97+ congruence @(Reify context) @b proof abstract
98+ SName ->
99+ id `apply`
100+ congruence @(Reify context) @a proof abstract `apply`
101+ congruence @(Reify context) @b proof abstract
102+ SResult -> absurd abstract
103+ SReify _ ->
104+ id `apply`
105+ congruence @(Reify context) @a proof abstract `apply`
106+ congruence @(Reify context) @b proof abstract
107+
108+
109+instance
110+ ( Reifiable context, Reifiable context'
111+ , Recontextualize (Reify context) (Reify context') a a'
112+ , Recontextualize (Reify context) (Reify context') b b'
113+ ) =>
114+ Recontextualize
115+ (Reify context)
116+ (Reify context')
117+ (AHThese context a b)
118+ (AHThese context' a' b')
119+
120+
121+sbimapThese :: ()
122+ => SContext context
123+ -> (a -> c)
124+ -> (b -> d)
125+ -> AHThese context a b
126+ -> AHThese context c d
127+sbimapThese = \case
128+ SAggregate -> \f g (AHThese a) -> AHThese (bimap f g a)
129+ SExpr -> \f g (AHThese a) -> AHThese (bimap f g a)
130+ SResult -> \f g (AHThese a) -> AHThese (bimap f g a)
131+ SName -> \f g (AHThese a) -> AHThese (bimap f g a)
132+ SReify context -> \f g (AHThese a) -> AHThese (sbimapThese context f g a)
133+
134+
135+sfromColumnsThese :: (Table (Reify context) a, Table (Reify context) b)
136+ => SContext context
137+ -> HTheseTable (Columns a) (Columns b) (Col (Reify context))
138+ -> AHThese context a b
139+sfromColumnsThese = \case
140+ SAggregate ->
141+ AHThese .
142+ bimap (fromColumns . hreify) (fromColumns . hreify) .
143+ fromColumns .
144+ hunreify
145+ SExpr ->
146+ AHThese .
147+ bimap (fromColumns . hreify) (fromColumns . hreify) .
148+ fromColumns .
149+ hunreify
150+ SResult ->
151+ AHThese .
152+ bimap (fromColumns . hreify) (fromColumns . hreify) .
153+ fromColumns .
154+ hunreify
155+ SName ->
156+ AHThese .
157+ bimap (fromColumns . hreify) (fromColumns . hreify) .
158+ fromColumns .
159+ hunreify
160+ SReify context ->
161+ AHThese .
162+ sbimapThese context (fromColumns . hreify) (fromColumns . hreify) .
163+ sfromColumnsThese context .
164+ hunreify
165+
166+
167+stoColumnsThese :: (Table (Reify context) a, Table (Reify context) b)
168+ => SContext context
169+ -> AHThese context a b
170+ -> HTheseTable (Columns a) (Columns b) (Col (Reify context))
171+stoColumnsThese = \case
172+ SAggregate ->
173+ hreify .
174+ toColumns .
175+ bimap (hunreify . toColumns) (hunreify . toColumns) .
176+ (\(AHThese a) -> a)
177+ SExpr ->
178+ hreify .
179+ toColumns .
180+ bimap (hunreify . toColumns) (hunreify . toColumns) .
181+ (\(AHThese a) -> a)
182+ SResult ->
183+ hreify .
184+ toColumns .
185+ bimap (hunreify . toColumns) (hunreify . toColumns) .
186+ (\(AHThese a) -> a)
187+ SName ->
188+ hreify .
189+ toColumns .
190+ bimap (hunreify . toColumns) (hunreify . toColumns) .
191+ (\(AHThese a) -> a)
192+ SReify context ->
193+ hreify .
194+ stoColumnsThese context .
195+ sbimapThese context (hunreify . toColumns) (hunreify . toColumns) .
196+ (\(AHThese a) -> a)
src/Rel8/Expr.hs+43−16
@@ -1,21 +1,27 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2{-# language DerivingStrategies #-}
2{-# language DerivingStrategies #-}
3−{-# language FlexibleContexts #-}
4{-# language FlexibleInstances #-}
3{-# language FlexibleInstances #-}
4+{-# language GADTs #-}
5{-# language MultiParamTypeClasses #-}
5{-# language MultiParamTypeClasses #-}
6+{-# language PolyKinds #-}
7+{-# language RoleAnnotations #-}
6{-# language ScopedTypeVariables #-}
8{-# language ScopedTypeVariables #-}
9+{-# language StandaloneDeriving #-}
7{-# language StandaloneKindSignatures #-}
10{-# language StandaloneKindSignatures #-}
8{-# language TypeApplications #-}
11{-# language TypeApplications #-}
9{-# language TypeFamilies #-}
12{-# language TypeFamilies #-}
10{-# language UndecidableInstances #-}
13{-# language UndecidableInstances #-}
14+{-# language UndecidableSuperClasses #-}
11
15
12module Rel8.Expr
16module Rel8.Expr
13 ( Expr(..)
17 ( Expr(..)
18+ , Col( E, unE )
14 )
19 )
15where
20where
16
21
17-- base
22-- base
18−import Data.Functor.Identity ( Identity( Identity ) )
23+import Data.Functor.Identity ( Identity )
24+import Data.Kind ( Type )
19import Data.String ( IsString, fromString )
25import Data.String ( IsString, fromString )
20import Prelude hiding ( null )
26import Prelude hiding ( null )
21
27
@@ -32,14 +38,17 @@ import Rel8.Expr.Opaleye
32 , zipPrimExprsWith
38 , zipPrimExprsWith
33 )
39 )
34import Rel8.Expr.Serialize ( litExpr )
40import Rel8.Expr.Serialize ( litExpr )
41+import Rel8.Schema.Context ( Interpretation, Col )
35−import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )
42+import Rel8.Schema.HTable.Identity ( HIdentity( HType ), HType )
36−import qualified Rel8.Schema.Kind as K
37import Rel8.Schema.Null ( Nullity( Null, NotNull ), Sql, nullable )
43import Rel8.Schema.Null ( Nullity( Null, NotNull ), Sql, nullable )
44+import Rel8.Schema.Reify ( notReify )
45+import Rel8.Schema.Result ( Result )
46+import Rel8.Schema.Spec ( Spec( Spec ) )
38import Rel8.Table
47import Rel8.Table
39 ( Table, Columns, Context, fromColumns, toColumns
48 ( Table, Columns, Context, fromColumns, toColumns
40− , FromExprs, fromResult, toResult
49+ , reify, unreify, coherence, congruence
41− , Transpose
42 )
50 )
51+import Rel8.Table.Recontextualize ( Recontextualize )
43import Rel8.Type ( DBType )
52import Rel8.Type ( DBType )
44import Rel8.Type.Monoid ( DBMonoid, memptyExpr )
53import Rel8.Type.Monoid ( DBMonoid, memptyExpr )
45import Rel8.Type.Num ( DBFloating, DBFractional, DBNum )
54import Rel8.Type.Num ( DBFloating, DBFractional, DBNum )
@@ -47,9 +56,13 @@ import Rel8.Type.Semigroup ( DBSemigroup, (<>.) )
47
56
48
57
49-- | Typed SQL expressions.
58-- | Typed SQL expressions.
50−type Expr :: K.Context
59+type role Expr representational
60+type Expr :: k -> Type
61+data Expr a where
51−newtype Expr a = Expr Opaleye.PrimExpr
62+ Expr :: k ~ Type => !Opaleye.PrimExpr -> Expr (a :: k)
63+
64+
52− deriving stock Show
65+deriving stock instance Show (Expr a)
53
66
54
67
55instance Sql DBSemigroup a => Semigroup (Expr a) where
68instance Sql DBSemigroup a => Semigroup (Expr a) where
@@ -113,13 +126,27 @@ instance Sql DBFloating a => Floating (Expr a) where
113 atanh = function "atanh"
126 atanh = function "atanh"
114
127
115
128
129+instance Interpretation Expr where
130+ data Col Expr _spec where
131+ E :: {unE :: !(Expr a)} -> Col Expr ('Spec a)
132+
133+
116instance Sql DBType a => Table Expr (Expr a) where
134instance Sql DBType a => Table Expr (Expr a) where
117− type Columns (Expr a) = HIdentity a
135+ type Columns (Expr a) = HType a
118 type Context (Expr a) = Expr
136 type Context (Expr a) = Expr
119− type FromExprs (Expr a) = a
120− type Transpose to (Expr a) = to a
121
137
122− toColumns a = HIdentity a
138+ toColumns a = HType (E a)
123− fromColumns (HIdentity a) = a
139+ fromColumns (HType (E a)) = a
124− toResult a = HIdentity (Identity a)
140+ reify = notReify
125− fromResult (HIdentity (Identity a)) = a
141+ unreify = notReify
142+ coherence = notReify
143+ congruence = notReify
144+
145+
146+instance Sql DBType a => Recontextualize Expr Expr (Expr a) (Expr a)
147+
148+
149+instance Sql DBType a => Recontextualize Expr Result (Expr a) (Identity a)
150+
151+
152+instance Sql DBType a => Recontextualize Result Expr (Identity a) (Expr a)
src/Rel8/Expr.hs-boot+8−6
@@ -1,4 +1,6 @@
1−{-# language DataKinds #-}
1+{-# language GADTs #-}
2+{-# language PolyKinds #-}
3+{-# language RoleAnnotations #-}
2{-# language StandaloneKindSignatures #-}
4{-# language StandaloneKindSignatures #-}
3
5
4module Rel8.Expr
6module Rel8.Expr
@@ -7,14 +9,14 @@ module Rel8.Expr
7where
9where
8
10
9-- base
11-- base
12+import Data.Kind ( Type )
10import Prelude ()
13import Prelude ()
11
14
12-- opaleye
15-- opaleye
13import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
16import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
14
17
15−-- rel8
16−import Rel8.Schema.Kind ( Context )
17
18
18−
19+type role Expr representational
19−type Expr :: Context
20+type Expr :: k -> Type
21+data Expr a where
20−newtype Expr a = Expr Opaleye.PrimExpr
22+ Expr :: k ~ Type => !Opaleye.PrimExpr -> Expr (a :: k)
src/Rel8/Expr/Aggregate.hs+64−25
@@ -10,7 +10,6 @@ module Rel8.Expr.Aggregate
10 , and, or
10 , and, or
11 , min, max
11 , min, max
12 , sum, sumWhere
12 , sum, sumWhere
13− , avg
14 , stringAgg
13 , stringAgg
15 , groupByExpr
14 , groupByExpr
16 , listAggExpr, nonEmptyAggExpr
15 , listAggExpr, nonEmptyAggExpr
@@ -24,12 +23,10 @@ import Data.List.NonEmpty ( NonEmpty )
24import Prelude hiding ( and, max, min, null, or, sum )
23import Prelude hiding ( and, max, min, null, or, sum )
25
24
26-- opaleye
25-- opaleye
27−import qualified Opaleye.Internal.Aggregate as Opaleye
26+import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
28−import Opaleye.Internal.Column ( Field_( Column ) )
29−import qualified Opaleye.Aggregate as Opaleye
30
27
31-- rel8
28-- rel8
32−import Rel8.Aggregate ( Aggregate, unsafeMakeAggregate )
29+import Rel8.Aggregate ( Aggregate, Aggregator(..), unsafeMakeAggregate )
33import Rel8.Expr ( Expr )
30import Rel8.Expr ( Expr )
34import Rel8.Expr.Bool ( caseExpr )
31import Rel8.Expr.Bool ( caseExpr )
35import Rel8.Expr.Opaleye
32import Rel8.Expr.Opaleye
@@ -53,13 +50,23 @@ import Rel8.Type.Sum ( DBSum )
53
50
54-- | Count the occurances of a single column. Corresponds to @COUNT(a)@
51-- | Count the occurances of a single column. Corresponds to @COUNT(a)@
55count :: Expr a -> Aggregate Int64
52count :: Expr a -> Aggregate Int64
56−count = unsafeMakeAggregate toPrimExpr fromPrimExpr Opaleye.count
53+count = unsafeMakeAggregate toPrimExpr fromPrimExpr $
54+ Just Aggregator
55+ { operation = Opaleye.AggrCount
56+ , ordering = []
57+ , distinction = Opaleye.AggrAll
58+ }
59+
57
60
58-- | Count the number of distinct occurances of a single column. Corresponds to
61-- | Count the number of distinct occurances of a single column. Corresponds to
59-- @COUNT(DISTINCT a)@
62-- @COUNT(DISTINCT a)@
60countDistinct :: Sql DBEq a => Expr a -> Aggregate Int64
63countDistinct :: Sql DBEq a => Expr a -> Aggregate Int64
61countDistinct = unsafeMakeAggregate toPrimExpr fromPrimExpr $
64countDistinct = unsafeMakeAggregate toPrimExpr fromPrimExpr $
62− Opaleye.distinctAggregator Opaleye.count
65+ Just Aggregator
66+ { operation = Opaleye.AggrCount
67+ , ordering = []
68+ , distinction = Opaleye.AggrDistinct
69+ }
63
70
64
71
65-- | Corresponds to @COUNT(*)@.
72-- | Corresponds to @COUNT(*)@.
@@ -74,39 +81,56 @@ countWhere condition = count (caseExpr [(condition, litExpr (Just True))] null)
74
81
75-- | Corresponds to @bool_and@.
82-- | Corresponds to @bool_and@.
76and :: Expr Bool -> Aggregate Bool
83and :: Expr Bool -> Aggregate Bool
77−and = unsafeMakeAggregate toPrimExpr fromPrimExpr Opaleye.boolAnd
84+and = unsafeMakeAggregate toPrimExpr fromPrimExpr $
85+ Just Aggregator
86+ { operation = Opaleye.AggrBoolAnd
87+ , ordering = []
88+ , distinction = Opaleye.AggrAll
89+ }
78
90
79
91
80-- | Corresponds to @bool_or@.
92-- | Corresponds to @bool_or@.
81or :: Expr Bool -> Aggregate Bool
93or :: Expr Bool -> Aggregate Bool
82−or = unsafeMakeAggregate toPrimExpr fromPrimExpr Opaleye.boolOr
94+or = unsafeMakeAggregate toPrimExpr fromPrimExpr $
95+ Just Aggregator
96+ { operation = Opaleye.AggrBoolOr
97+ , ordering = []
98+ , distinction = Opaleye.AggrAll
99+ }
83
100
84
101
85-- | Produce an aggregation for @Expr a@ using the @max@ function.
102-- | Produce an aggregation for @Expr a@ using the @max@ function.
86max :: Sql DBMax a => Expr a -> Aggregate a
103max :: Sql DBMax a => Expr a -> Aggregate a
87−max = unsafeMakeAggregate toPrimExpr fromPrimExpr Opaleye.unsafeMax
104+max = unsafeMakeAggregate toPrimExpr fromPrimExpr $
105+ Just Aggregator
106+ { operation = Opaleye.AggrMax
107+ , ordering = []
108+ , distinction = Opaleye.AggrAll
109+ }
88
110
89
111
90-- | Produce an aggregation for @Expr a@ using the @max@ function.
112-- | Produce an aggregation for @Expr a@ using the @max@ function.
91min :: Sql DBMin a => Expr a -> Aggregate a
113min :: Sql DBMin a => Expr a -> Aggregate a
92−min = unsafeMakeAggregate toPrimExpr fromPrimExpr Opaleye.unsafeMin
114+min = unsafeMakeAggregate toPrimExpr fromPrimExpr $
115+ Just Aggregator
116+ { operation = Opaleye.AggrMin
117+ , ordering = []
118+ , distinction = Opaleye.AggrAll
119+ }
93
120
94-- | Corresponds to @sum@. Note that in SQL, @sum@ is type changing - for
121-- | Corresponds to @sum@. Note that in SQL, @sum@ is type changing - for
95-- example the @sum@ of @integer@ returns a @bigint@. Rel8 doesn't support
122-- example the @sum@ of @integer@ returns a @bigint@. Rel8 doesn't support
96−-- this, and will add explicit casts back to the original input type. This can
123+-- this, and will add explicit cast back to the original input type. This can
97-- lead to overflows, and if you anticipate very large sums, you should upcast
124-- lead to overflows, and if you anticipate very large sums, you should upcast
98-- your input.
125-- your input.
99sum :: Sql DBSum a => Expr a -> Aggregate a
126sum :: Sql DBSum a => Expr a -> Aggregate a
100−sum = unsafeMakeAggregate toPrimExpr (castExpr . fromPrimExpr) Opaleye.unsafeSum
127+sum = unsafeMakeAggregate toPrimExpr (castExpr . fromPrimExpr) $
101−
128+ Just Aggregator
129+ { operation = Opaleye.AggrSum
130+ , ordering = []
131+ , distinction = Opaleye.AggrAll
132+ }
102
133
103−-- | Corresponds to @avg@. Note that in SQL, @avg@ is type changing - for
104−-- example, the @avg@ of @integer@ returns a @numeric@. Rel8 doesn't support
105−-- this, and will add explicit casts back to the original input type. If you
106−-- need a fractional result on an integral column, you should cast your input
107−-- to 'Double' or 'Data.Scientific.Scientific' before calling 'avg'.
108−avg :: Sql DBSum a => Expr a -> Aggregate a
109−avg = unsafeMakeAggregate toPrimExpr (castExpr . fromPrimExpr) Opaleye.unsafeAvg
110
134
111-- | Take the sum of all expressions that satisfy a predicate.
135-- | Take the sum of all expressions that satisfy a predicate.
112sumWhere :: (Sql DBNum a, Sql DBSum a)
136sumWhere :: (Sql DBNum a, Sql DBSum a)
@@ -118,12 +142,17 @@ sumWhere condition a = sum (caseExpr [(condition, a)] 0)
118stringAgg :: Sql DBString a
142stringAgg :: Sql DBString a
119 => Expr db -> Expr a -> Aggregate a
143 => Expr db -> Expr a -> Aggregate a
120stringAgg delimiter =
144stringAgg delimiter =
121− unsafeMakeAggregate toPrimExpr (castExpr . fromPrimExpr) (Opaleye.stringAgg (Column (toPrimExpr delimiter)))
145+ unsafeMakeAggregate toPrimExpr (castExpr . fromPrimExpr) $
146+ Just Aggregator
147+ { operation = Opaleye.AggrStringAggr (toPrimExpr delimiter)
148+ , ordering = []
149+ , distinction = Opaleye.AggrAll
150+ }
122
151
123
152
124-- | Aggregate a value by grouping by it.
153-- | Aggregate a value by grouping by it.
125groupByExpr :: Sql DBEq a => Expr a -> Aggregate a
154groupByExpr :: Sql DBEq a => Expr a -> Aggregate a
126−groupByExpr = unsafeMakeAggregate toPrimExpr fromPrimExpr Opaleye.groupBy
155+groupByExpr = unsafeMakeAggregate toPrimExpr fromPrimExpr Nothing
127
156
128
157
129-- | Collect expressions values as a list.
158-- | Collect expressions values as a list.
@@ -138,13 +167,23 @@ nonEmptyAggExpr = snonEmptyAggExpr typeInformation
138
167
139slistAggExpr :: ()
168slistAggExpr :: ()
140 => TypeInformation (Unnullify a) -> Expr a -> Aggregate [a]
169 => TypeInformation (Unnullify a) -> Expr a -> Aggregate [a]
141−slistAggExpr info = unsafeMakeAggregate to fromPrimExpr Opaleye.arrayAgg
170+slistAggExpr info = unsafeMakeAggregate to fromPrimExpr $ Just
171+ Aggregator
172+ { operation = Opaleye.AggrArr
173+ , ordering = []
174+ , distinction = Opaleye.AggrAll
175+ }
142 where
176 where
143 to = encodeArrayElement info . toPrimExpr
177 to = encodeArrayElement info . toPrimExpr
144
178
145
179
146snonEmptyAggExpr :: ()
180snonEmptyAggExpr :: ()
147 => TypeInformation (Unnullify a) -> Expr a -> Aggregate (NonEmpty a)
181 => TypeInformation (Unnullify a) -> Expr a -> Aggregate (NonEmpty a)
148−snonEmptyAggExpr info = unsafeMakeAggregate to fromPrimExpr Opaleye.arrayAgg
182+snonEmptyAggExpr info = unsafeMakeAggregate to fromPrimExpr $ Just
183+ Aggregator
184+ { operation = Opaleye.AggrArr
185+ , ordering = []
186+ , distinction = Opaleye.AggrAll
187+ }
149 where
188 where
150 to = encodeArrayElement info . toPrimExpr
189 to = encodeArrayElement info . toPrimExpr
src/Rel8/Expr/Eq.hs+1−1
@@ -22,7 +22,7 @@ import Prelude
22import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
22import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
23
23
24-- rel8
24-- rel8
25−import Rel8.Expr ( Expr )
25+import {-# SOURCE #-} Rel8.Expr ( Expr )
26import Rel8.Expr.Bool ( (&&.), (||.), false, or_, coalesce )
26import Rel8.Expr.Bool ( (&&.), (||.), false, or_, coalesce )
27import Rel8.Expr.Null ( isNull, unsafeLiftOpNull )
27import Rel8.Expr.Null ( isNull, unsafeLiftOpNull )
28import Rel8.Expr.Opaleye ( fromPrimExpr, toPrimExpr, zipPrimExprsWith )
28import Rel8.Expr.Opaleye ( fromPrimExpr, toPrimExpr, zipPrimExprsWith )
src/Rel8/Expr/Num.hs+6−39
@@ -4,24 +4,18 @@
4{-# options_ghc -fno-warn-redundant-constraints #-}
4{-# options_ghc -fno-warn-redundant-constraints #-}
5
5
6module Rel8.Expr.Num
6module Rel8.Expr.Num
7− ( fromIntegral
8− , realToFrac
9− , div, mod, divMod
10− , quot, rem, quotRem
11− , ceiling, floor, round, truncate
7+ ( fromIntegral, realToFrac, div, mod, ceiling, floor, round, truncate
12 )
8 )
13where
9where
14
10
15-- base
11-- base
16−import Prelude ( (+), (-), fst, negate, signum, snd )
12+import Prelude ()
17
13
18-- rel
14-- rel
19import Rel8.Expr ( Expr( Expr ) )
15import Rel8.Expr ( Expr( Expr ) )
20−import Rel8.Expr.Eq ( (==.) )
21import Rel8.Expr.Function ( function )
16import Rel8.Expr.Function ( function )
22import Rel8.Expr.Opaleye ( castExpr )
17import Rel8.Expr.Opaleye ( castExpr )
23import Rel8.Schema.Null ( Homonullable, Sql )
18import Rel8.Schema.Null ( Homonullable, Sql )
24−import Rel8.Table.Bool ( bool )
25import Rel8.Type.Num ( DBFractional, DBIntegral, DBNum )
19import Rel8.Type.Num ( DBFractional, DBIntegral, DBNum )
26
20
27
21
@@ -48,41 +42,14 @@ ceiling :: (Sql DBFractional a, Sql DBIntegral b, Homonullable a b)
48ceiling = function "ceiling"
42ceiling = function "ceiling"
49
43
50
44
51−-- | Emulates the behaviour of the Haskell function 'Prelude.div' in
45+-- | Perform integral division. Corresponds to the @div()@ function.
52−-- PostgreSQL.
53div :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
46div :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
54−div n d = fst (divMod n d)
47+div = function "div"
55
48
56
49
57−-- | Emulates the behaviour of the Haskell function 'Prelude.mod' in
50+-- | Corresponds to the @mod()@ function.
58−-- PostgreSQL.
59mod :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
51mod :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
60−mod n d = snd (divMod n d)
52+mod = function "mod"
61−
62−
63−-- | Simultaneous 'div' and 'mod'.
64−divMod :: Sql DBIntegral a => Expr a -> Expr a -> (Expr a, Expr a)
65−divMod n d = bool qr (q - 1, r + d) (signum r ==. negate (signum d))
66− where
67− qr@(q, r) = quotRem n d
68−
69−
70−-- | Perform integral division. Corresponds to the @div()@ function in
71−-- PostgreSQL, which behaves like Haskell's 'Prelude.quot' rather than
72−-- 'Prelude.div'.
73−quot :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
74−quot = function "div"
75−
76−
77−-- | Corresponds to the @mod()@ function in PostgreSQL, which behaves like
78−-- Haskell's 'Prelude.rem' rather than 'Prelude.mod'.
79−rem :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
80−rem = function "mod"
81−
82−
83−-- | Simultaneous 'quot' and 'rem'.
84−quotRem :: Sql DBIntegral a => Expr a -> Expr a -> (Expr a, Expr a)
85−quotRem n d = (quot n d, rem n d)
86
53
87
54
88-- | Round a 'DFractional' to a 'DBIntegral' by rounding to the nearest smaller
55-- | Round a 'DFractional' to a 'DBIntegral' by rounding to the nearest smaller
src/Rel8/Expr/Opaleye.hs+3−12
@@ -10,7 +10,7 @@ module Rel8.Expr.Opaleye
10 , scastExpr, sunsafeCastExpr
10 , scastExpr, sunsafeCastExpr
11 , unsafeLiteral
11 , unsafeLiteral
12 , fromPrimExpr, toPrimExpr, mapPrimExpr, zipPrimExprsWith, traversePrimExpr
12 , fromPrimExpr, toPrimExpr, mapPrimExpr, zipPrimExprsWith, traversePrimExpr
13− , toColumn, fromColumn, traverseFieldP
13+ , toColumn, fromColumn
14 )
14 )
15where
15where
16
16
@@ -27,9 +27,6 @@ import Rel8.Schema.Null ( Unnullify, Sql )
27import Rel8.Type ( DBType, typeInformation )
27import Rel8.Type ( DBType, typeInformation )
28import Rel8.Type.Information ( TypeInformation(..) )
28import Rel8.Type.Information ( TypeInformation(..) )
29
29
30−-- profunctors
31−import Data.Profunctor ( Profunctor, dimap )
32−
33
30
34castExpr :: Sql DBType a => Expr a -> Expr a
31castExpr :: Sql DBType a => Expr a -> Expr a
35castExpr = scastExpr typeInformation
32castExpr = scastExpr typeInformation
@@ -83,15 +80,9 @@ traversePrimExpr :: Functor f
83traversePrimExpr f = fmap fromPrimExpr . f . toPrimExpr
80traversePrimExpr f = fmap fromPrimExpr . f . toPrimExpr
84
81
85
82
86−traverseFieldP :: Profunctor p
87− => p (Opaleye.Field_ n x) (Opaleye.Field_ m y)
88− -> p (Expr a) (Expr b)
89−traverseFieldP = dimap (toColumn . toPrimExpr) (fromPrimExpr . fromColumn)
90−
91−
92−toColumn :: Opaleye.PrimExpr -> Opaleye.Field_ n b
83+toColumn :: Opaleye.PrimExpr -> Opaleye.Column b
93toColumn = Opaleye.Column
84toColumn = Opaleye.Column
94
85
95
86
96−fromColumn :: Opaleye.Field_ n b -> Opaleye.PrimExpr
87+fromColumn :: Opaleye.Column b -> Opaleye.PrimExpr
97fromColumn (Opaleye.Column a) = a
88fromColumn (Opaleye.Column a) = a
src/Rel8/Expr/Sequence.hs+1−2
@@ -11,7 +11,6 @@ import Prelude
11import Rel8.Expr ( Expr )
11import Rel8.Expr ( Expr )
12import Rel8.Expr.Function ( function )
12import Rel8.Expr.Function ( function )
13import Rel8.Expr.Serialize ( litExpr )
13import Rel8.Expr.Serialize ( litExpr )
14−import Rel8.Expr.Text ( quoteIdent )
15
14
16-- text
15-- text
17import Data.Text ( pack )
16import Data.Text ( pack )
@@ -19,4 +18,4 @@ import Data.Text ( pack )
19
18
20-- | See https://www.postgresql.org/docs/current/functions-sequence.html
19-- | See https://www.postgresql.org/docs/current/functions-sequence.html
21nextval :: String -> Expr Int64
20nextval :: String -> Expr Int64
22−nextval = function "nextval" . quoteIdent . litExpr . pack
21+nextval = function "nextval" . litExpr . pack
src/Rel8/Expr/Text.hs+2−23
@@ -17,9 +17,6 @@ module Rel8.Expr.Text
17 , pgClientEncoding, quoteIdent, quoteLiteral, quoteNullable, regexpReplace
17 , pgClientEncoding, quoteIdent, quoteLiteral, quoteNullable, regexpReplace
18 , regexpSplitToArray, repeat, replace, reverse, right, rpad, rtrim
18 , regexpSplitToArray, repeat, replace, reverse, right, rpad, rtrim
19 , splitPart, strpos, substr, translate
19 , splitPart, strpos, substr, translate
20−
21− -- * @LIKE@ and @ILIKE@
22− , like, ilike
23 )
20 )
24where
21where
25
22
@@ -27,7 +24,7 @@ where
27import Data.Bool ( Bool )
24import Data.Bool ( Bool )
28import Data.Int ( Int32 )
25import Data.Int ( Int32 )
29import Data.Maybe ( Maybe( Nothing, Just ) )
26import Data.Maybe ( Maybe( Nothing, Just ) )
30−import Prelude ( flip )
27+import Prelude ()
31
28
32-- bytestring
29-- bytestring
33import Data.ByteString ( ByteString )
30import Data.ByteString ( ByteString )
@@ -52,7 +49,7 @@ infixr 6 ++.
52
49
53
50
54-- | Matches regular expression, case sensitive
51-- | Matches regular expression, case sensitive
55−--
52+--
56-- Corresponds to the @~.@ operator.
53-- Corresponds to the @~.@ operator.
57(~.) :: Expr Text -> Expr Text -> Expr Bool
54(~.) :: Expr Text -> Expr Text -> Expr Bool
58(~.) = binaryOperator "~."
55(~.) = binaryOperator "~."
@@ -276,21 +273,3 @@ substr a b Nothing = function "substr" a b
276-- | Corresponds to the @translate@ function.
273-- | Corresponds to the @translate@ function.
277translate :: Expr Text -> Expr Text -> Expr Text -> Expr Text
274translate :: Expr Text -> Expr Text -> Expr Text -> Expr Text
278translate = function "translate"
275translate = function "translate"
279−
280−
281−-- | @like x y@ corresponds to the expression @y LIKE x@.
282−--
283−-- Note that the arguments to @like@ are swapped. This is to aid currying, so
284−-- you can write expressions like
285−-- @filter (like "Rel%" . packageName) =<< each haskellPackages@
286−like :: Expr Text -> Expr Text -> Expr Bool
287−like = flip (binaryOperator "LIKE")
288−
289−
290−-- | @ilike x y@ corresponds to the expression @y ILIKE x@.
291−--
292−-- Note that the arguments to @ilike@ are swapped. This is to aid currying, so
293−-- you can write expressions like
294−-- @filter (ilike "Rel%" . packageName) =<< each haskellPackages@
295−ilike :: Expr Text -> Expr Text -> Expr Bool
296−ilike = flip (binaryOperator "ILIKE")
src/Rel8/Expr/Window.hsdeleted−121
@@ -1,121 +0,0 @@
1−module Rel8.Expr.Window
2− ( cumulative
3− , rowNumber
4− , rank
5− , denseRank
6− , percentRank
7− , cumeDist
8− , ntile
9− , lag
10− , lead
11− , firstValue
12− , lastValue
13− , nthValue
14− )
15−where
16−
17−-- base
18−import Data.Int ( Int32, Int64 )
19−import Prelude
20−
21−-- opaleye
22−import qualified Opaleye.Internal.Aggregate as Opaleye
23−import qualified Opaleye.Internal.PackMap as Opaleye
24−import qualified Opaleye.Internal.Window as Opaleye
25−import qualified Opaleye.Window as Opaleye
26−
27−-- profunctors
28−import Data.Profunctor (dimap)
29−
30−-- rel8
31−import Rel8.Aggregate ( Aggregate( Aggregate ) )
32−import Rel8.Expr ( Expr )
33−import Rel8.Expr.Opaleye ( fromColumn, fromPrimExpr, toColumn, toPrimExpr )
34−import Rel8.Schema.Null ( Nullify )
35−import Rel8.Window ( Window( Window ) )
36−
37−
38−cumulative :: (a -> Aggregate b) -> Window a (Expr b)
39−cumulative f =
40− fromWindowFunction $ Opaleye.aggregatorWindowFunction (fromAggregate f) id
41−
42−
43−-- | [@row_number()@](https://www.postgresql.org/docs/current/functions-window.html)
44−rowNumber :: Window a (Expr Int64)
45−rowNumber = fromWindowFunction $ fromPrimExpr . fromColumn <$> Opaleye.rowNumber
46−
47−
48−-- | [@rank()@](https://www.postgresql.org/docs/current/functions-window.html)
49−rank :: Window a (Expr Int64)
50−rank = fromWindowFunction $ fromPrimExpr . fromColumn <$> Opaleye.rank
51−
52−
53−-- | [@dense_rank()@](https://www.postgresql.org/docs/current/functions-window.html)
54−denseRank :: Window a (Expr Int64)
55−denseRank = fromWindowFunction $ fromPrimExpr . fromColumn <$> Opaleye.denseRank
56−
57−
58−-- | [@percent_rank()@](https://www.postgresql.org/docs/current/functions-window.html)
59−percentRank :: Window a (Expr Double)
60−percentRank = fromWindowFunction $ fromPrimExpr . fromColumn <$> Opaleye.percentRank
61−
62−
63−-- | [@cume_dist()@](https://www.postgresql.org/docs/current/functions-window.html)
64−cumeDist :: Window a (Expr Double)
65−cumeDist = fromWindowFunction $ fromPrimExpr . fromColumn <$> Opaleye.cumeDist
66−
67−
68−-- | [@ntile(num_buckets)@](https://www.postgresql.org/docs/current/functions-window.html)
69−ntile :: Expr Int32 -> Window a (Expr Int32)
70−ntile buckets = fromWindowFunction $ fromPrimExpr . fromColumn <$>
71− Opaleye.ntile (toColumn (toPrimExpr buckets))
72−
73−
74−-- | [@lag(value, offset, default)@](https://www.postgresql.org/docs/current/functions-window.html)
75−lag :: Expr Int32 -> Expr a -> Window (Expr a) (Expr a)
76−lag offset def =
77− fromWindowFunction $
78− dimap (toColumn . toPrimExpr) (fromPrimExpr . fromColumn) $
79− Opaleye.lag (toColumn (toPrimExpr offset)) (toColumn (toPrimExpr def))
80−
81−
82−-- | [@lead(value, offset, default)@](https://www.postgresql.org/docs/current/functions-window.html)
83−lead :: Expr Int32 -> Expr a -> Window (Expr a) (Expr a)
84−lead offset def =
85− fromWindowFunction $
86− dimap (toColumn . toPrimExpr) (fromPrimExpr . fromColumn) $
87− Opaleye.lead (toColumn (toPrimExpr offset)) (toColumn (toPrimExpr def))
88−
89−
90−-- | [@first_value(value)@](https://www.postgresql.org/docs/current/functions-window.html)
91−firstValue :: Window (Expr a) (Expr a)
92−firstValue =
93− fromWindowFunction $
94− dimap (toColumn . toPrimExpr) (fromPrimExpr . fromColumn)
95− Opaleye.firstValue
96−
97−
98−-- | [@last_value(value)@](https://www.postgresql.org/docs/current/functions-window.html)
99−lastValue :: Window (Expr a) (Expr a)
100−lastValue =
101− fromWindowFunction $
102− dimap (toColumn . toPrimExpr) (fromPrimExpr . fromColumn)
103− Opaleye.lastValue
104−
105−
106−-- | [@nth_value(value, n)@](https://www.postgresql.org/docs/current/functions-window.html)
107−nthValue :: Expr Int32 -> Window (Expr a) (Expr (Nullify a))
108−nthValue n =
109− fromWindowFunction $
110− dimap (toColumn . toPrimExpr) (fromPrimExpr . fromColumn) $
111− Opaleye.nthValue (toColumn (toPrimExpr n))
112−
113−
114−fromAggregate :: (a -> Aggregate b) -> Opaleye.Aggregator a (Expr b)
115−fromAggregate f = Opaleye.Aggregator $ Opaleye.PackMap $ \w a -> case f a of
116− Aggregate (Opaleye.Aggregator (Opaleye.PackMap x)) -> x w ()
117−
118−
119−fromWindowFunction :: Opaleye.WindowFunction a b -> Window a b
120−fromWindowFunction (Opaleye.WindowFunction (Opaleye.PackMap w)) =
121− Window $ Opaleye.Windows $ Opaleye.PackMap $ \f -> w $ \o -> f (o, mempty)
src/Rel8/FCF.hs+3−3
@@ -5,7 +5,7 @@
5
5
6module Rel8.FCF
6module Rel8.FCF
7 ( Exp, Eval
7 ( Exp, Eval
8− , Id
8+ , Compose
9 )
9 )
10where
10where
11
11
@@ -22,5 +22,5 @@ type Eval :: Exp e -> e
22type family Eval a
22type family Eval a
23
23
24
24
25−data Id :: a -> Exp a
25+data Compose :: (Type -> Type) -> (Type -> Exp Type) -> Type -> Exp Type
26−type instance Eval (Id a) = a
26+type instance Eval (Compose f g a) = f (Eval (g a))
src/Rel8/Generic/Coherence.hsnew file+79
@@ -0,0 +1,79 @@
1+{-# language AllowAmbiguousTypes #-}
2+{-# language DataKinds #-}
3+{-# language FlexibleInstances #-}
4+{-# language MultiParamTypeClasses #-}
5+{-# language PolyKinds #-}
6+{-# language RankNTypes #-}
7+{-# language ScopedTypeVariables #-}
8+{-# language StandaloneKindSignatures #-}
9+{-# language TypeApplications #-}
10+{-# language TypeFamilies #-}
11+{-# language TypeOperators #-}
12+{-# language UndecidableInstances #-}
13+
14+module Rel8.Generic.Coherence
15+ ( GCoherent
16+ , gcoherence
17+ , gcongruence
18+ )
19+where
20+
21+-- base
22+import Control.Category ( id )
23+import Data.Kind ( Constraint, Type )
24+import Data.Proxy ( Proxy( Proxy ) )
25+import Data.Type.Equality ( (:~:), apply )
26+import GHC.Generics ( (:*:), K1, M1, Meta( MetaSel ), C, D, S )
27+import Prelude hiding ( id )
28+
29+-- rel8
30+import Rel8.FCF ( Eval, Exp )
31+import Rel8.Generic.Map ( GMap )
32+import Rel8.Generic.Table.Record ( GColumns, GContext )
33+
34+
35+type GCoherent :: (Type -> Exp Constraint) -> (Type -> Type) -> Constraint
36+class GCoherent _Table rep where
37+ gcoherence :: ()
38+ => proxy _Context
39+ -> proxy' f
40+ -> (forall a proxy_. Eval (_Table a)
41+ => proxy_ a -> Eval (_Context (Eval (f a))) :~: context)
42+ -> GContext _Context (GMap f rep) :~: context
43+
44+ gcongruence :: ()
45+ => proxy _Columns
46+ -> proxy' f
47+ -> (forall a proxy_. Eval (_Table a)
48+ => proxy_ a -> Eval (_Columns a) :~: Eval (_Columns (Eval (f a))))
49+ -> GColumns _Columns rep :~: GColumns _Columns (GMap f rep)
50+
51+
52+instance GCoherent _Table rep => GCoherent _Table (M1 D c rep) where
53+ gcoherence = gcoherence @_Table @rep
54+ gcongruence = gcongruence @_Table @rep
55+
56+
57+instance GCoherent _Table rep => GCoherent _Table (M1 C c rep) where
58+ gcoherence = gcoherence @_Table @rep
59+ gcongruence = gcongruence @_Table @rep
60+
61+
62+instance (GCoherent _Table rep1, GCoherent _Table rep2) =>
63+ GCoherent _Table (rep1 :*: rep2)
64+ where
65+ gcoherence = gcoherence @_Table @rep1
66+ gcongruence _Columns f proof = id `apply`
67+ gcongruence @_Table @rep1 _Columns f proof `apply`
68+ gcongruence @_Table @rep2 _Columns f proof
69+
70+
71+instance
72+ ( Eval (_Table a)
73+ , meta ~ 'MetaSel ('Just _l) _su _ss _ds
74+ , k1 ~ K1 i a
75+ )
76+ => GCoherent _Table (M1 S meta k1)
77+ where
78+ gcoherence _ _ proof = proof (Proxy @a)
79+ gcongruence _ _ proof = id `apply` proof (Proxy @a)
src/Rel8/Generic/Construction.hs+163−145
@@ -2,6 +2,8 @@
2{-# language ConstraintKinds #-}
2{-# language ConstraintKinds #-}
3{-# language DataKinds #-}
3{-# language DataKinds #-}
4{-# language FlexibleContexts #-}
4{-# language FlexibleContexts #-}
5+{-# language FlexibleInstances #-}
6+{-# language MultiParamTypeClasses #-}
5{-# language NamedFieldPuns #-}
7{-# language NamedFieldPuns #-}
6{-# language ScopedTypeVariables #-}
8{-# language ScopedTypeVariables #-}
7{-# language StandaloneKindSignatures #-}
9{-# language StandaloneKindSignatures #-}
@@ -25,17 +27,18 @@ where
25import Data.Bifunctor ( first )
27import Data.Bifunctor ( first )
26import Data.Kind ( Constraint, Type )
28import Data.Kind ( Constraint, Type )
27import Data.List.NonEmpty ( NonEmpty( (:|) ) )
29import Data.List.NonEmpty ( NonEmpty( (:|) ) )
30+import Data.Type.Equality ( (:~:)( Refl ) )
28import GHC.TypeLits ( Symbol )
31import GHC.TypeLits ( Symbol )
29import Prelude
32import Prelude
30
33
31-- rel8
34-- rel8
32−import Rel8.Aggregate ( Aggregate( Aggregate ) )
35+import Rel8.Aggregate ( Col( A ), Aggregate( Aggregate ) )
33−import Rel8.Expr ( Expr )
36+import Rel8.Expr ( Col( E ), Expr )
34import Rel8.Expr.Aggregate ( groupByExpr )
37import Rel8.Expr.Aggregate ( groupByExpr )
35import Rel8.Expr.Eq ( (==.) )
38import Rel8.Expr.Eq ( (==.) )
36import Rel8.Expr.Null ( nullify, snull, unsafeUnnullify )
39import Rel8.Expr.Null ( nullify, snull, unsafeUnnullify )
37import Rel8.Expr.Serialize ( litExpr )
40import Rel8.Expr.Serialize ( litExpr )
38−import Rel8.FCF ( Eval, Exp, Id )
41+import Rel8.FCF ( Eval, Exp )
39import Rel8.Generic.Construction.ADT
42import Rel8.Generic.Construction.ADT
40 ( GConstructorADT, GMakeableADT, gmakeADT
43 ( GConstructorADT, GMakeableADT, gmakeADT
41 , GConstructableADT
44 , GConstructableADT
@@ -57,14 +60,16 @@ import Rel8.Kind.Algebra
57import qualified Rel8.Kind.Algebra as K
60import qualified Rel8.Kind.Algebra as K
58import Rel8.Schema.Context.Nullify ( sguard, snullify )
61import Rel8.Schema.Context.Nullify ( sguard, snullify )
59import Rel8.Schema.HTable ( HTable )
62import Rel8.Schema.HTable ( HTable )
60−import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )
63+import Rel8.Schema.HTable.Identity ( HIdentity( HType ) )
61import qualified Rel8.Schema.Kind as K
64import qualified Rel8.Schema.Kind as K
62−import Rel8.Schema.Name ( Name( Name ) )
65+import Rel8.Schema.Name ( Col( N ), Name( Name ) )
63import Rel8.Schema.Null ( Nullity( Null, NotNull ) )
66import Rel8.Schema.Null ( Nullity( Null, NotNull ) )
64−import Rel8.Schema.Spec ( Spec( Spec, nullity, info ) )
67+import Rel8.Schema.Spec ( SSpec( SSpec, nullity, info ) )
68+import Rel8.Schema.Reify ( Col( Reify ), Reify, hreify, hunreify )
69+import Rel8.Schema.Result ( Result )
65import Rel8.Table
70import Rel8.Table
66− ( TTable, TColumns
71+ ( TTable, TColumns, TUnreify
67− , Table, fromColumns, toColumns
72+ , Table, fromColumns, toColumns, reify, unreify
68 )
73 )
69import Rel8.Table.Bool ( case_ )
74import Rel8.Table.Bool ( case_ )
70import Rel8.Type.Tag ( Tag )
75import Rel8.Type.Tag ( Tag )
@@ -73,10 +78,10 @@ import Rel8.Type.Tag ( Tag )
73type GGBuildable :: K.Algebra -> Symbol -> (K.Context -> Exp (Type -> Type)) -> Constraint
78type GGBuildable :: K.Algebra -> Symbol -> (K.Context -> Exp (Type -> Type)) -> Constraint
74type GGBuildable algebra name rep =
79type GGBuildable algebra name rep =
75 ( KnownAlgebra algebra
80 ( KnownAlgebra algebra
76− , Eval (GGColumns algebra TColumns (Eval (rep Aggregate))) ~ Eval (GGColumns algebra TColumns (Eval (rep Expr)))
81+ , Eval (GGColumns algebra TColumns (Eval (rep (Reify Aggregate)))) ~ Eval (GGColumns algebra TColumns (Eval (rep (Reify Result))))
77− , Eval (GGColumns algebra TColumns (Eval (rep Expr))) ~ Eval (GGColumns algebra TColumns (Eval (rep Expr)))
82+ , Eval (GGColumns algebra TColumns (Eval (rep (Reify Expr)))) ~ Eval (GGColumns algebra TColumns (Eval (rep (Reify Result))))
78− , Eval (GGColumns algebra TColumns (Eval (rep Name))) ~ Eval (GGColumns algebra TColumns (Eval (rep Expr)))
83+ , Eval (GGColumns algebra TColumns (Eval (rep (Reify Name)))) ~ Eval (GGColumns algebra TColumns (Eval (rep (Reify Result))))
79− , HTable (Eval (GGColumns algebra TColumns (Eval (rep Expr))))
84+ , HTable (Eval (GGColumns algebra TColumns (Eval (rep (Reify Result)))))
80 , GGBuildable' algebra name rep
85 , GGBuildable' algebra name rep
81 )
86 )
82
87
@@ -84,63 +89,65 @@ type GGBuildable algebra name rep =
84type GGBuildable' :: K.Algebra -> Symbol -> (K.Context -> Exp (Type -> Type)) -> Constraint
89type GGBuildable' :: K.Algebra -> Symbol -> (K.Context -> Exp (Type -> Type)) -> Constraint
85type family GGBuildable' algebra name rep where
90type family GGBuildable' algebra name rep where
86 GGBuildable' 'K.Product name rep =
91 GGBuildable' 'K.Product name rep =
87− ( name ~ GConstructor (Eval (rep Expr))
92+ ( name ~ GConstructor (Eval (rep (Reify Expr)))
88− , Representable Id (Eval (rep Expr))
93+ , Representable TUnreify (Eval (rep (Reify Expr)))
89− , GConstructable (TTable Expr) TColumns Id Expr (Eval (rep Expr))
94+ , GConstructable (TTable (Reify Expr)) TColumns TUnreify (Col (Reify Expr)) (Eval (rep (Reify Expr)))
90 )
95 )
91 GGBuildable' 'K.Sum name rep =
96 GGBuildable' 'K.Sum name rep =
92− ( Representable Id (GConstructorADT name (Eval (rep Expr)))
97+ ( Representable TUnreify (GConstructorADT name (Eval (rep (Reify Expr))))
93− , GMakeableADT (TTable Expr) TColumns Id Expr name (Eval (rep Expr))
98+ , GMakeableADT (TTable (Reify Expr)) TColumns TUnreify (Col (Reify Expr)) name (Eval (rep (Reify Expr)))
94 )
99 )
95
100
96
101
97type GGBuild :: K.Algebra -> Symbol -> (K.Context -> Exp (Type -> Type)) -> Type -> Type
102type GGBuild :: K.Algebra -> Symbol -> (K.Context -> Exp (Type -> Type)) -> Type -> Type
98type family GGBuild algebra name rep r where
103type family GGBuild algebra name rep r where
99 GGBuild 'K.Product _name rep r =
104 GGBuild 'K.Product _name rep r =
100− GConstruct Id (Eval (rep Expr)) r
105+ GConstruct TUnreify (Eval (rep (Reify Expr))) r
101 GGBuild 'K.Sum name rep r =
106 GGBuild 'K.Sum name rep r =
102− GConstruct Id (GConstructorADT name (Eval (rep Expr))) r
107+ GConstruct TUnreify (GConstructorADT name (Eval (rep (Reify Expr)))) r
103
108
104
109
105ggbuild :: forall algebra name rep a. GGBuildable algebra name rep
110ggbuild :: forall algebra name rep a. GGBuildable algebra name rep
106− => (Eval (GGColumns algebra TColumns (Eval (rep Expr))) Expr -> a)
111+ => (Eval (GGColumns algebra TColumns (Eval (rep (Reify Result)))) (Col Expr) -> a)
107 -> GGBuild algebra name rep a
112 -> GGBuild algebra name rep a
108ggbuild gfromColumns = case algebraSing @algebra of
113ggbuild gfromColumns = case algebraSing @algebra of
109 SProduct ->
114 SProduct ->
110− gtabulate @Id @(Eval (rep Expr)) @a $
115+ gtabulate @TUnreify @(Eval (rep (Reify Expr))) @a $
111 gfromColumns .
116 gfromColumns .
117+ hunreify .
112 gconstruct
118 gconstruct
113− @(TTable Expr)
119+ @(TTable (Reify Expr))
114 @TColumns
120 @TColumns
115− @Id
121+ @TUnreify
116− @Expr
122+ @(Col (Reify Expr))
117− @(Eval (rep Expr))
123+ @(Eval (rep (Reify Expr)))
118− (const toColumns)
124+ (\(_ :: proxy x) -> toColumns . reify @_ @x Refl)
119 SSum ->
125 SSum ->
120− gtabulate @Id @(GConstructorADT name (Eval (rep Expr))) @a $
126+ gtabulate @TUnreify @(GConstructorADT name (Eval (rep (Reify Expr)))) @a $
121 gfromColumns .
127 gfromColumns .
128+ hunreify .
122 gmakeADT
129 gmakeADT
123− @(TTable Expr)
130+ @(TTable (Reify Expr))
124 @TColumns
131 @TColumns
125− @Id
132+ @TUnreify
126− @Expr
133+ @(Col (Reify Expr))
127 @name
134 @name
128− @(Eval (rep Expr))
135+ @(Eval (rep (Reify Expr)))
129− (const toColumns)
136+ (\(_ :: proxy x) -> toColumns . reify @_ @x Refl)
130− (\Spec {info} -> snull info)
137+ (\SSpec {info} -> Reify (E (snull info)))
131− (\Spec {nullity} -> case nullity of
138+ (\SSpec {nullity} -> case nullity of
132 Null -> id
139 Null -> id
133− NotNull -> nullify)
140+ NotNull -> \(Reify (E a)) -> Reify (E (nullify a)))
134− (HIdentity . litExpr)
141+ (HType . Reify . E . litExpr)
135
142
136
143
137type GGConstructable :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Constraint
144type GGConstructable :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Constraint
138type GGConstructable algebra rep =
145type GGConstructable algebra rep =
139 ( KnownAlgebra algebra
146 ( KnownAlgebra algebra
140− , Eval (GGColumns algebra TColumns (Eval (rep Aggregate))) ~ Eval (GGColumns algebra TColumns (Eval (rep Expr)))
147+ , Eval (GGColumns algebra TColumns (Eval (rep (Reify Aggregate)))) ~ Eval (GGColumns algebra TColumns (Eval (rep (Reify Result))))
141− , Eval (GGColumns algebra TColumns (Eval (rep Expr))) ~ Eval (GGColumns algebra TColumns (Eval (rep Expr)))
148+ , Eval (GGColumns algebra TColumns (Eval (rep (Reify Expr)))) ~ Eval (GGColumns algebra TColumns (Eval (rep (Reify Result))))
142− , Eval (GGColumns algebra TColumns (Eval (rep Name))) ~ Eval (GGColumns algebra TColumns (Eval (rep Expr)))
149+ , Eval (GGColumns algebra TColumns (Eval (rep (Reify Name)))) ~ Eval (GGColumns algebra TColumns (Eval (rep (Reify Result))))
143− , HTable (Eval (GGColumns algebra TColumns (Eval (rep Expr))))
150+ , HTable (Eval (GGColumns algebra TColumns (Eval (rep (Reify Result)))))
144 , GGConstructable' algebra rep
151 , GGConstructable' algebra rep
145 )
152 )
146
153
@@ -148,100 +155,105 @@ type GGConstructable algebra rep =
148type GGConstructable' :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Constraint
155type GGConstructable' :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Constraint
149type family GGConstructable' algebra rep where
156type family GGConstructable' algebra rep where
150 GGConstructable' 'K.Product rep =
157 GGConstructable' 'K.Product rep =
151− ( Representable Id (Eval (rep Aggregate))
158+ ( Representable TUnreify (Eval (rep (Reify Aggregate)))
152− , Representable Id (Eval (rep Expr))
159+ , Representable TUnreify (Eval (rep (Reify Expr)))
153− , Representable Id (Eval (rep Name))
160+ , Representable TUnreify (Eval (rep (Reify Name)))
154− , GConstructable (TTable Aggregate) TColumns Id Aggregate (Eval (rep Aggregate))
161+ , GConstructable (TTable (Reify Aggregate)) TColumns TUnreify (Col (Reify Aggregate)) (Eval (rep (Reify Aggregate)))
155− , GConstructable (TTable Expr) TColumns Id Expr (Eval (rep Expr))
162+ , GConstructable (TTable (Reify Expr)) TColumns TUnreify (Col (Reify Expr)) (Eval (rep (Reify Expr)))
156− , GConstructable (TTable Name) TColumns Id Name (Eval (rep Name))
163+ , GConstructable (TTable (Reify Name)) TColumns TUnreify (Col (Reify Name)) (Eval (rep (Reify Name)))
157 )
164 )
158 GGConstructable' 'K.Sum rep =
165 GGConstructable' 'K.Sum rep =
159− ( RepresentableConstructors Id (Eval (rep Expr))
166+ ( RepresentableConstructors TUnreify (Eval (rep (Reify Expr)))
160− , RepresentableFields Id (Eval (rep Aggregate))
167+ , RepresentableFields TUnreify (Eval (rep (Reify Aggregate)))
161− , RepresentableFields Id (Eval (rep Expr))
168+ , RepresentableFields TUnreify (Eval (rep (Reify Expr)))
162− , RepresentableFields Id (Eval (rep Name))
169+ , RepresentableFields TUnreify (Eval (rep (Reify Name)))
163− , Functor (GConstructors Id (Eval (rep Expr)))
170+ , Functor (GConstructors TUnreify (Eval (rep (Reify Expr))))
164− , GConstructableADT (TTable Aggregate) TColumns Id Aggregate (Eval (rep Aggregate))
171+ , GConstructableADT (TTable (Reify Aggregate)) TColumns TUnreify (Col (Reify Aggregate)) (Eval (rep (Reify Aggregate)))
165− , GConstructableADT (TTable Expr) TColumns Id Expr (Eval (rep Expr))
172+ , GConstructableADT (TTable (Reify Expr)) TColumns TUnreify (Col (Reify Expr)) (Eval (rep (Reify Expr)))
166− , GConstructableADT (TTable Name) TColumns Id Name (Eval (rep Name))
173+ , GConstructableADT (TTable (Reify Name)) TColumns TUnreify (Col (Reify Name)) (Eval (rep (Reify Name)))
167 )
174 )
168
175
169
176
170type GGConstruct :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Type -> Type
177type GGConstruct :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Type -> Type
171type family GGConstruct algebra rep r where
178type family GGConstruct algebra rep r where
172− GGConstruct 'K.Product rep r = GConstruct Id (Eval (rep Expr)) r -> r
179+ GGConstruct 'K.Product rep r =
180+ GConstruct TUnreify (Eval (rep (Reify Expr))) r -> r
181+ GGConstruct 'K.Sum rep r =
173− GGConstruct 'K.Sum rep r = GConstructADT Id (Eval (rep Expr)) r r
182+ GConstructADT TUnreify (Eval (rep (Reify Expr))) r r
174
183
175
184
176ggconstruct :: forall algebra rep a. GGConstructable algebra rep
185ggconstruct :: forall algebra rep a. GGConstructable algebra rep
177− => (Eval (GGColumns algebra TColumns (Eval (rep Expr))) Expr -> a)
186+ => (Eval (GGColumns algebra TColumns (Eval (rep (Reify Result)))) (Col Expr) -> a)
178 -> GGConstruct algebra rep a -> a
187 -> GGConstruct algebra rep a -> a
179ggconstruct gfromColumns f = case algebraSing @algebra of
188ggconstruct gfromColumns f = case algebraSing @algebra of
180 SProduct ->
189 SProduct ->
181 f $
190 f $
182− gtabulate @Id @(Eval (rep Expr)) @a $
191+ gtabulate @TUnreify @(Eval (rep (Reify Expr))) @a $
183 gfromColumns .
192 gfromColumns .
193+ hunreify .
184 gconstruct
194 gconstruct
185− @(TTable Expr)
195+ @(TTable (Reify Expr))
186 @TColumns
196 @TColumns
187− @Id
197+ @TUnreify
188− @Expr
198+ @(Col (Reify Expr))
189− @(Eval (rep Expr))
199+ @(Eval (rep (Reify Expr)))
190− (const toColumns)
200+ (\(_ :: proxy x) -> toColumns . reify @_ @x Refl)
191 SSum ->
201 SSum ->
192− gcindex @Id @(Eval (rep Expr)) @a f $
202+ gcindex @TUnreify @(Eval (rep (Reify Expr))) @a f $
193− fmap gfromColumns $
203+ fmap (gfromColumns . hunreify) $
194 gconstructADT
204 gconstructADT
195− @(TTable Expr)
205+ @(TTable (Reify Expr))
196 @TColumns
206 @TColumns
197− @Id
207+ @TUnreify
198− @Expr
208+ @(Col (Reify Expr))
199− @(Eval (rep Expr))
209+ @(Eval (rep (Reify Expr)))
200− (const toColumns)
210+ (\(_ :: proxy x) -> toColumns . reify @_ @x Refl)
201− (\Spec {info} -> snull info)
211+ (\SSpec {info} -> Reify (E (snull info)))
202− (\Spec {nullity} -> case nullity of
212+ (\SSpec {nullity} -> case nullity of
203 Null -> id
213 Null -> id
204− NotNull -> nullify)
214+ NotNull -> \(Reify (E a)) -> Reify (E (nullify a)))
205− (HIdentity . litExpr)
215+ (HType . Reify . E . litExpr)
206
216
207
217
208type GGDeconstruct :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Type -> Type -> Type
218type GGDeconstruct :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Type -> Type -> Type
209type family GGDeconstruct algebra rep a r where
219type family GGDeconstruct algebra rep a r where
210 GGDeconstruct 'K.Product rep a r =
220 GGDeconstruct 'K.Product rep a r =
211− GConstruct Id (Eval (rep Expr)) r -> a -> r
221+ GConstruct TUnreify (Eval (rep (Reify Expr))) r -> a -> r
212 GGDeconstruct 'K.Sum rep a r =
222 GGDeconstruct 'K.Sum rep a r =
213− GConstructADT Id (Eval (rep Expr)) r (a -> r)
223+ GConstructADT TUnreify (Eval (rep (Reify Expr))) r (a -> r)
214
224
215
225
216ggdeconstruct :: forall algebra rep a r. (GGConstructable algebra rep, Table Expr r)
226ggdeconstruct :: forall algebra rep a r. (GGConstructable algebra rep, Table Expr r)
217− => (a -> Eval (GGColumns algebra TColumns (Eval (rep Expr))) Expr)
227+ => (a -> Eval (GGColumns algebra TColumns (Eval (rep (Reify Result)))) (Col Expr))
218 -> GGDeconstruct algebra rep a r
228 -> GGDeconstruct algebra rep a r
219ggdeconstruct gtoColumns = case algebraSing @algebra of
229ggdeconstruct gtoColumns = case algebraSing @algebra of
220 SProduct -> \build ->
230 SProduct -> \build ->
221− gindex @Id @(Eval (rep Expr)) @r build .
231+ gindex @TUnreify @(Eval (rep (Reify Expr))) @r build .
222 gdeconstruct
232 gdeconstruct
223− @(TTable Expr)
233+ @(TTable (Reify Expr))
224 @TColumns
234 @TColumns
225− @Id
235+ @TUnreify
226− @Expr
236+ @(Col (Reify Expr))
227− @(Eval (rep Expr))
237+ @(Eval (rep (Reify Expr)))
228− (const fromColumns) .
238+ (\(_ :: proxy x) -> unreify @_ @x Refl . fromColumns) .
239+ hreify .
229 gtoColumns
240 gtoColumns
230 SSum ->
241 SSum ->
231− gctabulate @Id @(Eval (rep Expr)) @r @(a -> r) $ \constructors as ->
242+ gctabulate @TUnreify @(Eval (rep (Reify Expr))) @r @(a -> r) $ \constructors as ->
232 let
243 let
233− (HIdentity tag, cases) =
244+ (HType (Reify (E tag)), cases) =
234 gdeconstructADT
245 gdeconstructADT
235− @(TTable Expr)
246+ @(TTable (Reify Expr))
236 @TColumns
247 @TColumns
237− @Id
248+ @TUnreify
238− @Expr
249+ @(Col (Reify Expr))
239− @(Eval (rep Expr))
250+ @(Eval (rep (Reify Expr)))
240− (const fromColumns)
251+ (\(_ :: proxy x) -> unreify @_ @x Refl . fromColumns)
241− (\Spec {nullity} -> case nullity of
252+ (\SSpec {nullity} -> case nullity of
242 Null -> id
253 Null -> id
243− NotNull -> unsafeUnnullify)
254+ NotNull -> \(Reify (E a)) -> Reify (E (unsafeUnnullify a)))
244 constructors $
255 constructors $
256+ hreify $
245 gtoColumns as
257 gtoColumns as
246 in
258 in
247 case cases of
259 case cases of
@@ -251,102 +263,108 @@ ggdeconstruct gtoColumns = case algebraSing @algebra of
251
263
252type GGName :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Type -> Type
264type GGName :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Type -> Type
253type family GGName algebra rep a where
265type family GGName algebra rep a where
254− GGName 'K.Product rep a = GConstruct Id (Eval (rep Name)) a
266+ GGName 'K.Product rep a = GConstruct TUnreify (Eval (rep (Reify Name))) a
255− GGName 'K.Sum rep a = Name Tag -> GBuildADT Id (Eval (rep Name)) a
267+ GGName 'K.Sum rep a = Name Tag -> GBuildADT TUnreify (Eval (rep (Reify Name))) a
256
268
257
269
258ggname :: forall algebra rep a. GGConstructable algebra rep
270ggname :: forall algebra rep a. GGConstructable algebra rep
259− => (Eval (GGColumns algebra TColumns (Eval (rep Expr))) Name -> a)
271+ => (Eval (GGColumns algebra TColumns (Eval (rep (Reify Result)))) (Col Name) -> a)
260 -> GGName algebra rep a
272 -> GGName algebra rep a
261ggname gfromColumns = case algebraSing @algebra of
273ggname gfromColumns = case algebraSing @algebra of
262 SProduct ->
274 SProduct ->
263− gtabulate @Id @(Eval (rep Name)) @a $
275+ gtabulate @TUnreify @(Eval (rep (Reify Name))) @a $
264 gfromColumns .
276 gfromColumns .
277+ hunreify .
265 gconstruct
278 gconstruct
266− @(TTable Name)
279+ @(TTable (Reify Name))
267 @TColumns
280 @TColumns
268− @Id
281+ @TUnreify
269− @Name
282+ @(Col (Reify Name))
270− @(Eval (rep Name))
283+ @(Eval (rep (Reify Name)))
271− (const toColumns)
284+ (\(_ :: proxy x) -> toColumns . reify @_ @x Refl)
272 SSum -> \tag ->
285 SSum -> \tag ->
273− gftabulate @Id @(Eval (rep Name)) @a $
286+ gftabulate @TUnreify @(Eval (rep (Reify Name))) @a $
274 gfromColumns .
287 gfromColumns .
288+ hunreify .
275 gbuildADT
289 gbuildADT
276− @(TTable Name)
290+ @(TTable (Reify Name))
277 @TColumns
291 @TColumns
278− @Id
292+ @TUnreify
279− @Name
293+ @(Col (Reify Name))
280− @(Eval (rep Name))
294+ @(Eval (rep (Reify Name)))
281− (const toColumns)
295+ (\(_ :: proxy x) -> toColumns . reify @_ @x Refl)
282− (\_ _ (Name a) -> Name a)
296+ (\_ _ (Reify (N (Name a))) -> Reify (N (Name a)))
283− (HIdentity tag)
297+ (HType (Reify (N tag)))
284
298
285
299
286type GGAggregate :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Type -> Type
300type GGAggregate :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Type -> Type
287type family GGAggregate algebra rep r where
301type family GGAggregate algebra rep r where
288 GGAggregate 'K.Product rep r =
302 GGAggregate 'K.Product rep r =
289− GConstruct Id (Eval (rep Aggregate)) r ->
303+ GConstruct TUnreify (Eval (rep (Reify Aggregate))) r ->
290− GConstruct Id (Eval (rep Expr)) r
304+ GConstruct TUnreify (Eval (rep (Reify Expr))) r
291 GGAggregate 'K.Sum rep r =
305 GGAggregate 'K.Sum rep r =
292− GBuildADT Id (Eval (rep Aggregate)) r ->
306+ GBuildADT TUnreify (Eval (rep (Reify Aggregate))) r ->
293− GBuildADT Id (Eval (rep Expr)) r
307+ GBuildADT TUnreify (Eval (rep (Reify Expr))) r
294
308
295
309
296ggaggregate :: forall algebra rep exprs agg. GGConstructable algebra rep
310ggaggregate :: forall algebra rep exprs agg. GGConstructable algebra rep
297− => (Eval (GGColumns algebra TColumns (Eval (rep Expr))) Aggregate -> agg)
311+ => (Eval (GGColumns algebra TColumns (Eval (rep (Reify Result)))) (Col Aggregate) -> agg)
298− -> (exprs -> Eval (GGColumns algebra TColumns (Eval (rep Expr))) Expr)
312+ -> (exprs -> Eval (GGColumns algebra TColumns (Eval (rep (Reify Result)))) (Col Expr))
299 -> GGAggregate algebra rep agg -> exprs -> agg
313 -> GGAggregate algebra rep agg -> exprs -> agg
300ggaggregate gfromColumns gtoColumns agg es = case algebraSing @algebra of
314ggaggregate gfromColumns gtoColumns agg es = case algebraSing @algebra of
301 SProduct -> flip f exprs $
315 SProduct -> flip f exprs $
302 gfromColumns .
316 gfromColumns .
317+ hunreify .
303 gconstruct
318 gconstruct
304− @(TTable Aggregate)
319+ @(TTable (Reify Aggregate))
305 @TColumns
320 @TColumns
306− @Id
321+ @TUnreify
307− @Aggregate
322+ @(Col (Reify Aggregate))
308− @(Eval (rep Aggregate))
323+ @(Eval (rep (Reify Aggregate)))
309− (const toColumns)
324+ (\(_ :: proxy x) -> toColumns . reify @_ @x Refl)
310 where
325 where
311 f =
326 f =
312− gindex @Id @(Eval (rep Expr)) @agg .
327+ gindex @TUnreify @(Eval (rep (Reify Expr))) @agg .
313 agg .
328 agg .
314− gtabulate @Id @(Eval (rep Aggregate)) @agg
329+ gtabulate @TUnreify @(Eval (rep (Reify Aggregate))) @agg
315 exprs =
330 exprs =
316 gdeconstruct
331 gdeconstruct
317− @(TTable Expr)
332+ @(TTable (Reify Expr))
318 @TColumns
333 @TColumns
319− @Id
334+ @TUnreify
320− @Expr
335+ @(Col (Reify Expr))
321− @(Eval (rep Expr))
336+ @(Eval (rep (Reify Expr)))
322− (const fromColumns) $
337+ (\(_ :: proxy x) -> unreify @_ @x Refl . fromColumns) $
338+ hreify $
323 gtoColumns es
339 gtoColumns es
324 SSum -> flip f exprs $
340 SSum -> flip f exprs $
325 gfromColumns .
341 gfromColumns .
342+ hunreify .
326 gbuildADT
343 gbuildADT
327− @(TTable Aggregate)
344+ @(TTable (Reify Aggregate))
328 @TColumns
345 @TColumns
329− @Id
346+ @TUnreify
330− @Aggregate
347+ @(Col (Reify Aggregate))
331− @(Eval (rep Aggregate))
348+ @(Eval (rep (Reify Aggregate)))
332− (const toColumns)
349+ (\(_ :: proxy x) -> toColumns . reify @_ @x Refl)
333− (\tag' Spec {nullity} (Aggregate a) ->
350+ (\tag' SSpec {nullity} (Reify (A (Aggregate a))) ->
334− Aggregate $ sguard (tag ==. litExpr tag') . snullify nullity <$> a)
351+ Reify $ A $ Aggregate $ sguard (tag ==. litExpr tag') . snullify nullity <$> a)
335− (HIdentity (groupByExpr tag))
352+ (HType (Reify (A (groupByExpr tag))))
336 where
353 where
337 f =
354 f =
338− gfindex @Id @(Eval (rep Expr)) @agg .
355+ gfindex @TUnreify @(Eval (rep (Reify Expr))) @agg .
339 agg .
356 agg .
340− gftabulate @Id @(Eval (rep Aggregate)) @agg
357+ gftabulate @TUnreify @(Eval (rep (Reify Aggregate))) @agg
341− (HIdentity tag, exprs) =
358+ (HType (Reify (E tag)), exprs) =
342 gunbuildADT
359 gunbuildADT
343− @(TTable Expr)
360+ @(TTable (Reify Expr))
344 @TColumns
361 @TColumns
345− @Id
362+ @TUnreify
346− @Expr
363+ @(Col (Reify Expr))
347− @(Eval (rep Expr))
364+ @(Eval (rep (Reify Expr)))
348− (const fromColumns)
365+ (\(_ :: proxy x) -> unreify @_ @x Refl . fromColumns)
349− (\Spec {nullity} -> case nullity of
366+ (\SSpec {nullity} -> case nullity of
350 Null -> id
367 Null -> id
351− NotNull -> unsafeUnnullify) $
368+ NotNull -> \(Reify (E a)) -> Reify (E (unsafeUnnullify a))) $
369+ hreify $
352 gtoColumns es
370 gtoColumns es
src/Rel8/Generic/Construction/ADT.hs+27−20
@@ -1,7 +1,6 @@
1{-# language AllowAmbiguousTypes #-}
1{-# language AllowAmbiguousTypes #-}
2{-# language BlockArguments #-}
2{-# language BlockArguments #-}
3{-# language DataKinds #-}
3{-# language DataKinds #-}
4−{-# language FlexibleContexts #-}
5{-# language FlexibleInstances #-}
4{-# language FlexibleInstances #-}
6{-# language MultiParamTypeClasses #-}
5{-# language MultiParamTypeClasses #-}
7{-# language RankNTypes #-}
6{-# language RankNTypes #-}
@@ -50,12 +49,12 @@ import Rel8.Generic.Construction.Record
50import Rel8.Generic.Table.ADT ( GColumnsADT, GColumnsADT' )
49import Rel8.Generic.Table.ADT ( GColumnsADT, GColumnsADT' )
51import Rel8.Generic.Table.Record ( GColumns )
50import Rel8.Generic.Table.Record ( GColumns )
52import Rel8.Schema.HTable ( HTable )
51import Rel8.Schema.HTable ( HTable )
53−import Rel8.Schema.HTable.Identity ( HIdentity )
52+import Rel8.Schema.HTable.Identity ( HType )
54import Rel8.Schema.HTable.Label ( HLabel, hlabel, hunlabel )
53import Rel8.Schema.HTable.Label ( HLabel, hlabel, hunlabel )
55import Rel8.Schema.HTable.Nullify ( HNullify, hnulls, hnullify, hunnullify )
54import Rel8.Schema.HTable.Nullify ( HNullify, hnulls, hnullify, hunnullify )
56import Rel8.Schema.HTable.Product ( HProduct( HProduct ) )
55import Rel8.Schema.HTable.Product ( HProduct( HProduct ) )
57import Rel8.Schema.Null ( Nullify )
56import Rel8.Schema.Null ( Nullify )
58−import Rel8.Schema.Spec ( Spec )
57+import Rel8.Schema.Spec ( Spec( Spec ), SSpec )
59import qualified Rel8.Schema.Kind as K
58import qualified Rel8.Schema.Kind as K
60import Rel8.Type.Tag ( Tag( Tag ) )
59import Rel8.Type.Tag ( Tag( Tag ) )
61
60
@@ -63,16 +62,24 @@ import Rel8.Type.Tag ( Tag( Tag ) )
63import Data.Text ( pack )
62import Data.Text ( pack )
64
63
65
64
66−type Null :: K.Context -> Type
65+type Null :: K.HContext -> Type
67−type Null context = forall a. Spec a -> context (Nullify a)
66+type Null context = forall a. ()
67+ => SSpec ('Spec a)
68+ -> context ('Spec (Nullify a))
68
69
69
70
70−type Nullifier :: K.Context -> Type
71+type Nullifier :: K.HContext -> Type
71−type Nullifier context = forall a. Spec a -> context a -> context (Nullify a)
72+type Nullifier context = forall a. ()
73+ => SSpec ('Spec a)
74+ -> context ('Spec a)
75+ -> context ('Spec (Nullify a))
72
76
73
77
74−type Unnullifier :: K.Context -> Type
78+type Unnullifier :: K.HContext -> Type
75−type Unnullifier context = forall a. Spec a -> context (Nullify a) -> context a
79+type Unnullifier context = forall a. ()
80+ => SSpec ('Spec a)
81+ -> context ('Spec (Nullify a))
82+ -> context ('Spec a)
76
83
77
84
78type NoConstructor :: Symbol -> Symbol -> ErrorMessage
85type NoConstructor :: Symbol -> Symbol -> ErrorMessage
@@ -181,12 +188,12 @@ type GConstructableADT
181 :: (Type -> Exp Constraint)
188 :: (Type -> Exp Constraint)
182 -> (Type -> Exp K.HTable)
189 -> (Type -> Exp K.HTable)
183 -> (Type -> Exp Type)
190 -> (Type -> Exp Type)
184− -> K.Context -> (Type -> Type) -> Constraint
191+ -> K.HContext -> (Type -> Type) -> Constraint
185class GConstructableADT _Table _Columns f context rep where
192class GConstructableADT _Table _Columns f context rep where
186 gbuildADT :: ()
193 gbuildADT :: ()
187 => ToColumns _Table _Columns f context
194 => ToColumns _Table _Columns f context
188 -> (Tag -> Nullifier context)
195 -> (Tag -> Nullifier context)
189− -> HIdentity Tag context
196+ -> HType Tag context
190 -> GFieldsADT f rep
197 -> GFieldsADT f rep
191 -> GColumnsADT _Columns rep context
198 -> GColumnsADT _Columns rep context
192
199
@@ -194,13 +201,13 @@ class GConstructableADT _Table _Columns f context rep where
194 => FromColumns _Table _Columns f context
201 => FromColumns _Table _Columns f context
195 -> Unnullifier context
202 -> Unnullifier context
196 -> GColumnsADT _Columns rep context
203 -> GColumnsADT _Columns rep context
197− -> (HIdentity Tag context, GFieldsADT f rep)
204+ -> (HType Tag context, GFieldsADT f rep)
198
205
199 gconstructADT :: ()
206 gconstructADT :: ()
200 => ToColumns _Table _Columns f context
207 => ToColumns _Table _Columns f context
201 -> Null context
208 -> Null context
202 -> Nullifier context
209 -> Nullifier context
203− -> (Tag -> HIdentity Tag context)
210+ -> (Tag -> HType Tag context)
204 -> GConstructors f rep (GColumnsADT _Columns rep context)
211 -> GConstructors f rep (GColumnsADT _Columns rep context)
205
212
206 gdeconstructADT :: ()
213 gdeconstructADT :: ()
@@ -208,11 +215,11 @@ class GConstructableADT _Table _Columns f context rep where
208 -> Unnullifier context
215 -> Unnullifier context
209 -> GConstructors f rep r
216 -> GConstructors f rep r
210 -> GColumnsADT _Columns rep context
217 -> GColumnsADT _Columns rep context
211− -> (HIdentity Tag context, NonEmpty (Tag, r))
218+ -> (HType Tag context, NonEmpty (Tag, r))
212
219
213
220
214instance
221instance
215− ( htable ~ HLabel "tag" (HIdentity Tag)
222+ ( htable ~ HLabel "tag" (HType Tag)
216 , GConstructableADT' _Table _Columns f context htable rep
223 , GConstructableADT' _Table _Columns f context htable rep
217 )
224 )
218 => GConstructableADT _Table _Columns f context (M1 D meta rep)
225 => GConstructableADT _Table _Columns f context (M1 D meta rep)
@@ -238,7 +245,7 @@ type GConstructableADT'
238 :: (Type -> Exp Constraint)
245 :: (Type -> Exp Constraint)
239 -> (Type -> Exp K.HTable)
246 -> (Type -> Exp K.HTable)
240 -> (Type -> Exp Type)
247 -> (Type -> Exp Type)
241− -> K.Context -> K.HTable -> (Type -> Type) -> Constraint
248+ -> K.HContext -> K.HTable -> (Type -> Type) -> Constraint
242class GConstructableADT' _Table _Columns f context htable rep where
249class GConstructableADT' _Table _Columns f context htable rep where
243 gbuildADT' :: ()
250 gbuildADT' :: ()
244 => ToColumns _Table _Columns f context
251 => ToColumns _Table _Columns f context
@@ -376,19 +383,19 @@ type GMakeableADT
376 :: (Type -> Exp Constraint)
383 :: (Type -> Exp Constraint)
377 -> (Type -> Exp K.HTable)
384 -> (Type -> Exp K.HTable)
378 -> (Type -> Exp Type)
385 -> (Type -> Exp Type)
379− -> K.Context -> Symbol -> (Type -> Type) -> Constraint
386+ -> K.HContext -> Symbol -> (Type -> Type) -> Constraint
380class GMakeableADT _Table _Columns f context name rep where
387class GMakeableADT _Table _Columns f context name rep where
381 gmakeADT :: ()
388 gmakeADT :: ()
382 => ToColumns _Table _Columns f context
389 => ToColumns _Table _Columns f context
383 -> Null context
390 -> Null context
384 -> Nullifier context
391 -> Nullifier context
385− -> (Tag -> HIdentity Tag context)
392+ -> (Tag -> HType Tag context)
386 -> GFields f (GConstructorADT name rep)
393 -> GFields f (GConstructorADT name rep)
387 -> GColumnsADT _Columns rep context
394 -> GColumnsADT _Columns rep context
388
395
389
396
390instance
397instance
391− ( htable ~ HLabel "tag" (HIdentity Tag)
398+ ( htable ~ HLabel "tag" (HType Tag)
392 , meta ~ 'MetaData datatype _module _package _newtype
399 , meta ~ 'MetaData datatype _module _package _newtype
393 , fallback ~ TypeError (NoConstructor datatype name)
400 , fallback ~ TypeError (NoConstructor datatype name)
394 , fields ~ GFields f (GConstructorADT' name rep fallback)
401 , fields ~ GFields f (GConstructorADT' name rep fallback)
@@ -410,7 +417,7 @@ type GMakeableADT'
410 :: (Type -> Exp Constraint)
417 :: (Type -> Exp Constraint)
411 -> (Type -> Exp K.HTable)
418 -> (Type -> Exp K.HTable)
412 -> (Type -> Exp Type)
419 -> (Type -> Exp Type)
413− -> K.Context -> K.HTable -> Symbol -> (Type -> Type) -> Type -> Constraint
420+ -> K.HContext -> K.HTable -> Symbol -> (Type -> Type) -> Type -> Constraint
414class GMakeableADT' _Table _Columns f context htable name rep fields where
421class GMakeableADT' _Table _Columns f context htable name rep fields where
415 gmakeADT' :: ()
422 gmakeADT' :: ()
416 => ToColumns _Table _Columns f context
423 => ToColumns _Table _Columns f context
src/Rel8/Generic/Construction/Record.hs+3−3
@@ -43,7 +43,7 @@ type FromColumns
43 :: (Type -> Exp Constraint)
43 :: (Type -> Exp Constraint)
44 -> (Type -> Exp K.HTable)
44 -> (Type -> Exp K.HTable)
45 -> (Type -> Exp Type)
45 -> (Type -> Exp Type)
46− -> K.Context
46+ -> K.HContext
47 -> Type
47 -> Type
48type FromColumns _Table _Columns f context = forall proxy x.
48type FromColumns _Table _Columns f context = forall proxy x.
49 Eval (_Table x) => proxy x -> Eval (_Columns x) context -> Eval (f x)
49 Eval (_Table x) => proxy x -> Eval (_Columns x) context -> Eval (f x)
@@ -53,7 +53,7 @@ type ToColumns
53 :: (Type -> Exp Constraint)
53 :: (Type -> Exp Constraint)
54 -> (Type -> Exp K.HTable)
54 -> (Type -> Exp K.HTable)
55 -> (Type -> Exp Type)
55 -> (Type -> Exp Type)
56− -> K.Context
56+ -> K.HContext
57 -> Type
57 -> Type
58type ToColumns _Table _Columns f context = forall proxy x.
58type ToColumns _Table _Columns f context = forall proxy x.
59 Eval (_Table x) => proxy x -> Eval (f x) -> Eval (_Columns x) context
59 Eval (_Table x) => proxy x -> Eval (f x) -> Eval (_Columns x) context
@@ -117,7 +117,7 @@ type GConstructable
117 :: (Type -> Exp Constraint)
117 :: (Type -> Exp Constraint)
118 -> (Type -> Exp K.HTable)
118 -> (Type -> Exp K.HTable)
119 -> (Type -> Exp Type)
119 -> (Type -> Exp Type)
120− -> K.Context -> (Type -> Type) -> Constraint
120+ -> K.HContext -> (Type -> Type) -> Constraint
121class GConstructable _Table _Columns f context rep where
121class GConstructable _Table _Columns f context rep where
122 gconstruct :: ()
122 gconstruct :: ()
123 => ToColumns _Table _Columns f context
123 => ToColumns _Table _Columns f context
src/Rel8/Generic/Map.hs+64−20
@@ -1,19 +1,26 @@
1+{-# language AllowAmbiguousTypes #-}
1{-# language DataKinds #-}
2{-# language DataKinds #-}
3+{-# language EmptyCase #-}
4+{-# language FlexibleInstances #-}
5+{-# language LambdaCase #-}
6+{-# language MultiParamTypeClasses #-}
7+{-# language RankNTypes #-}
8+{-# language ScopedTypeVariables #-}
2{-# language StandaloneKindSignatures #-}
9{-# language StandaloneKindSignatures #-}
10+{-# language TypeApplications #-}
3{-# language TypeFamilies #-}
11{-# language TypeFamilies #-}
4{-# language TypeOperators #-}
12{-# language TypeOperators #-}
5{-# language UndecidableInstances #-}
13{-# language UndecidableInstances #-}
6
14
7module Rel8.Generic.Map
15module Rel8.Generic.Map
8− ( GMap
16+ ( GMap, GMappable (gmap, gunmap)
9− , Map
10 )
17 )
11where
18where
12
19
13-- base
20-- base
14−import Data.Kind ( Type )
21+import Data.Kind ( Constraint, Type )
15import GHC.Generics
22import GHC.Generics
16− ( (:+:), (:*:), K1, M1, U1, V1
23+ ( (:+:)( L1, R1 ), (:*:)( (:*:) ), K1( K1 ), M1( M1 ), U1( U1 ), V1
17 )
24 )
18import Prelude ()
25import Prelude ()
19
26
@@ -31,19 +38,56 @@ type family GMap f rep where
31 GMap f (K1 i a) = K1 i (Eval (f a))
38 GMap f (K1 i a) = K1 i (Eval (f a))
32
39
33
40
34−-- | Map a @Type -> Type@ function over the @Type@-kinded type variables in
35−-- of a type constructor.
36−type Map :: (Type -> Exp Type) -> Type -> Type
41+type GMappable :: (Type -> Exp Constraint) -> (Type -> Type) -> Constraint
37−type family Map f a where
42+class GMappable constraint rep where
38− Map p (t a b c d e f g) =
43+ gmap :: ()
39− t (Eval (p a)) (Eval (p b)) (Eval (p c)) (Eval (p d)) (Eval (p e))
44+ => proxy f
40− (Eval (p f)) (Eval (p g))
45+ -> (forall a. Eval (constraint a) => a -> Eval (f a))
41− Map p (t a b c d e f) =
46+ -> rep x
42− t (Eval (p a)) (Eval (p b)) (Eval (p c)) (Eval (p d)) (Eval (p e))
47+ -> GMap f rep x
43− (Eval (p f))
48+
44− Map p (t a b c d e) =
49+ gunmap :: ()
45− t (Eval (p a)) (Eval (p b)) (Eval (p c)) (Eval (p d)) (Eval (p e))
50+ => proxy f
46− Map p (t a b c d) = t (Eval (p a)) (Eval (p b)) (Eval (p c)) (Eval (p d))
51+ -> (forall a. Eval (constraint a) => Eval (f a) -> a)
47− Map p (t a b c) = t (Eval (p a)) (Eval (p b)) (Eval (p c))
52+ -> GMap f rep x
48− Map p (t a b) = t (Eval (p a)) (Eval (p b))
53+ -> rep x
49− Map p (t a) = t (Eval (p a))
54+
55+
56+instance GMappable constraint rep => GMappable constraint (M1 i c rep) where
57+ gmap proxy f (M1 a) = M1 (gmap @constraint proxy f a)
58+ gunmap proxy f (M1 a) = M1 (gunmap @constraint proxy f a)
59+
60+
61+instance GMappable constraint V1 where
62+ gmap _ _ = \case
63+ gunmap _ _ = \case
64+
65+
66+instance (GMappable constraint rep1, GMappable constraint rep2) =>
67+ GMappable constraint (rep1 :+: rep2)
68+ where
69+ gmap proxy f = \case
70+ L1 a -> L1 (gmap @constraint proxy f a)
71+ R1 a -> R1 (gmap @constraint proxy f a)
72+ gunmap proxy f = \case
73+ L1 a -> L1 (gunmap @constraint proxy f a)
74+ R1 a -> R1 (gunmap @constraint proxy f a)
75+
76+
77+instance GMappable constraint U1 where
78+ gmap _ _ U1 = U1
79+ gunmap _ _ U1 = U1
80+
81+
82+instance (GMappable constraint rep1, GMappable constraint rep2) =>
83+ GMappable constraint (rep1 :*: rep2)
84+ where
85+ gmap proxy f (a :*: b) =
86+ gmap @constraint proxy f a :*: gmap @constraint proxy f b
87+ gunmap proxy f (a :*: b) =
88+ gunmap @constraint proxy f a :*: gunmap @constraint proxy f b
89+
90+
91+instance Eval (constraint a) => GMappable constraint (K1 i a) where
92+ gmap _ f (K1 a) = K1 (f a)
93+ gunmap _ f (K1 a) = K1 (f a)
src/Rel8/Generic/Record.hs−2
@@ -1,6 +1,5 @@
1{-# language AllowAmbiguousTypes #-}
1{-# language AllowAmbiguousTypes #-}
2{-# language DataKinds #-}
2{-# language DataKinds #-}
3−{-# language FlexibleContexts #-}
4{-# language FlexibleInstances #-}
3{-# language FlexibleInstances #-}
5{-# language MultiParamTypeClasses #-}
4{-# language MultiParamTypeClasses #-}
6{-# language PolyKinds #-}
5{-# language PolyKinds #-}
@@ -142,7 +141,6 @@ instance {-# OVERLAPPABLE #-} Snd (Count n rep) ~ rep => Countable n rep where
142 uncount = id
141 uncount = id
143
142
144
143
145−type Record :: Type -> Type
146newtype Record a = Record
144newtype Record a = Record
147 { unrecord :: a
145 { unrecord :: a
148 }
146 }
src/Rel8/Generic/Reify.hsnew file+24
@@ -0,0 +1,24 @@
1+{-# language StandaloneKindSignatures #-}
2+{-# language TypeFamilies #-}
3+
4+module Rel8.Generic.Reify
5+ ( ARep
6+ )
7+where
8+
9+-- base
10+import Data.Functor.Contravariant ( Contravariant, contramap )
11+import Data.Kind ( Type )
12+import Data.Void ( Void, absurd )
13+import GHC.Generics ( Generic, Rep, from, to )
14+import Prelude
15+
16+
17+type ARep :: (Type -> Type) -> Type
18+newtype ARep rep = ARep (rep Void)
19+
20+
21+instance (Contravariant rep, Functor rep) => Generic (ARep rep) where
22+ type Rep (ARep rep) = rep
23+ from (ARep a) = fmap absurd a
24+ to = ARep . contramap absurd
src/Rel8/Generic/Rel8able.hs+71−178
@@ -1,18 +1,13 @@
1{-# language AllowAmbiguousTypes #-}
1{-# language AllowAmbiguousTypes #-}
2−{-# language ConstraintKinds #-}
3{-# language DataKinds #-}
2{-# language DataKinds #-}
4{-# language DefaultSignatures #-}
3{-# language DefaultSignatures #-}
5{-# language FlexibleContexts #-}
4{-# language FlexibleContexts #-}
6{-# language FlexibleInstances #-}
5{-# language FlexibleInstances #-}
7−{-# language LambdaCase #-}
8{-# language MultiParamTypeClasses #-}
6{-# language MultiParamTypeClasses #-}
9−{-# language PolyKinds #-}
10−{-# language QuantifiedConstraints #-}
11{-# language ScopedTypeVariables #-}
7{-# language ScopedTypeVariables #-}
12{-# language StandaloneKindSignatures #-}
8{-# language StandaloneKindSignatures #-}
13{-# language TypeApplications #-}
9{-# language TypeApplications #-}
14−{-# language TypeFamilyDependencies #-}
10+{-# language TypeFamilies #-}
15−{-# language TypeOperators #-}
16{-# language UndecidableInstances #-}
11{-# language UndecidableInstances #-}
17
12
18module Rel8.Generic.Rel8able
13module Rel8.Generic.Rel8able
@@ -20,39 +15,35 @@ module Rel8.Generic.Rel8able
20 , Algebra
15 , Algebra
21 , GRep
16 , GRep
22 , GColumns, gfromColumns, gtoColumns
17 , GColumns, gfromColumns, gtoColumns
23− , GFromExprs, gfromResult, gtoResult
18+ , greify, gunreify
24− , TSerialize, serialize, deserialize
19+ , TUnreifyContext
25 )
20 )
26where
21where
27
22
28-- base
23-- base
29−import Data.Functor.Identity ( Identity )
30import Data.Kind ( Constraint, Type )
24import Data.Kind ( Constraint, Type )
31−import Data.Type.Bool ( type (&&) )
25+import Data.Proxy ( Proxy( Proxy ) )
26+import Data.Type.Equality ( (:~:)( Refl ) )
32import GHC.Generics ( Generic, Rep, from, to )
27import GHC.Generics ( Generic, Rep, from, to )
33import Prelude
28import Prelude
34
29
35-- rel8
30-- rel8
36−import Rel8.Aggregate ( Aggregate )
31+import Rel8.Kind.Context ( Reifiable )
37−import Rel8.Expr ( Expr )
38−import Rel8.FCF ( Exp, Eval )
32+import Rel8.FCF ( Eval, Exp )
33+import Rel8.Generic.Map ( GMap, GMappable, gmap, gunmap )
39import Rel8.Generic.Record ( Record(..) )
34import Rel8.Generic.Record ( Record(..) )
40import Rel8.Generic.Table ( GAlgebra )
35import Rel8.Generic.Table ( GAlgebra )
41import qualified Rel8.Generic.Table.Record as G
36import qualified Rel8.Generic.Table.Record as G
42import qualified Rel8.Kind.Algebra as K ( Algebra(..) )
37import qualified Rel8.Kind.Algebra as K ( Algebra(..) )
43−import Rel8.Kind.Context ( SContext(..) )
38+import Rel8.Schema.Context ( Col )
44−import Rel8.Schema.Field ( Field )
45import Rel8.Schema.HTable ( HTable )
39import Rel8.Schema.HTable ( HTable )
46import qualified Rel8.Schema.Kind as K
40import qualified Rel8.Schema.Kind as K
47−import Rel8.Schema.Name ( Name )
41+import Rel8.Schema.Reify ( Reify, UnwrapReify )
48import Rel8.Schema.Result ( Result )
42import Rel8.Schema.Result ( Result )
49import Rel8.Table
43import Rel8.Table
50− ( Table, Columns, Context, fromColumns, toColumns
44+ ( fromColumns, toColumns, reify, unreify
51− , FromExprs, fromResult, toResult
52− , Transpose
53− , TTable, TColumns
45+ , TTable, TColumns, TContext, TUnreify
54 )
46 )
55−import Rel8.Table.Transpose ( Transposes )
56
47
57
48
58-- | The kind of 'Rel8able' types
49-- | The kind of 'Rel8able' types
@@ -60,59 +51,6 @@ type KRel8able :: Type
60type KRel8able = K.Rel8able
51type KRel8able = K.Rel8able
61
52
62
53
63−-- This is almost 'Data.Type.Equality.==', but we add an extra case.
64−type (==) :: k -> k -> Bool
65−type family a == b where
66− -- This extra case is needed to solve the equation "a == a" (where a is a
67− -- KRel8able), which occurs when we have polymorphic Rel8ables
68− -- (e.g., newtype T t f = T { x :: t a })
69− (a :: KRel8able) == (a :: KRel8able) = 'True
70−
71− -- This extra case is needed to solve the equation "a == Identity a",
72− -- which occurs when we have polymorphic Rel8ables
73− -- (e.g., newtype T a f = T { x :: Column f a })
74− a == Identity a = 'False
75−
76− -- These cases are exactly the same as those in 'Data.Type.Equality.==.
77− f a == g b = f == g && a == b
78− a == a = 'True
79− _ == _ = 'False
80−
81−
82−type Serialize :: Bool -> Type -> Type -> Constraint
83−class transposition ~ (a == Transpose Result expr) =>
84− Serialize transposition expr a
85− where
86− serialize :: a -> Columns expr Result
87− deserialize :: Columns expr Result -> a
88−
89−
90−instance
91− ( (a == Transpose Result expr) ~ 'True
92− , Transposes Expr Result expr a
93− )
94− => Serialize 'True expr a
95− where
96− serialize = toColumns
97− deserialize = fromColumns
98−
99−
100−instance
101− ( (a == Transpose Result expr) ~ 'False
102− , Table (Context expr) expr
103− , FromExprs expr ~ a
104− )
105− => Serialize 'False expr a
106− where
107− serialize = toResult @_ @expr
108− deserialize = fromResult @_ @expr
109−
110−
111−data TSerialize :: Type -> Type -> Exp Constraint
112−type instance Eval (TSerialize expr a) =
113− Serialize (a == Transpose Result expr) expr a
114−
115−
116-- | This type class allows you to define custom 'Table's using higher-kinded
54-- | This type class allows you to define custom 'Table's using higher-kinded
117-- data types. Higher-kinded data types are data types of the pattern:
55-- data types. Higher-kinded data types are data types of the pattern:
118--
56--
@@ -146,7 +84,7 @@ type instance Eval (TSerialize expr a) =
146-- [Supplying @Rel8able@ instances]
84-- [Supplying @Rel8able@ instances]
147--
85--
148-- This type class should be derived generically for all table types in your
86-- This type class should be derived generically for all table types in your
149−-- project. To do this, enable the @DeriveAnyClass@ and @DeriveGeneric@ language
87+-- project. To do this, enable the @DeriveAnyType@ and @DeriveGeneric@ language
150-- extensions:
88-- extensions:
151--
89--
152-- @
90-- @
@@ -158,124 +96,79 @@ type instance Eval (TSerialize expr a) =
158type Rel8able :: K.Rel8able -> Constraint
96type Rel8able :: K.Rel8able -> Constraint
159class HTable (GColumns t) => Rel8able t where
97class HTable (GColumns t) => Rel8able t where
160 type GColumns t :: K.HTable
98 type GColumns t :: K.HTable
161− type GFromExprs t :: Type
162
99
100+ gfromColumns :: Reifiable context
163− gfromColumns :: SContext context -> GColumns t context -> t context
101+ => GColumns t (Col (Reify context)) -> t (Reify context)
102+
103+ gtoColumns :: Reifiable context
164− gtoColumns :: SContext context -> t context -> GColumns t context
104+ => t (Reify context) -> GColumns t (Col (Reify context))
165
105
166− gfromResult :: GColumns t Result -> GFromExprs t
106+ greify :: Reifiable context
167− gtoResult :: GFromExprs t -> GColumns t Result
107+ => t context -> t (Reify context)
168
108
109+ gunreify :: Reifiable context
110+ => t (Reify context) -> t context
111+
169− type GColumns t = G.GColumns TColumns (GRep t Expr)
112+ type GColumns t = G.GColumns TColumns (GRep t (Reify Result))
170− type GFromExprs t = t Result
171
113
172 default gfromColumns :: forall context.
114 default gfromColumns :: forall context.
173− ( SRel8able t Aggregate
115+ ( Generic (Record (t (Reify context)))
174− , SRel8able t Expr
116+ , G.GTable (TTable (Reify context)) TColumns (Col (Reify context)) (GRep t (Reify context))
175− , forall table. SRel8able t (Field table)
117+ , G.GColumns TColumns (GRep t (Reify context)) ~ GColumns t
176− , SRel8able t Name
177− , SSerialize t
178 )
118 )
179− => SContext context -> GColumns t context -> t context
119+ => GColumns t (Col (Reify context)) -> t (Reify context)
180− gfromColumns = \case
120+ gfromColumns =
181− SAggregate -> sfromColumns
121+ unrecord .
182− SExpr -> sfromColumns
122+ to .
183− SField -> sfromColumns
123+ G.gfromColumns @(TTable (Reify context)) @TColumns fromColumns
184− SName -> sfromColumns
185− SResult -> sfromResult
186
124
187 default gtoColumns :: forall context.
125 default gtoColumns :: forall context.
188− ( SRel8able t Aggregate
126+ ( Generic (Record (t (Reify context)))
189− , SRel8able t Expr
127+ , G.GTable (TTable (Reify context)) TColumns (Col (Reify context)) (GRep t (Reify context))
190− , forall table. SRel8able t (Field table)
128+ , G.GColumns TColumns (GRep t (Reify context)) ~ GColumns t
191− , SRel8able t Name
192− , SSerialize t
193 )
129 )
194− => SContext context -> t context -> GColumns t context
130+ => t (Reify context) -> GColumns t (Col (Reify context))
195− gtoColumns = \case
131+ gtoColumns =
196− SAggregate -> stoColumns
132+ G.gtoColumns @(TTable (Reify context)) @TColumns toColumns .
197− SExpr -> stoColumns
133+ from .
198− SField -> stoColumns
134+ Record
199− SName -> stoColumns
135+
200− SResult -> stoResult
136+ default greify :: forall context.
201−
137+ ( Generic (Record (t context))
202− default gfromResult :: (SSerialize t, GFromExprs t ~ t Result)
138+ , Generic (Record (t (Reify context)))
203− => GColumns t Result -> GFromExprs t
139+ , GMappable (TTable (Reify context)) (GRep t (Reify context))
204− gfromResult = sfromResult
140+ , GRep t context ~ GMap TUnreify (GRep t (Reify context))
205−
141+ )
206− default gtoResult :: (SSerialize t, GFromExprs t ~ t Result)
142+ => t context -> t (Reify context)
207− => GFromExprs t -> GColumns t Result
143+ greify =
208− gtoResult = stoResult
144+ unrecord .
145+ to .
146+ gunmap @(TTable (Reify context)) (Proxy @TUnreify) (reify Refl) .
147+ from .
148+ Record
149+
150+ default gunreify :: forall context.
151+ ( Generic (Record (t context))
152+ , Generic (Record (t (Reify context)))
153+ , GMappable (TTable (Reify context)) (GRep t (Reify context))
154+ , GRep t context ~ GMap TUnreify (GRep t (Reify context))
155+ )
156+ => t (Reify context) -> t context
157+ gunreify =
158+ unrecord .
159+ to .
160+ gmap @(TTable (Reify context)) (Proxy @TUnreify) (unreify Refl) .
161+ from .
162+ Record
209
163
210
164
211type Algebra :: K.Rel8able -> K.Algebra
165type Algebra :: K.Rel8able -> K.Algebra
212−type Algebra t = GAlgebra (GRep t Expr)
166+type Algebra t = GAlgebra (GRep t (Reify Result))
213
167
214
168
215type GRep :: K.Rel8able -> K.Context -> Type -> Type
169type GRep :: K.Rel8able -> K.Context -> Type -> Type
216type GRep t context = Rep (Record (t context))
170type GRep t context = Rep (Record (t context))
217
171
218
172
219−type SRel8able :: K.Rel8able -> K.Context -> Constraint
173+data TUnreifyContext :: Type -> Exp K.Context
220−class
174+type instance Eval (TUnreifyContext a) = UnwrapReify (Eval (TContext a))
221− ( Generic (Record (t context))
222− , G.GTable (TTable context) TColumns (GRep t context)
223− , G.GColumns TColumns (GRep t context) ~ GColumns t
224− )
225− => SRel8able t context
226−instance
227− ( Generic (Record (t context))
228− , G.GTable (TTable context) TColumns (GRep t context)
229− , G.GColumns TColumns (GRep t context) ~ GColumns t
230− )
231− => SRel8able t context
232−
233−
234−type SSerialize :: K.Rel8able -> Constraint
235−type SSerialize t =
236− ( Generic (Record (t Result))
237− , G.GSerialize TSerialize TColumns (GRep t Expr) (GRep t Result)
238− , G.GColumns TColumns (GRep t Expr) ~ GColumns t
239− )
240−
241−
242−sfromColumns :: forall t context. SRel8able t context
243− => GColumns t context -> t context
244−sfromColumns =
245− unrecord .
246− to .
247− G.gfromColumns @(TTable context) @TColumns fromColumns
248−
249−
250−stoColumns :: forall t context. SRel8able t context
251− => t context -> GColumns t context
252−stoColumns =
253− G.gtoColumns @(TTable context) @TColumns toColumns .
254− from .
255− Record
256−
257−
258−sfromResult :: forall t. SSerialize t
259− => GColumns t Result -> t Result
260−sfromResult =
261− unrecord .
262− to .
263− G.gfromResult
264− @TSerialize
265− @TColumns
266− @(GRep t Expr)
267− @(GRep t Result)
268− (\(_ :: proxy x) -> deserialize @_ @x)
269−
270−
271−stoResult :: forall t. SSerialize t
272− => t Result -> GColumns t Result
273−stoResult =
274− G.gtoResult
275− @TSerialize
276− @TColumns
277− @(GRep t Expr)
278− @(GRep t Result)
279− (\(_ :: proxy x) -> serialize @_ @x) .
280− from .
281− Record
src/Rel8/Generic/Table.hs+107−22
@@ -12,7 +12,8 @@
12{-# language UndecidableInstances #-}
12{-# language UndecidableInstances #-}
13
13
14module Rel8.Generic.Table
14module Rel8.Generic.Table
15+ ( GGTable, GGColumns, GGContext, ggfromColumns, ggtoColumns, ggtable
15− ( GGSerialize, GGColumns, ggfromResult, ggtoResult
16+ , GGToExprs, ggfromResult, ggtoResult
16 , GAlgebra
17 , GAlgebra
17 )
18 )
18where
19where
@@ -25,19 +26,43 @@ import Prelude ()
25-- rel8
26-- rel8
26import Rel8.FCF ( Eval, Exp )
27import Rel8.FCF ( Eval, Exp )
27import Rel8.Generic.Table.ADT
28import Rel8.Generic.Table.ADT
29+ ( GTableADT, GColumnsADT, gfromColumnsADT, gtoColumnsADT, gtableADT
28− ( GSerializeADT, GColumnsADT, gtoResultADT, gfromResultADT
30+ , GToExprsADT, gtoResultADT, gfromResultADT
31+ )
32+import Rel8.Generic.Table.Record
33+ ( GTable, GColumns, GContext, gfromColumns, gtoColumns, gtable
34+ , GToExprs, gtoResult, gfromResult
29 )
35 )
30−import Rel8.Generic.Table.Record ( GSerialize, GColumns, gtoResult, gfromResult )
31import Rel8.Kind.Algebra
36import Rel8.Kind.Algebra
32 ( Algebra( Product, Sum )
37 ( Algebra( Product, Sum )
33 , SAlgebra( SProduct, SSum )
38 , SAlgebra( SProduct, SSum )
34 , KnownAlgebra, algebraSing
39 , KnownAlgebra, algebraSing
35 )
40 )
41+import Rel8.Schema.Context ( Col )
36import qualified Rel8.Schema.Kind as K
42import qualified Rel8.Schema.Kind as K
43+import Rel8.Schema.Null ( Nullify )
44+import Rel8.Schema.Spec ( Spec( Spec ), SSpec )
37import Rel8.Schema.Result ( Result )
45import Rel8.Schema.Result ( Result )
38
46
39
47
40−data GGSerialize
48+data GGTable
49+ :: Algebra
50+ -> (Type -> Exp Constraint)
51+ -> (Type -> Exp K.HTable)
52+ -> K.HContext
53+ -> (Type -> Type)
54+ -> Exp Constraint
55+
56+
57+type instance Eval (GGTable 'Product _Table _Columns context rep) =
58+ GTable _Table _Columns context rep
59+
60+
61+type instance Eval (GGTable 'Sum _Table _Columns context rep) =
62+ GTableADT _Table _Columns context rep
63+
64+
65+data GGToExprs
41 :: Algebra
66 :: Algebra
42 -> (Type -> Type -> Exp Constraint)
67 -> (Type -> Type -> Exp Constraint)
43 -> (Type -> Exp K.HTable)
68 -> (Type -> Exp K.HTable)
@@ -46,12 +71,12 @@ data GGSerialize
46 -> Exp Constraint
71 -> Exp Constraint
47
72
48
73
49−type instance Eval (GGSerialize 'Product _Serialize _Columns exprs rep) =
74+type instance Eval (GGToExprs 'Product _ToExprs _Columns exprs rep) =
50− GSerialize _Serialize _Columns exprs rep
75+ GToExprs _ToExprs _Columns exprs rep
51
76
52
77
53−type instance Eval (GGSerialize 'Sum _Serialize _Columns exprs rep) =
78+type instance Eval (GGToExprs 'Sum _ToExprs _Columns exprs rep) =
54− GSerializeADT _Serialize _Columns exprs rep
79+ GToExprsADT _ToExprs _Columns exprs rep
55
80
56
81
57data GGColumns
82data GGColumns
@@ -67,6 +92,19 @@ type instance Eval (GGColumns 'Product _Columns rep) = GColumns _Columns rep
67type instance Eval (GGColumns 'Sum _Columns rep) = GColumnsADT _Columns rep
92type instance Eval (GGColumns 'Sum _Columns rep) = GColumnsADT _Columns rep
68
93
69
94
95+data GGContext
96+ :: Algebra
97+ -> (Type -> Exp K.Context)
98+ -> (Type -> Type)
99+ -> Exp K.Context
100+
101+
102+type instance Eval (GGContext 'Product _Context rep) = GContext _Context rep
103+
104+
105+type instance Eval (GGContext 'Sum _Context _rep) = Result
106+
107+
70type GAlgebra :: (Type -> Type) -> Algebra
108type GAlgebra :: (Type -> Type) -> Algebra
71type family GAlgebra rep where
109type family GAlgebra rep where
72 GAlgebra (M1 _ _ rep) = GAlgebra rep
110 GAlgebra (M1 _ _ rep) = GAlgebra rep
@@ -77,27 +115,74 @@ type family GAlgebra rep where
77 GAlgebra (K1 _ _) = 'Product
115 GAlgebra (K1 _ _) = 'Product
78
116
79
117
118+ggfromColumns :: forall algebra _Table _Columns rep context x.
119+ ( KnownAlgebra algebra
120+ , Eval (GGTable algebra _Table _Columns context rep)
121+ )
122+ => (forall spec. algebra ~ 'Sum => context spec -> Col Result spec)
123+ -> (forall spec. algebra ~ 'Sum => Col Result spec -> context spec)
124+ -> (forall a. Eval (_Table a) => Eval (_Columns a) context -> a)
125+ -> Eval (GGColumns algebra _Columns rep) context
126+ -> rep x
127+ggfromColumns f g h x = case algebraSing @algebra of
128+ SProduct -> gfromColumns @_Table @_Columns h x
129+ SSum -> gfromColumnsADT @_Table @_Columns f g h x
130+
131+
132+ggtoColumns :: forall algebra _Table _Columns rep context x.
133+ ( KnownAlgebra algebra
134+ , Eval (GGTable algebra _Table _Columns context rep)
135+ )
136+ => (forall spec. algebra ~ 'Sum => context spec -> Col Result spec)
137+ -> (forall spec. algebra ~ 'Sum => Col Result spec -> context spec)
138+ -> (forall a. Eval (_Table a) => a -> Eval (_Columns a) context)
139+ -> rep x
140+ -> Eval (GGColumns algebra _Columns rep) context
141+ggtoColumns f g h x = case algebraSing @algebra of
142+ SProduct -> gtoColumns @_Table @_Columns h x
143+ SSum -> gtoColumnsADT @_Table @_Columns f g h x
144+
145+
146+ggtable :: forall algebra _Table _Columns rep context.
147+ ( KnownAlgebra algebra
148+ , Eval (GGTable algebra _Table _Columns context rep)
149+ )
150+ => (forall a proxy. Eval (_Table a) => proxy a -> Eval (_Columns a) context)
151+ -> (forall a. ()
152+ => SSpec ('Spec a)
153+ -> context ('Spec a)
154+ -> context ('Spec (Nullify a)))
155+ -> Eval (GGColumns algebra _Columns rep) context
156+ggtable = case algebraSing @algebra of
157+ SProduct -> \table _ -> gtable @_Table @_Columns @_ @rep table
158+ SSum -> gtableADT @_Table @_Columns @_ @rep
159+
160+
80−ggfromResult :: forall algebra _Serialize _Columns exprs rep x.
161+ggfromResult :: forall algebra _ToExprs _Columns exprs rep x.
81 ( KnownAlgebra algebra
162 ( KnownAlgebra algebra
82− , Eval (GGSerialize algebra _Serialize _Columns exprs rep)
163+ , Eval (GGToExprs algebra _ToExprs _Columns exprs rep)
83 )
164 )
84− => (forall expr a proxy. Eval (_Serialize expr a)
165+ => (forall expr a proxy. Eval (_ToExprs expr a)
166+ => proxy expr
85− => proxy expr -> Eval (_Columns expr) Result -> a)
167+ -> Eval (_Columns expr) (Col Result)
168+ -> a)
86− -> Eval (GGColumns algebra _Columns exprs) Result
169+ -> Eval (GGColumns algebra _Columns exprs) (Col Result)
87 -> rep x
170 -> rep x
88ggfromResult f x = case algebraSing @algebra of
171ggfromResult f x = case algebraSing @algebra of
89− SProduct -> gfromResult @_Serialize @_Columns @exprs @rep f x
172+ SProduct -> gfromResult @_ToExprs @_Columns @exprs f x
90− SSum -> gfromResultADT @_Serialize @_Columns @exprs @rep f x
173+ SSum -> gfromResultADT @_ToExprs @_Columns @exprs f x
91
174
92
175
93−ggtoResult :: forall algebra _Serialize _Columns exprs rep x.
176+ggtoResult :: forall algebra _ToExprs _Columns exprs rep x.
94 ( KnownAlgebra algebra
177 ( KnownAlgebra algebra
95− , Eval (GGSerialize algebra _Serialize _Columns exprs rep)
178+ , Eval (GGToExprs algebra _ToExprs _Columns exprs rep)
96 )
179 )
97− => (forall expr a proxy. Eval (_Serialize expr a)
180+ => (forall expr a proxy. Eval (_ToExprs expr a)
181+ => proxy expr
182+ -> a
98− => proxy expr -> a -> Eval (_Columns expr) Result)
183+ -> Eval (_Columns expr) (Col Result))
99 -> rep x
184 -> rep x
100− -> Eval (GGColumns algebra _Columns exprs) Result
185+ -> Eval (GGColumns algebra _Columns exprs) (Col Result)
101ggtoResult f x = case algebraSing @algebra of
186ggtoResult f x = case algebraSing @algebra of
102− SProduct -> gtoResult @_Serialize @_Columns @exprs @rep f x
187+ SProduct -> gtoResult @_ToExprs @_Columns @exprs f x
103− SSum -> gtoResultADT @_Serialize @_Columns @exprs @rep f x
188+ SSum -> gtoResultADT @_ToExprs @_Columns @exprs f x
src/Rel8/Generic/Table/ADT.hs+197−58
@@ -4,6 +4,7 @@
4{-# language FlexibleInstances #-}
4{-# language FlexibleInstances #-}
5{-# language LambdaCase #-}
5{-# language LambdaCase #-}
6{-# language MultiParamTypeClasses #-}
6{-# language MultiParamTypeClasses #-}
7+{-# language PolyKinds #-}
7{-# language RankNTypes #-}
8{-# language RankNTypes #-}
8{-# language ScopedTypeVariables #-}
9{-# language ScopedTypeVariables #-}
9{-# language StandaloneKindSignatures #-}
10{-# language StandaloneKindSignatures #-}
@@ -13,13 +14,13 @@
13{-# language UndecidableInstances #-}
14{-# language UndecidableInstances #-}
14
15
15module Rel8.Generic.Table.ADT
16module Rel8.Generic.Table.ADT
17+ ( GTableADT, GColumnsADT, gfromColumnsADT, gtoColumnsADT, gtableADT
18+ , GTableADT', GColumnsADT'
16− ( GSerializeADT, GColumnsADT, gfromResultADT, gtoResultADT
19+ , GToExprsADT, gfromResultADT, gtoResultADT
17− , GSerializeADT', GColumnsADT'
18 )
20 )
19where
21where
20
22
21-- base
23-- base
22−import Data.Functor.Identity ( Identity( Identity ) )
23import Data.Kind ( Constraint, Type )
24import Data.Kind ( Constraint, Type )
24import Data.Proxy ( Proxy( Proxy ) )
25import Data.Proxy ( Proxy( Proxy ) )
25import GHC.Generics
26import GHC.Generics
@@ -32,14 +33,22 @@ import Prelude hiding ( null )
32
33
33-- rel8
34-- rel8
34import Rel8.FCF ( Eval, Exp )
35import Rel8.FCF ( Eval, Exp )
35−import Rel8.Generic.Table.Record ( GSerialize, GColumns, gfromResult, gtoResult )
36+import Rel8.Generic.Table.Record
37+ ( GTable, GColumns, gtable
38+ , GToExprs, gfromResult, gtoResult
39+ )
36−import Rel8.Schema.HTable ( HTable )
40+import Rel8.Schema.HTable ( HTable, hmap )
37−import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )
41+import Rel8.Schema.HTable.Identity ( HIdentity( HType ), HType )
38import Rel8.Schema.HTable.Label ( HLabel, hlabel, hunlabel )
42import Rel8.Schema.HTable.Label ( HLabel, hlabel, hunlabel )
39import Rel8.Schema.HTable.Nullify ( HNullify, hnulls, hnullify, hunnullify )
43import Rel8.Schema.HTable.Nullify ( HNullify, hnulls, hnullify, hunnullify )
40import Rel8.Schema.HTable.Product ( HProduct( HProduct ) )
44import Rel8.Schema.HTable.Product ( HProduct( HProduct ) )
41import qualified Rel8.Schema.Kind as K
45import qualified Rel8.Schema.Kind as K
46+import Rel8.Schema.Null ( Nullify )
47+import Rel8.Schema.Spec ( Spec( Spec ), SSpec )
48+import Rel8.Schema.Result
49+ ( Col( R ), Result
42−import Rel8.Schema.Result ( Result, null, nullifier, unnullifier )
50+ , null, nullifier, unnullifier
51+ )
43import Rel8.Type.Tag ( Tag( Tag ) )
52import Rel8.Type.Tag ( Tag( Tag ) )
44
53
45-- text
54-- text
@@ -51,7 +60,7 @@ type GColumnsADT
51 -> (Type -> Type) -> K.HTable
60 -> (Type -> Type) -> K.HTable
52type family GColumnsADT _Columns rep where
61type family GColumnsADT _Columns rep where
53 GColumnsADT _Columns (M1 D _ rep) =
62 GColumnsADT _Columns (M1 D _ rep) =
54− GColumnsADT' _Columns (HLabel "tag" (HIdentity Tag)) rep
63+ GColumnsADT' _Columns (HLabel "tag" (HType Tag)) rep
55
64
56
65
57type GColumnsADT'
66type GColumnsADT'
@@ -65,118 +74,244 @@ type family GColumnsADT' _Columns htable rep where
65 HProduct htable (HLabel label (HNullify (GColumns _Columns rep)))
74 HProduct htable (HLabel label (HNullify (GColumns _Columns rep)))
66
75
67
76
68−type GSerializeADT
77+type GTableADT
78+ :: (Type -> Exp Constraint)
79+ -> (Type -> Exp K.HTable)
80+ -> K.HContext -> (Type -> Type) -> Constraint
81+class GTableADT _Table _Columns context rep where
82+ gfromColumnsADT :: ()
83+ => (forall spec. context spec -> Col Result spec)
84+ -> (forall spec. Col Result spec -> context spec)
85+ -> (forall a. Eval (_Table a) => Eval (_Columns a) context -> a)
86+ -> GColumnsADT _Columns rep context
87+ -> rep x
88+
89+ gtoColumnsADT :: ()
90+ => (forall spec. context spec -> Col Result spec)
91+ -> (forall spec. Col Result spec -> context spec)
92+ -> (forall a. Eval (_Table a) => a -> Eval (_Columns a) context)
93+ -> rep x
94+ -> GColumnsADT _Columns rep context
95+
96+ gtableADT :: ()
97+ => (forall a proxy. Eval (_Table a) => proxy a -> Eval (_Columns a) context)
98+ -> (forall a. ()
99+ => SSpec ('Spec a)
100+ -> context ('Spec a)
101+ -> context ('Spec (Nullify a)))
102+ -> GColumnsADT _Columns rep context
103+
104+
105+instance
106+ ( htable ~ HLabel "tag" (HType Tag)
107+ , HTable (GColumnsADT _Columns (M1 D meta rep))
108+ , Eval (_Table (htable context))
109+ , Eval (_Columns (htable context)) ~ htable
110+ , GTableADT' _Table _Columns htable context rep
111+ , GToExprsADT' (Const _Table) _Columns htable rep rep
112+ )
113+ => GTableADT _Table _Columns context (M1 D meta rep)
114+ where
115+ gfromColumnsADT fromContext toContext fromColumns =
116+ gfromResultADT @(Const _Table) @_Columns @(M1 D meta rep) @(M1 D meta rep)
117+ (const (fromColumns . hmap toContext)) .
118+ hmap fromContext
119+
120+ gtoColumnsADT fromContext toContext toColumns =
121+ hmap toContext .
122+ gtoResultADT @(Const _Table) @_Columns @(M1 D meta rep) @(M1 D meta rep)
123+ (const (hmap fromContext . toColumns))
124+
125+ gtableADT table hnullifier =
126+ gtableADT' @_Table @_Columns @htable @context @rep table hnullifier htable
127+ where
128+ htable = table (Proxy @(htable context))
129+
130+
131+type GTableADT'
132+ :: (Type -> Exp Constraint)
133+ -> (Type -> Exp K.HTable)
134+ -> K.HTable -> K.HContext -> (Type -> Type) -> Constraint
135+class GTableADT' _Table _Columns htable context rep where
136+ gtableADT' :: ()
137+ => (forall a proxy. Eval (_Table a) => proxy a -> Eval (_Columns a) context)
138+ -> (forall a. ()
139+ => SSpec ('Spec a)
140+ -> context ('Spec a)
141+ -> context ('Spec (Nullify a)))
142+ -> htable context
143+ -> GColumnsADT' _Columns htable rep context
144+
145+
146+instance
147+ ( htable' ~ GColumnsADT' _Columns htable a
148+ , GTableADT' _Table _Columns htable context a
149+ , GTableADT' _Table _Columns htable' context b
150+ )
151+ => GTableADT' _Table _Columns htable context (a :+: b)
152+ where
153+ gtableADT' table hnullifier =
154+ gtableADT' @_Table @_Columns @_ @_ @b table hnullifier .
155+ gtableADT' @_Table @_Columns @_ @_ @a table hnullifier
156+
157+
158+instance meta ~ 'MetaCons label _fixity _isRecord =>
159+ GTableADT' _Table _Columns htable context (M1 C meta U1)
160+ where
161+ gtableADT' _ _ = id
162+
163+
164+instance {-# OVERLAPPABLE #-}
165+ ( HTable (GColumns _Columns rep)
166+ , GTable _Table _Columns context rep
167+ , meta ~ 'MetaCons label _fixity _isRecord
168+ , GColumnsADT' _Columns htable (M1 C ('MetaCons label _fixity _isRecord) rep) ~
169+ HProduct htable (HLabel label (HNullify (GColumns _Columns rep)))
170+ )
171+ => GTableADT' _Table _Columns htable context (M1 C meta rep)
172+ where
173+ gtableADT' table hnullifier htable =
174+ HProduct htable $
175+ hlabel $
176+ hnullify hnullifier $
177+ gtable @_Table @_Columns @_ @rep table
178+
179+
180+type GToExprsADT
69 :: (Type -> Type -> Exp Constraint)
181 :: (Type -> Type -> Exp Constraint)
70 -> (Type -> Exp K.HTable)
182 -> (Type -> Exp K.HTable)
71 -> (Type -> Type) -> (Type -> Type) -> Constraint
183 -> (Type -> Type) -> (Type -> Type) -> Constraint
72−class GSerializeADT _Serialize _Columns exprs rep where
184+class GToExprsADT _ToExprs _Columns exprs rep where
73 gfromResultADT :: ()
185 gfromResultADT :: ()
74− => (forall expr a proxy. Eval (_Serialize expr a)
186+ => (forall expr a proxy.
187+ ( Eval (_ToExprs expr a)
188+ , HTable (Eval (_Columns expr))
189+ )
190+ => proxy expr
75− => proxy expr -> Eval (_Columns expr) Result -> a)
191+ -> Eval (_Columns expr) (Col Result)
192+ -> a)
76− -> GColumnsADT _Columns exprs Result
193+ -> GColumnsADT _Columns exprs (Col Result)
77 -> rep x
194 -> rep x
78
195
79 gtoResultADT :: ()
196 gtoResultADT :: ()
80− => (forall expr a proxy. Eval (_Serialize expr a)
197+ => (forall expr a proxy.
198+ ( Eval (_ToExprs expr a)
199+ , HTable (Eval (_Columns expr))
200+ )
201+ => proxy expr
202+ -> a
81− => proxy expr -> a -> Eval (_Columns expr) Result)
203+ -> Eval (_Columns expr) (Col Result))
82 -> rep x
204 -> rep x
83− -> GColumnsADT _Columns exprs Result
205+ -> GColumnsADT _Columns exprs (Col Result)
84
206
85
207
86instance
208instance
87− ( htable ~ HLabel "tag" (HIdentity Tag)
209+ ( htable ~ HLabel "tag" (HType Tag)
88− , GSerializeADT' _Serialize _Columns htable exprs rep
210+ , GToExprsADT' _ToExprs _Columns htable exprs rep
89 )
211 )
90− => GSerializeADT _Serialize _Columns (M1 D meta exprs) (M1 D meta rep)
212+ => GToExprsADT _ToExprs _Columns (M1 D meta exprs) (M1 D meta rep)
91 where
213 where
92 gfromResultADT fromResult columns =
214 gfromResultADT fromResult columns =
93− case gfromResultADT' @_Serialize @_Columns @htable @exprs @rep fromResult tag columns of
215+ case gfromResultADT' @_ToExprs @_Columns @_ @exprs fromResult tag columns of
94 Just rep -> M1 rep
216 Just rep -> M1 rep
95 _ -> error "ADT.fromColumns: mismatch between tag and data"
217 _ -> error "ADT.fromColumns: mismatch between tag and data"
96 where
218 where
97− tag = (\(HIdentity (Identity a)) -> a) . hunlabel @"tag"
219+ tag = (\(HType (R a)) -> a) . hunlabel @"tag"
98
220
99 gtoResultADT toResult (M1 rep) =
221 gtoResultADT toResult (M1 rep) =
100− gtoResultADT' @_Serialize @_Columns @htable @exprs @rep toResult tag (Just rep)
222+ gtoResultADT' @_ToExprs @_Columns @_ @exprs toResult tag (Just rep)
101 where
223 where
102− tag = hlabel @"tag" . HIdentity . Identity
224+ tag = hlabel @"tag" . HType . R
103
225
104
226
105−type GSerializeADT'
227+type GToExprsADT'
106 :: (Type -> Type -> Exp Constraint)
228 :: (Type -> Type -> Exp Constraint)
107 -> (Type -> Exp K.HTable)
229 -> (Type -> Exp K.HTable)
108 -> K.HTable -> (Type -> Type) -> (Type -> Type) -> Constraint
230 -> K.HTable -> (Type -> Type) -> (Type -> Type) -> Constraint
109−class GSerializeADT' _Serialize _Columns htable exprs rep where
231+class GToExprsADT' _ToExprs _Columns htable exprs rep where
110− gfromResultADT' :: context ~ Result
232+ gfromResultADT' :: ()
111− => (forall expr a proxy. Eval (_Serialize expr a)
233+ => (forall expr a proxy.
234+ ( Eval (_ToExprs expr a)
235+ , HTable (Eval (_Columns expr))
236+ )
237+ => proxy expr
112− => proxy expr -> Eval (_Columns expr) context -> a)
238+ -> Eval (_Columns expr) (Col Result)
239+ -> a)
113− -> (htable Result -> Tag)
240+ -> (htable (Col Result) -> Tag)
114− -> GColumnsADT' _Columns htable exprs context
241+ -> GColumnsADT' _Columns htable exprs (Col Result)
115 -> Maybe (rep x)
242 -> Maybe (rep x)
116
243
117− gtoResultADT' :: context ~ Result
244+ gtoResultADT' :: ()
118− => (forall expr a proxy. Eval (_Serialize expr a)
245+ => (forall expr a proxy.
246+ ( Eval (_ToExprs expr a)
247+ , HTable (Eval (_Columns expr))
248+ )
249+ => proxy expr
250+ -> a
119− => proxy expr -> a -> Eval (_Columns expr) context)
251+ -> Eval (_Columns expr) (Col Result))
120− -> (Tag -> htable Result)
252+ -> (Tag -> htable (Col Result))
121 -> Maybe (rep x)
253 -> Maybe (rep x)
122− -> GColumnsADT' _Columns htable exprs context
254+ -> GColumnsADT' _Columns htable exprs (Col Result)
123
255
124 extract :: GColumnsADT' _Columns htable exprs context -> htable context
256 extract :: GColumnsADT' _Columns htable exprs context -> htable context
125
257
126
258
127instance
259instance
128− ( htable' ~ GColumnsADT' _Columns htable exprs1
260+ ( htable' ~ GColumnsADT' _Columns htable a
129− , GSerializeADT' _Serialize _Columns htable exprs1 a
261+ , GToExprsADT' _ToExprs _Columns htable a rep1
130− , GSerializeADT' _Serialize _Columns htable' exprs2 b
262+ , GToExprsADT' _ToExprs _Columns htable' b rep2
131 )
263 )
132− => GSerializeADT' _Serialize _Columns htable (exprs1 :+: exprs2) (a :+: b)
264+ => GToExprsADT' _ToExprs _Columns htable (a :+: b) (rep1 :+: rep2)
133 where
265 where
134 gfromResultADT' fromResult f columns =
266 gfromResultADT' fromResult f columns =
135 case ma of
267 case ma of
136 Just a -> Just (L1 a)
268 Just a -> Just (L1 a)
137 Nothing -> R1 <$>
269 Nothing -> R1 <$>
138− gfromResultADT' @_Serialize @_Columns @_ @exprs2 @b
270+ gfromResultADT' @_ToExprs @_Columns @_ @b @rep2
139 fromResult
271 fromResult
140− (f . extract @_Serialize @_Columns @_ @exprs1 @a)
272+ (f . extract @_ToExprs @_Columns @_ @a @rep1)
141 columns
273 columns
142 where
274 where
143 ma =
275 ma =
144− gfromResultADT' @_Serialize @_Columns @_ @exprs1 @a
276+ gfromResultADT' @_ToExprs @_Columns @_ @a @rep1
145 fromResult
277 fromResult
146 f
278 f
147− (extract @_Serialize @_Columns @_ @exprs2 @b columns)
279+ (extract @_ToExprs @_Columns @_ @b @rep2 columns)
148
280
149 gtoResultADT' toResult tag = \case
281 gtoResultADT' toResult tag = \case
150 Just (L1 a) ->
282 Just (L1 a) ->
151− gtoResultADT' @_Serialize @_Columns @_ @exprs2 @b
283+ gtoResultADT' @_ToExprs @_Columns @_ @b @rep2
152 toResult
284 toResult
153− (\_ -> gtoResultADT' @_Serialize @_Columns @_ @exprs1 @a
285+ (\_ -> gtoResultADT' @_ToExprs @_Columns @_ @a @rep1
154 toResult
286 toResult
155 tag
287 tag
156 (Just a))
288 (Just a))
157 Nothing
289 Nothing
158 Just (R1 b) ->
290 Just (R1 b) ->
159− gtoResultADT' @_Serialize @_Columns @_ @exprs2 @b
291+ gtoResultADT' @_ToExprs @_Columns @_ @b @rep2
160 toResult
292 toResult
161 (\tag' ->
293 (\tag' ->
162− gtoResultADT' @_Serialize @_Columns @_ @exprs1 @a
294+ gtoResultADT' @_ToExprs @_Columns @_ @a @rep1
163 toResult
295 toResult
164 (\_ -> tag tag')
296 (\_ -> tag tag')
165 Nothing)
297 Nothing)
166 (Just b)
298 (Just b)
167 Nothing ->
299 Nothing ->
168− gtoResultADT' @_Serialize @_Columns @_ @exprs2 @b
300+ gtoResultADT' @_ToExprs @_Columns @_ @b @rep2
169 toResult
301 toResult
170− (\_ -> gtoResultADT' @_Serialize @_Columns @_ @exprs1 @a toResult tag Nothing)
302+ (\_ -> gtoResultADT' @_ToExprs @_Columns @_ @a @rep1 toResult tag Nothing)
171 Nothing
303 Nothing
172
304
173 extract =
305 extract =
174− extract @_Serialize @_Columns @_ @exprs1 @a .
306+ extract @_ToExprs @_Columns @_ @a @rep1 .
175− extract @_Serialize @_Columns @_ @exprs2 @b
307+ extract @_ToExprs @_Columns @_ @b @rep2
176
308
177
309
310+instance
178−instance (meta ~ 'MetaCons label _fixity _isRecord, KnownSymbol label) =>
311+ ( meta ~ 'MetaCons label _fixity _isRecord
312+ , KnownSymbol label
313+ )
179− GSerializeADT' _Serialize _Columns _htable (M1 C meta U1) (M1 C meta U1)
314+ => GToExprsADT' _ToExprs _Columns htable (M1 C meta U1) (M1 C meta U1)
180 where
315 where
181 gfromResultADT' _ tag columns
316 gfromResultADT' _ tag columns
182 | tag columns == tag' = Just (M1 U1)
317 | tag columns == tag' = Just (M1 U1)
@@ -193,17 +328,17 @@ instance (meta ~ 'MetaCons label _fixity _isRecord, KnownSymbol label) =>
193
328
194instance {-# OVERLAPPABLE #-}
329instance {-# OVERLAPPABLE #-}
195 ( HTable (GColumns _Columns exprs)
330 ( HTable (GColumns _Columns exprs)
196− , GSerialize _Serialize _Columns exprs rep
331+ , GToExprs _ToExprs _Columns exprs rep
197 , meta ~ 'MetaCons label _fixity _isRecord
332 , meta ~ 'MetaCons label _fixity _isRecord
198 , KnownSymbol label
333 , KnownSymbol label
199− , GColumnsADT' _Columns htable (M1 C ('MetaCons label _fixity _isRecord) exprs) ~
334+ , GColumnsADT' _Columns htable (M1 C meta exprs) ~
200 HProduct htable (HLabel label (HNullify (GColumns _Columns exprs)))
335 HProduct htable (HLabel label (HNullify (GColumns _Columns exprs)))
201 )
336 )
202− => GSerializeADT' _Serialize _Columns htable (M1 C meta exprs) (M1 C meta rep)
337+ => GToExprsADT' _ToExprs _Columns htable (M1 C meta exprs) (M1 C meta rep)
203 where
338 where
204 gfromResultADT' fromResult tag (HProduct a b)
339 gfromResultADT' fromResult tag (HProduct a b)
205 | tag a == tag' =
340 | tag a == tag' =
206− M1 . gfromResult @_Serialize @_Columns @exprs @rep fromResult <$>
341+ M1 . gfromResult @_ToExprs @_Columns @exprs fromResult <$>
207 hunnullify unnullifier (hunlabel b)
342 hunnullify unnullifier (hunlabel b)
208 | otherwise = Nothing
343 | otherwise = Nothing
209 where
344 where
@@ -214,8 +349,12 @@ instance {-# OVERLAPPABLE #-}
214 Just (M1 rep) -> HProduct (tag tag') $
349 Just (M1 rep) -> HProduct (tag tag') $
215 hlabel $
350 hlabel $
216 hnullify nullifier $
351 hnullify nullifier $
217− gtoResult @_Serialize @_Columns @exprs @rep toResult rep
352+ gtoResult @_ToExprs @_Columns @exprs toResult rep
218 where
353 where
219 tag' = Tag $ pack $ symbolVal (Proxy @label)
354 tag' = Tag $ pack $ symbolVal (Proxy @label)
220
355
221 extract (HProduct a _) = a
356 extract (HProduct a _) = a
357+
358+
359+data Const :: (a -> Exp Constraint) -> a -> a -> Exp Constraint
360+type instance Eval (Const f x a) = (Eval (f a), x ~ a)
src/Rel8/Generic/Table/Record.hs+93−74
@@ -14,7 +14,7 @@
14
14
15module Rel8.Generic.Table.Record
15module Rel8.Generic.Table.Record
16 ( GTable, GColumns, GContext, gfromColumns, gtoColumns, gtable
16 ( GTable, GColumns, GContext, gfromColumns, gtoColumns, gtable
17− , GSerialize, gfromResult, gtoResult
17+ , GToExprs, gfromResult, gtoResult
18 )
18 )
19where
19where
20
20
@@ -30,9 +30,12 @@ import Prelude hiding ( null )
30
30
31-- rel8
31-- rel8
32import Rel8.FCF ( Eval, Exp )
32import Rel8.FCF ( Eval, Exp )
33+import Rel8.Schema.Context ( Col )
34+import Rel8.Schema.HTable ( HTable )
33import Rel8.Schema.HTable.Label ( HLabel, hlabel, hunlabel )
35import Rel8.Schema.HTable.Label ( HLabel, hlabel, hunlabel )
34import Rel8.Schema.HTable.Product ( HProduct(..) )
36import Rel8.Schema.HTable.Product ( HProduct(..) )
35import qualified Rel8.Schema.Kind as K
37import qualified Rel8.Schema.Kind as K
38+import Rel8.Schema.Result ( Result )
36
39
37
40
38type GColumns :: (Type -> Exp K.HTable) -> (Type -> Type) -> K.HTable
41type GColumns :: (Type -> Exp K.HTable) -> (Type -> Type) -> K.HTable
@@ -55,8 +58,8 @@ type family GContext _Context rep where
55type GTable
58type GTable
56 :: (Type -> Exp Constraint)
59 :: (Type -> Exp Constraint)
57 -> (Type -> Exp K.HTable)
60 -> (Type -> Exp K.HTable)
58− -> (Type -> Type) -> Constraint
61+ -> K.HContext -> (Type -> Type) -> Constraint
59−class GTable _Table _Columns rep
62+class GTable _Table _Columns context rep
60 where
63 where
61 gfromColumns :: ()
64 gfromColumns :: ()
62 => (forall a. Eval (_Table a) => Eval (_Columns a) context -> a)
65 => (forall a. Eval (_Table a) => Eval (_Columns a) context -> a)
@@ -73,109 +76,125 @@ class GTable _Table _Columns rep
73 -> GColumns _Columns rep context
76 -> GColumns _Columns rep context
74
77
75
78
76−type GSerialize
79+instance GTable _Table _Columns context rep =>
77− :: (Type -> Type -> Exp Constraint)
80+ GTable _Table _Columns context (M1 D c rep)
78− -> (Type -> Exp K.HTable)
79− -> (Type -> Type) -> (Type -> Type) -> Constraint
80−class GSerialize _Serialize _Columns exprs rep
81 where
81 where
82− gfromResult :: ()
82+ gfromColumns fromColumns =
83− => (forall expr a proxy. Eval (_Serialize expr a)
83+ M1 . gfromColumns @_Table @_Columns @context @rep fromColumns
84− => proxy expr -> Eval (_Columns expr) context -> a)
84+ gtoColumns toColumns (M1 a) =
85− -> GColumns _Columns exprs context
85+ gtoColumns @_Table @_Columns @context @rep toColumns a
86− -> rep x
87−
88− gtoResult :: ()
89− => (forall expr a proxy. Eval (_Serialize expr a)
90− => proxy expr -> a -> Eval (_Columns expr) context)
86+ gtable = gtable @_Table @_Columns @context @rep
91− -> rep x
92− -> GColumns _Columns exprs context
93
87
94
88
95−instance GTable _Table _Columns rep => GTable _Table _Columns (M1 D c rep)
89+instance GTable _Table _Columns context rep =>
90+ GTable _Table _Columns context (M1 C c rep)
96 where
91 where
97 gfromColumns fromColumns =
92 gfromColumns fromColumns =
98− M1 . gfromColumns @_Table @_Columns @rep fromColumns
93+ M1 . gfromColumns @_Table @_Columns @context @rep fromColumns
99 gtoColumns toColumns (M1 a) =
94 gtoColumns toColumns (M1 a) =
100− gtoColumns @_Table @_Columns @rep toColumns a
95+ gtoColumns @_Table @_Columns @context @rep toColumns a
101− gtable = gtable @_Table @_Columns @rep
96+ gtable = gtable @_Table @_Columns @context @rep
102
97
103
98
104−instance GSerialize _Serialize _Columns exprs rep =>
99+instance
105− GSerialize _Serialize _Columns (M1 D c exprs) (M1 D c rep)
100+ ( GTable _Table _Columns context rep1
101+ , GTable _Table _Columns context rep2
102+ )
103+ => GTable _Table _Columns context (rep1 :*: rep2)
106 where
104 where
107− gfromResult fromResult =
105+ gfromColumns fromColumns (HProduct a b) =
108− M1 . gfromResult @_Serialize @_Columns @exprs @rep fromResult
106+ gfromColumns @_Table @_Columns @context @rep1 fromColumns a :*:
109− gtoResult toResult (M1 a) =
107+ gfromColumns @_Table @_Columns @context @rep2 fromColumns b
110− gtoResult @_Serialize @_Columns @exprs @rep toResult a
108+ gtoColumns toColumns (a :*: b) = HProduct
109+ (gtoColumns @_Table @_Columns @context @rep1 toColumns a)
110+ (gtoColumns @_Table @_Columns @context @rep2 toColumns b)
111+ gtable table = HProduct
112+ (gtable @_Table @_Columns @context @rep1 table)
113+ (gtable @_Table @_Columns @context @rep2 table)
111
114
112
115
116+instance
117+ ( Eval (_Table a)
118+ , meta ~ 'MetaSel ('Just label) _su _ss _ds
119+ , k1 ~ K1 i a
120+ )
113−instance GTable _Table _Columns rep => GTable _Table _Columns (M1 C c rep)
121+ => GTable _Table _Columns context (M1 S meta k1)
114 where
122 where
115− gfromColumns fromColumns =
123+ gfromColumns fromColumns = M1 . K1 . fromColumns . hunlabel
116− M1 . gfromColumns @_Table @_Columns @rep fromColumns
117− gtoColumns toColumns (M1 a) =
124+ gtoColumns toColumns (M1 (K1 a)) = hlabel (toColumns a)
118− gtoColumns @_Table @_Columns @rep toColumns a
125+ gtable table = hlabel (table (Proxy @a))
119− gtable = gtable @_Table @_Columns @rep
120
126
121
127
128+type GToExprs
129+ :: (Type -> Type -> Exp Constraint)
130+ -> (Type -> Exp K.HTable)
131+ -> (Type -> Type) -> (Type -> Type) -> Constraint
132+class GToExprs _ToExprs _Columns exprs rep where
133+ gfromResult :: ()
134+ => (forall expr a proxy.
135+ ( Eval (_ToExprs expr a)
136+ , HTable (Eval (_Columns expr))
137+ )
138+ => proxy expr
139+ -> Eval (_Columns expr) (Col Result)
140+ -> a)
141+ -> GColumns _Columns exprs (Col Result)
142+ -> rep x
143+ gtoResult :: ()
144+ => (forall expr a proxy.
145+ ( Eval (_ToExprs expr a)
146+ , HTable (Eval (_Columns expr))
147+ )
148+ => proxy expr
149+ -> a
150+ -> Eval (_Columns expr) (Col Result))
151+ -> rep x
152+ -> GColumns _Columns exprs (Col Result)
153+
154+
122−instance GSerialize _Serialize _Columns exprs rep =>
155+instance GToExprs _ToExprs _Columns exprs rep =>
123− GSerialize _Serialize _Columns (M1 C c exprs) (M1 C c rep)
156+ GToExprs _ToExprs _Columns (M1 D c exprs) (M1 D c rep)
124 where
157 where
125 gfromResult fromResult =
158 gfromResult fromResult =
126− M1 . gfromResult @_Serialize @_Columns @exprs @rep fromResult
159+ M1 . gfromResult @_ToExprs @_Columns @exprs fromResult
127 gtoResult toResult (M1 a) =
160 gtoResult toResult (M1 a) =
128− gtoResult @_Serialize @_Columns @exprs @rep toResult a
161+ gtoResult @_ToExprs @_Columns @exprs toResult a
129
162
130
163
131−instance (GTable _Table _Columns rep1, GTable _Table _Columns rep2) =>
164+instance GToExprs _ToExprs _Columns exprs rep =>
132− GTable _Table _Columns (rep1 :*: rep2)
165+ GToExprs _ToExprs _Columns (M1 C c exprs) (M1 C c rep)
133 where
166 where
134− gfromColumns fromColumns (HProduct a b) =
167+ gfromResult fromResult =
135− gfromColumns @_Table @_Columns @rep1 fromColumns a :*:
168+ M1 . gfromResult @_ToExprs @_Columns @exprs fromResult
136− gfromColumns @_Table @_Columns @rep2 fromColumns b
169+ gtoResult toResult (M1 a) =
137− gtoColumns toColumns (a :*: b) = HProduct
170+ gtoResult @_ToExprs @_Columns @exprs toResult a
138− (gtoColumns @_Table @_Columns @rep1 toColumns a)
139− (gtoColumns @_Table @_Columns @rep2 toColumns b)
140− gtable table = HProduct
141− (gtable @_Table @_Columns @rep1 table)
142− (gtable @_Table @_Columns @rep2 table)
143
171
144
172
145instance
173instance
146− ( GSerialize _Serialize _Columns expr1 rep1
174+ ( GToExprs _ToExprs _Columns exprs1 rep1
147− , GSerialize _Serialize _Columns expr2 rep2
175+ , GToExprs _ToExprs _Columns exprs2 rep2
148 )
176 )
149− => GSerialize _Serialize _Columns (expr1 :*: expr2) (rep1 :*: rep2)
177+ => GToExprs _ToExprs _Columns (exprs1 :*: exprs2) (rep1 :*: rep2)
150 where
178 where
151 gfromResult fromResult (HProduct a b) =
179 gfromResult fromResult (HProduct a b) =
152− gfromResult @_Serialize @_Columns @expr1 @rep1 fromResult a :*:
180+ gfromResult @_ToExprs @_Columns @exprs1 fromResult a :*:
153− gfromResult @_Serialize @_Columns @expr2 @rep2 fromResult b
181+ gfromResult @_ToExprs @_Columns @exprs2 fromResult b
154 gtoResult toResult (a :*: b) =
182 gtoResult toResult (a :*: b) =
155 HProduct
183 HProduct
156− (gtoResult @_Serialize @_Columns @expr1 @rep1 toResult a)
184+ (gtoResult @_ToExprs @_Columns @exprs1 toResult a)
157− (gtoResult @_Serialize @_Columns @expr2 @rep2 toResult b)
185+ (gtoResult @_ToExprs @_Columns @exprs2 toResult b)
158
186
159
187
160instance
188instance
161− ( Eval (_Table a)
189+ ( Eval (_ToExprs exprs a)
190+ , HTable (Eval (_Columns exprs))
162 , meta ~ 'MetaSel ('Just label) _su _ss _ds
191 , meta ~ 'MetaSel ('Just label) _su _ss _ds
163− , k1 ~ K1 i a
192+ , k1 ~ K1 i exprs
164− )
165− => GTable _Table _Columns (M1 S meta k1)
166− where
167− gfromColumns fromColumns = M1 . K1 . fromColumns . hunlabel
168− gtoColumns toColumns (M1 (K1 a)) = hlabel (toColumns a)
169− gtable table = hlabel (table (Proxy @a))
170−
171−
172−instance
173− ( Eval (_Serialize expr a)
174− , meta ~ 'MetaSel ('Just label) _su _ss _ds
175− , k1 ~ K1 i expr
176 , k1' ~ K1 i a
193 , k1' ~ K1 i a
177 )
194 )
178− => GSerialize _Serialize _Columns (M1 S meta k1) (M1 S meta k1')
195+ => GToExprs _ToExprs _Columns (M1 S meta k1) (M1 S meta k1')
179 where
196 where
197+ gfromResult fromResult =
180− gfromResult fromResult = M1 . K1 . fromResult (Proxy @expr) . hunlabel
198+ M1 . K1 . fromResult (Proxy @exprs) . hunlabel
181− gtoResult toResult (M1 (K1 a)) = hlabel (toResult (Proxy @expr) a)
199+ gtoResult toResult (M1 (K1 a)) =
200+ hlabel (toResult (Proxy @exprs) a)
src/Rel8/Kind/Context.hs+21−8
@@ -1,11 +1,12 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2{-# language GADTs #-}
2{-# language GADTs #-}
3+{-# language LambdaCase #-}
3{-# language StandaloneKindSignatures #-}
4{-# language StandaloneKindSignatures #-}
4−{-# language TypeSynonymInstances #-}
5
5
6module Rel8.Kind.Context
6module Rel8.Kind.Context
7 ( Reifiable( contextSing )
7 ( Reifiable( contextSing )
8 , SContext(..)
8 , SContext(..)
9+ , sReifiable
9 )
10 )
10where
11where
11
12
@@ -16,9 +17,11 @@ import Prelude ()
16-- rel8
17-- rel8
17import Rel8.Aggregate ( Aggregate )
18import Rel8.Aggregate ( Aggregate )
18import Rel8.Expr ( Expr )
19import Rel8.Expr ( Expr )
19−import Rel8.Schema.Field ( Field )
20+import Rel8.Schema.Dict ( Dict( Dict ) )
21+import Rel8.Schema.Context ( Interpretation )
20import Rel8.Schema.Kind ( Context )
22import Rel8.Schema.Kind ( Context )
21import Rel8.Schema.Name ( Name )
23import Rel8.Schema.Name ( Name )
24+import Rel8.Schema.Reify ( Reify )
22import Rel8.Schema.Result ( Result )
25import Rel8.Schema.Result ( Result )
23
26
24
27
@@ -26,13 +29,13 @@ type SContext :: Context -> Type
26data SContext context where
29data SContext context where
27 SAggregate :: SContext Aggregate
30 SAggregate :: SContext Aggregate
28 SExpr :: SContext Expr
31 SExpr :: SContext Expr
29− SField :: SContext (Field table)
30 SName :: SContext Name
32 SName :: SContext Name
31 SResult :: SContext Result
33 SResult :: SContext Result
34+ SReify :: SContext context -> SContext (Reify context)
32
35
33
36
34type Reifiable :: Context -> Constraint
37type Reifiable :: Context -> Constraint
35−class Reifiable context where
38+class Interpretation context => Reifiable context where
36 contextSing :: SContext context
39 contextSing :: SContext context
37
40
38
41
@@ -44,13 +47,23 @@ instance Reifiable Expr where
44 contextSing = SExpr
47 contextSing = SExpr
45
48
46
49
47−instance Reifiable (Field table) where
48− contextSing = SField
49−
50−
51instance Reifiable Result where
50instance Reifiable Result where
52 contextSing = SResult
51 contextSing = SResult
53
52
54
53
55instance Reifiable Name where
54instance Reifiable Name where
56 contextSing = SName
55 contextSing = SName
56+
57+
58+instance Reifiable context => Reifiable (Reify context) where
59+ contextSing = SReify contextSing
60+
61+
62+sReifiable :: SContext context -> Dict Reifiable context
63+sReifiable = \case
64+ SAggregate -> Dict
65+ SExpr -> Dict
66+ SName -> Dict
67+ SResult -> Dict
68+ SReify context -> case sReifiable context of
69+ Dict -> Dict
src/Rel8/Order.hs+8−1
@@ -4,6 +4,7 @@
4
4
5module Rel8.Order
5module Rel8.Order
6 ( Order(..)
6 ( Order(..)
7+ , toOrderExprs
7 )
8 )
8where
9where
9
10
@@ -16,7 +17,8 @@ import Prelude
16import Data.Functor.Contravariant.Divisible ( Decidable, Divisible )
17import Data.Functor.Contravariant.Divisible ( Decidable, Divisible )
17
18
18-- opaleye
19-- opaleye
19−import qualified Opaleye.Order as Opaleye
20+import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
21+import qualified Opaleye.Internal.Order as Opaleye
20
22
21
23
22-- | An ordering expression for @a@. Primitive orderings are defined with
24-- | An ordering expression for @a@. Primitive orderings are defined with
@@ -28,3 +30,8 @@ import qualified Opaleye.Order as Opaleye
28type Order :: Type -> Type
30type Order :: Type -> Type
29newtype Order a = Order (Opaleye.Order a)
31newtype Order a = Order (Opaleye.Order a)
30 deriving newtype (Contravariant, Divisible, Decidable, Semigroup, Monoid)
32 deriving newtype (Contravariant, Divisible, Decidable, Semigroup, Monoid)
33+
34+
35+toOrderExprs :: Order a -> a -> [Opaleye.OrderExpr]
36+toOrderExprs (Order (Opaleye.Order order)) a =
37+ uncurry Opaleye.OrderExpr <$> order a
src/Rel8/Query.hs+9−28
@@ -1,6 +1,4 @@
1−{-# language FlexibleContexts #-}
2{-# language StandaloneKindSignatures #-}
1{-# language StandaloneKindSignatures #-}
3−{-# language UndecidableInstances #-}
4
2
5module Rel8.Query
3module Rel8.Query
6 ( Query( Query )
4 ( Query( Query )
@@ -17,21 +15,18 @@ import Prelude
17-- opaleye
15-- opaleye
18import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
16import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
19import qualified Opaleye.Internal.PackMap as Opaleye
17import qualified Opaleye.Internal.PackMap as Opaleye
20−import qualified Opaleye.Internal.PrimQuery as Opaleye hiding (lateral)
18+import qualified Opaleye.Internal.PrimQuery as Opaleye
21import qualified Opaleye.Internal.QueryArr as Opaleye
19import qualified Opaleye.Internal.QueryArr as Opaleye
22import qualified Opaleye.Internal.Tag as Opaleye
20import qualified Opaleye.Internal.Tag as Opaleye
23
21
24-- rel8
22-- rel8
25−import Rel8.Expr ( Expr )
26import Rel8.Query.Set ( unionAll )
23import Rel8.Query.Set ( unionAll )
27import Rel8.Query.Opaleye ( fromOpaleye )
24import Rel8.Query.Opaleye ( fromOpaleye )
28import Rel8.Query.Values ( values )
25import Rel8.Query.Values ( values )
29−import Rel8.Table ( Table, fromColumns, toColumns )
30import Rel8.Table.Alternative
26import Rel8.Table.Alternative
31 ( AltTable, (<|>:)
27 ( AltTable, (<|>:)
32 , AlternativeTable, emptyTable
28 , AlternativeTable, emptyTable
33 )
29 )
34−import Rel8.Table.Projection ( Projectable, apply, project )
35
30
36-- semigroupoids
31-- semigroupoids
37import Data.Functor.Apply ( Apply, (<.>) )
32import Data.Functor.Apply ( Apply, (<.>) )
@@ -156,10 +151,6 @@ newtype Query a =
156 )
151 )
157
152
158
153
159−instance Projectable Query where
160− project f = fmap (fromColumns . apply f . toColumns)
161−
162−
163instance Functor Query where
154instance Functor Query where
164 fmap f (Query a) = Query (fmap (fmap (fmap f)) a)
155 fmap f (Query a) = Query (fmap (fmap (fmap f)) a)
165
156
@@ -178,14 +169,14 @@ instance Bind Query where
178
169
179
170
180instance Monad Query where
171instance Monad Query where
181− Query q >>= f = Query $ \dummies -> Opaleye.stateQueryArr $ \_ tag ->
172+ Query q >>= f = Query $ \dummies -> Opaleye.QueryArr $ \(_, tag) ->
182 let
173 let
183− qa = q dummies
174+ Opaleye.QueryArr qa = q dummies
184− ((m, a), query, tag') = Opaleye.runStateQueryArr qa () tag
175+ ((m, a), query, tag') = qa ((), tag)
185 Query q' = f a
176 Query q' = f a
186 (dummies', query', tag'') =
177 (dummies', query', tag'') =
187 ( dummy : dummies
178 ( dummy : dummies
188− , query <> Opaleye.aRebind bindings
179+ , \lateral -> Opaleye.Rebind True bindings . query lateral
189 , Opaleye.next tag'
180 , Opaleye.next tag'
190 )
181 )
191 where
182 where
@@ -193,11 +184,11 @@ instance Monad Query where
193 where
184 where
194 random = Opaleye.FunExpr "random" []
185 random = Opaleye.FunExpr "random" []
195 name = Opaleye.extractAttr "dummy" tag'
186 name = Opaleye.extractAttr "dummy" tag'
196− qa' = Opaleye.lateral $ \_ -> q' dummies'
187+ Opaleye.QueryArr qa' = Opaleye.lateral $ \_ -> q' dummies'
197− ((m'@(Any needsDummies), b), query'', tag''') = Opaleye.runStateQueryArr qa' () tag''
188+ ((m'@(Any needsDummies), b), query'', tag''') = qa' ((), tag'')
198 query'''
189 query'''
199− | needsDummies = query' <> query''
190+ | needsDummies = \lateral -> query'' lateral . query' lateral
200− | otherwise = query <> query''
191+ | otherwise = \lateral -> query'' lateral . query lateral
201 m'' = m <> m'
192 m'' = m <> m'
202 in
193 in
203 ((m'', b), query''', tag''')
194 ((m'', b), query''', tag''')
@@ -211,13 +202,3 @@ instance AltTable Query where
211-- | 'emptyTable' = 'values' @[]@.
202-- | 'emptyTable' = 'values' @[]@.
212instance AlternativeTable Query where
203instance AlternativeTable Query where
213 emptyTable = values []
204 emptyTable = values []
214−
215−
216−-- | '<>' = 'unionAll'.
217−instance Table Expr a => Semigroup (Query a) where
218− (<>) = (<|>:)
219−
220−
221−-- | 'mempty' = @'values' []@.
222−instance Table Expr a => Monoid (Query a) where
223− mempty = emptyTable
src/Rel8/Query/Aggregate.hs−19
@@ -1,17 +1,13 @@
1{-# language FlexibleContexts #-}
1{-# language FlexibleContexts #-}
2{-# language MonoLocalBinds #-}
2{-# language MonoLocalBinds #-}
3−{-# language ScopedTypeVariables #-}
4−{-# language TypeApplications #-}
5
3
6module Rel8.Query.Aggregate
4module Rel8.Query.Aggregate
7 ( aggregate
5 ( aggregate
8 , countRows
6 , countRows
9− , mode
10 )
7 )
11where
8where
12
9
13-- base
10-- base
14−import Data.Functor.Contravariant ( (>$<) )
15import Data.Int ( Int64 )
11import Data.Int ( Int64 )
16import Prelude
12import Prelude
17
13
@@ -22,16 +18,9 @@ import qualified Opaleye.Aggregate as Opaleye
22import Rel8.Aggregate ( Aggregates )
18import Rel8.Aggregate ( Aggregates )
23import Rel8.Expr ( Expr )
19import Rel8.Expr ( Expr )
24import Rel8.Expr.Aggregate ( countStar )
20import Rel8.Expr.Aggregate ( countStar )
25−import Rel8.Expr.Order ( desc )
26import Rel8.Query ( Query )
21import Rel8.Query ( Query )
27−import Rel8.Query.Limit ( limit )
28import Rel8.Query.Maybe ( optional )
22import Rel8.Query.Maybe ( optional )
29import Rel8.Query.Opaleye ( mapOpaleye )
23import Rel8.Query.Opaleye ( mapOpaleye )
30−import Rel8.Query.Order ( orderBy )
31−import Rel8.Table ( toColumns )
32−import Rel8.Table.Aggregate ( hgroupBy )
33−import Rel8.Table.Cols ( Cols( Cols ), fromCols )
34−import Rel8.Table.Eq ( EqTable, eqTable )
35import Rel8.Table.Opaleye ( aggregator )
24import Rel8.Table.Opaleye ( aggregator )
36import Rel8.Table.Maybe ( maybeTable )
25import Rel8.Table.Maybe ( maybeTable )
37
26
@@ -46,11 +35,3 @@ aggregate = mapOpaleye (Opaleye.aggregate aggregator)
46-- will return @0@.
35-- will return @0@.
47countRows :: Query a -> Query (Expr Int64)
36countRows :: Query a -> Query (Expr Int64)
48countRows = fmap (maybeTable 0 id) . optional . aggregate . fmap (const countStar)
37countRows = fmap (maybeTable 0 id) . optional . aggregate . fmap (const countStar)
49−
50−
51−-- | Return the most common row in a query.
52−mode :: forall a. EqTable a => Query a -> Query a
53−mode rows = limit 1 $ fmap (fromCols . snd) $ orderBy (fst >$< desc) $ do
54− aggregate $ do
55− row <- toColumns <$> rows
56− pure (countStar, Cols $ hgroupBy (eqTable @a) row)
src/Rel8/Query/Distinct.hs+9−4
@@ -1,3 +1,5 @@
1+{-# options_ghc -fno-warn-redundant-constraints #-}
2+
1module Rel8.Query.Distinct
3module Rel8.Query.Distinct
2 ( distinct
4 ( distinct
3 , distinctOn
5 , distinctOn
@@ -6,11 +8,12 @@ module Rel8.Query.Distinct
6where
8where
7
9
8-- base
10-- base
9−import Prelude ()
11+import Prelude
10
12
11-- opaleye
13-- opaleye
12import qualified Opaleye.Distinct as Opaleye
14import qualified Opaleye.Distinct as Opaleye
13−import qualified Opaleye.Order as Opaleye
15+import qualified Opaleye.Internal.Order as Opaleye
16+import qualified Opaleye.Internal.QueryArr as Opaleye
14
17
15-- rel8
18-- rel8
16import Rel8.Order ( Order( Order ) )
19import Rel8.Order ( Order( Order ) )
@@ -30,11 +33,13 @@ distinct = mapOpaleye (Opaleye.distinctExplicit distinctspec)
30-- to a projection. If multiple rows have the same projection, it is
33-- to a projection. If multiple rows have the same projection, it is
31-- unspecified which row will be returned. If this matters, use 'distinctOnBy'.
34-- unspecified which row will be returned. If this matters, use 'distinctOnBy'.
32distinctOn :: EqTable b => (a -> b) -> Query a -> Query a
35distinctOn :: EqTable b => (a -> b) -> Query a -> Query a
36+distinctOn proj =
33−distinctOn proj = mapOpaleye (Opaleye.distinctOnExplicit unpackspec proj)
37+ mapOpaleye (\q -> Opaleye.productQueryArr (Opaleye.distinctOn unpackspec proj . Opaleye.runSimpleQueryArr q))
34
38
35
39
36-- | Select all distinct rows from a query, where rows are equivalent according
40-- | Select all distinct rows from a query, where rows are equivalent according
37-- to a projection. If there are multiple rows with the same projection, the
41-- to a projection. If there are multiple rows with the same projection, the
38-- first row according to the specified 'Order' will be returned.
42-- first row according to the specified 'Order' will be returned.
39distinctOnBy :: EqTable b => (a -> b) -> Order a -> Query a -> Query a
43distinctOnBy :: EqTable b => (a -> b) -> Order a -> Query a -> Query a
40−distinctOnBy proj (Order order) = mapOpaleye (Opaleye.distinctOnByExplicit unpackspec proj order)
44+distinctOnBy proj (Order order) =
45+ mapOpaleye (\q -> Opaleye.productQueryArr (Opaleye.distinctOnBy unpackspec proj order . Opaleye.runSimpleQueryArr q))
src/Rel8/Query/Each.hs+3−3
@@ -17,7 +17,7 @@ import Rel8.Query ( Query )
17import Rel8.Query.Opaleye ( fromOpaleye )
17import Rel8.Query.Opaleye ( fromOpaleye )
18import Rel8.Schema.Name ( Selects )
18import Rel8.Schema.Name ( Selects )
19import Rel8.Schema.Table ( TableSchema )
19import Rel8.Schema.Table ( TableSchema )
20−import Rel8.Table.Cols ( fromCols, toCols )
20+import Rel8.Table ( fromColumns, toColumns )
21import Rel8.Table.Opaleye ( table, unpackspec )
21import Rel8.Table.Opaleye ( table, unpackspec )
22
22
23
23
@@ -25,8 +25,8 @@ import Rel8.Table.Opaleye ( table, unpackspec )
25-- table@.
25-- table@.
26each :: Selects names exprs => TableSchema names -> Query exprs
26each :: Selects names exprs => TableSchema names -> Query exprs
27each =
27each =
28− fmap fromCols .
28+ fmap fromColumns .
29 fromOpaleye .
29 fromOpaleye .
30 Opaleye.selectTableExplicit unpackspec .
30 Opaleye.selectTableExplicit unpackspec .
31 table .
31 table .
32− fmap toCols
32+ fmap toColumns
src/Rel8/Query/Evaluate.hs+22−3
@@ -3,6 +3,7 @@
3
3
4module Rel8.Query.Evaluate
4module Rel8.Query.Evaluate
5 ( evaluate
5 ( evaluate
6+ , rebind
6 )
7 )
7where
8where
8
9
@@ -15,23 +16,28 @@ import Prelude hiding ( undefined )
15
16
16-- opaleye
17-- opaleye
17import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
18import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
19+import qualified Opaleye.Internal.PackMap as Opaleye
20+import qualified Opaleye.Internal.PrimQuery as Opaleye
21+import qualified Opaleye.Internal.QueryArr as Opaleye
22+import qualified Opaleye.Internal.Tag as Opaleye
23+import qualified Opaleye.Internal.Unpackspec as Opaleye
18
24
19-- rel8
25-- rel8
20import Rel8.Expr ( Expr )
26import Rel8.Expr ( Expr )
21import Rel8.Expr.Bool ( (&&.) )
27import Rel8.Expr.Bool ( (&&.) )
22import Rel8.Expr.Opaleye ( fromPrimExpr )
28import Rel8.Expr.Opaleye ( fromPrimExpr )
23import Rel8.Query ( Query( Query ) )
29import Rel8.Query ( Query( Query ) )
24−import Rel8.Query.Rebind ( rebind )
25import Rel8.Table ( Table )
30import Rel8.Table ( Table )
26import Rel8.Table.Bool ( case_ )
31import Rel8.Table.Bool ( case_ )
27−import Rel8.Table.Undefined ( undefined )
32+import Rel8.Table.Opaleye ( unpackspec )
33+import Rel8.Table.Undefined
28
34
29
35
30-- | 'evaluate' takes expressions that could potentially have side effects and
36-- | 'evaluate' takes expressions that could potentially have side effects and
31-- \"runs\" them in the 'Query' monad. The returned expressions have no side
37-- \"runs\" them in the 'Query' monad. The returned expressions have no side
32-- effects and can safely be reused.
38-- effects and can safely be reused.
33evaluate :: Table Expr a => a -> Query a
39evaluate :: Table Expr a => a -> Query a
34−evaluate = laterally >=> rebind "eval"
40+evaluate = laterally >=> rebind
35
41
36
42
37laterally :: Table Expr a => a -> Query a
43laterally :: Table Expr a => a -> Query a
@@ -45,5 +51,18 @@ laterally a = Query $ \bindings -> pure $ (Any True,) $
45 go = fromPrimExpr . Opaleye.UnExpr Opaleye.OpIsNotNull
51 go = fromPrimExpr . Opaleye.UnExpr Opaleye.OpIsNotNull
46
52
47
53
54+-- | 'rebind' takes some expressions, and binds each of them to a new
55+-- variable in the SQL. The @a@ returned consists only of these
56+-- variables. It's essentially a @let@ binding for Postgres expressions.
57+rebind :: Table Expr a => a -> Query a
58+rebind a = Query $ \_ -> Opaleye.QueryArr $ \(_, tag) ->
59+ let
60+ tag' = Opaleye.next tag
61+ (a', bindings) = Opaleye.run $
62+ Opaleye.runUnpackspec unpackspec (Opaleye.extractAttr "eval" tag') a
63+ in
64+ ((mempty, a'), \_ -> Opaleye.Rebind True bindings, tag')
65+
66+
48foldl1' :: (a -> a -> a) -> NonEmpty a -> a
67foldl1' :: (a -> a -> a) -> NonEmpty a -> a
49foldl1' f (a :| as) = foldl' f a as
68foldl1' f (a :| as) = foldl' f a as
src/Rel8/Query/Exists.hs+1−1
@@ -12,7 +12,7 @@ import Prelude hiding ( filter )
12
12
13-- opaleye
13-- opaleye
14import qualified Opaleye.Exists as Opaleye
14import qualified Opaleye.Exists as Opaleye
15−import qualified Opaleye.Operators as Opaleye
15+import qualified Opaleye.Operators as Opaleye hiding ( exists )
16
16
17-- rel8
17-- rel8
18import Rel8.Expr ( Expr )
18import Rel8.Expr ( Expr )
src/Rel8/Query/Indexed.hsdeleted−21
@@ -1,21 +0,0 @@
1−module Rel8.Query.Indexed
2− ( indexed
3− )
4−where
5−
6−-- base
7−import Control.Applicative ( liftA2 )
8−import Data.Int ( Int64 )
9−import Prelude
10−
11−-- rel8
12−import Rel8.Expr ( Expr )
13−import Rel8.Expr.Window ( rowNumber )
14−import Rel8.Query ( Query )
15−import Rel8.Query.Window ( window )
16−import Rel8.Table.Window ( currentRow )
17−
18−
19−-- | Pair each row of a query with its index within the query.
20−indexed :: Query a -> Query (Expr Int64, a)
21−indexed = window (liftA2 (,) (subtract 1 <$> rowNumber) currentRow)
src/Rel8/Query/List.hs+12−15
@@ -19,18 +19,17 @@ import Prelude
19import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
19import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
20
20
21-- rel8
21-- rel8
22−import Rel8.Expr ( Expr )
22+import Rel8.Expr ( Col( E, unE ), Expr )
23import Rel8.Expr.Aggregate ( listAggExpr, nonEmptyAggExpr )
23import Rel8.Expr.Aggregate ( listAggExpr, nonEmptyAggExpr )
24import Rel8.Expr.Opaleye ( mapPrimExpr )
24import Rel8.Expr.Opaleye ( mapPrimExpr )
25import Rel8.Query ( Query )
25import Rel8.Query ( Query )
26import Rel8.Query.Aggregate ( aggregate )
26import Rel8.Query.Aggregate ( aggregate )
27+import Rel8.Query.Evaluate ( rebind )
27import Rel8.Query.Maybe ( optional )
28import Rel8.Query.Maybe ( optional )
28−import Rel8.Query.Rebind ( rebind )
29import Rel8.Schema.HTable.Vectorize ( hunvectorize )
29import Rel8.Schema.HTable.Vectorize ( hunvectorize )
30import Rel8.Schema.Null ( Sql, Unnullify )
30import Rel8.Schema.Null ( Sql, Unnullify )
31−import Rel8.Schema.Spec ( Spec( Spec, info ) )
31+import Rel8.Schema.Spec ( SSpec( SSpec, info ) )
32−import Rel8.Table ( Table, fromColumns )
32+import Rel8.Table ( Table, fromColumns, toColumns )
33−import Rel8.Table.Cols ( toCols )
34import Rel8.Table.Aggregate ( listAgg, nonEmptyAgg )
33import Rel8.Table.Aggregate ( listAgg, nonEmptyAgg )
35import Rel8.Table.List ( ListTable( ListTable ) )
34import Rel8.Table.List ( ListTable( ListTable ) )
36import Rel8.Table.Maybe ( maybeTable )
35import Rel8.Table.Maybe ( maybeTable )
@@ -52,7 +51,7 @@ many =
52 fmap (maybeTable mempty (\(ListTable a) -> ListTable a)) .
51 fmap (maybeTable mempty (\(ListTable a) -> ListTable a)) .
53 optional .
52 optional .
54 aggregate .
53 aggregate .
55− fmap (listAgg . toCols)
54+ fmap (listAgg . toColumns)
56
55
57
56
58-- | Aggregate a 'Query' into a 'NonEmptyTable'. If the supplied query returns
57-- | Aggregate a 'Query' into a 'NonEmptyTable'. If the supplied query returns
@@ -67,7 +66,7 @@ some :: Table Expr a => Query a -> Query (NonEmptyTable Expr a)
67some =
66some =
68 fmap (\(NonEmptyTable a) -> NonEmptyTable a) .
67 fmap (\(NonEmptyTable a) -> NonEmptyTable a) .
69 aggregate .
68 aggregate .
70− fmap (nonEmptyAgg . toCols)
69+ fmap (nonEmptyAgg . toColumns)
71
70
72
71
73-- | A version of 'many' specialised to single expressions.
72-- | A version of 'many' specialised to single expressions.
@@ -85,9 +84,8 @@ someExpr = aggregate . fmap nonEmptyAggExpr
85--
84--
86-- @catListTable@ is an inverse to 'many'.
85-- @catListTable@ is an inverse to 'many'.
87catListTable :: Table Expr a => ListTable Expr a -> Query a
86catListTable :: Table Expr a => ListTable Expr a -> Query a
88−catListTable (ListTable as) =
89− rebind "unnest" $ fromColumns $ runIdentity $
87+catListTable (ListTable as) = rebind $ fromColumns $ runIdentity $
90− hunvectorize (\Spec {info} -> pure . sunnest info) as
88+ hunvectorize (\SSpec {info} -> pure . E . sunnest info . unE) as
91
89
92
90
93-- | Expand a 'NonEmptyTable' into a 'Query', where each row in the query is an
91-- | Expand a 'NonEmptyTable' into a 'Query', where each row in the query is an
@@ -95,9 +93,8 @@ catListTable (ListTable as) =
95--
93--
96-- @catNonEmptyTable@ is an inverse to 'some'.
94-- @catNonEmptyTable@ is an inverse to 'some'.
97catNonEmptyTable :: Table Expr a => NonEmptyTable Expr a -> Query a
95catNonEmptyTable :: Table Expr a => NonEmptyTable Expr a -> Query a
98−catNonEmptyTable (NonEmptyTable as) =
96+catNonEmptyTable (NonEmptyTable as) = rebind $ fromColumns $ runIdentity $
99− rebind "unnest" $ fromColumns $ runIdentity $
100− hunvectorize (\Spec {info} -> pure . sunnest info) as
97+ hunvectorize (\SSpec {info} -> pure . E . sunnest info . unE) as
101
98
102
99
103-- | Expand an expression that contains a list into a 'Query', where each row
100-- | Expand an expression that contains a list into a 'Query', where each row
@@ -105,7 +102,7 @@ catNonEmptyTable (NonEmptyTable as) =
105--
102--
106-- @catList@ is an inverse to 'manyExpr'.
103-- @catList@ is an inverse to 'manyExpr'.
107catList :: Sql DBType a => Expr [a] -> Query (Expr a)
104catList :: Sql DBType a => Expr [a] -> Query (Expr a)
108−catList = rebind "unnest" . sunnest typeInformation
105+catList = rebind . sunnest typeInformation
109
106
110
107
111-- | Expand an expression that contains a non-empty list into a 'Query', where
108-- | Expand an expression that contains a non-empty list into a 'Query', where
@@ -113,7 +110,7 @@ catList = rebind "unnest" . sunnest typeInformation
113--
110--
114-- @catNonEmpty@ is an inverse to 'someExpr'.
111-- @catNonEmpty@ is an inverse to 'someExpr'.
115catNonEmpty :: Sql DBType a => Expr (NonEmpty a) -> Query (Expr a)
112catNonEmpty :: Sql DBType a => Expr (NonEmpty a) -> Query (Expr a)
116−catNonEmpty = rebind "unnest" . sunnest typeInformation
113+catNonEmpty = rebind . sunnest typeInformation
117
114
118
115
119sunnest :: TypeInformation (Unnullify a) -> Expr (list a) -> Expr a
116sunnest :: TypeInformation (Unnullify a) -> Expr (list a) -> Expr a
src/Rel8/Query/Maybe.hs+7−9
@@ -1,5 +1,4 @@
1{-# language GADTs #-}
1{-# language GADTs #-}
2−{-# language LambdaCase #-}
3{-# language NamedFieldPuns #-}
2{-# language NamedFieldPuns #-}
4
3
5module Rel8.Query.Maybe
4module Rel8.Query.Maybe
@@ -19,7 +18,7 @@ import Control.Comonad ( extract )
19import qualified Opaleye.Internal.MaybeFields as Opaleye
18import qualified Opaleye.Internal.MaybeFields as Opaleye
20
19
21-- rel8
20-- rel8
22−import Rel8.Expr ( Expr )
21+import Rel8.Expr ( Col( E ), Expr )
23import Rel8.Expr.Eq ( (==.) )
22import Rel8.Expr.Eq ( (==.) )
24import Rel8.Expr.Opaleye ( fromColumn, fromPrimExpr )
23import Rel8.Expr.Opaleye ( fromColumn, fromPrimExpr )
25import Rel8.Query ( Query )
24import Rel8.Query ( Query )
@@ -35,7 +34,7 @@ import Rel8.Table.Maybe ( MaybeTable(..), isJustTable )
35-- JOIN@s.
34-- JOIN@s.
36optional :: Query a -> Query (MaybeTable Expr a)
35optional :: Query a -> Query (MaybeTable Expr a)
37optional = mapOpaleye $ Opaleye.optionalInternal $ \tag a -> MaybeTable
36optional = mapOpaleye $ Opaleye.optionalInternal $ \tag a -> MaybeTable
38− { tag = fromPrimExpr $ fromColumn tag
37+ { tag = E $ fromPrimExpr $ fromColumn tag
39 , just = pure a
38 , just = pure a
40 }
39 }
41
40
@@ -55,14 +54,13 @@ catMaybeTable ma@(MaybeTable _ a) = do
55-- to step through multiple @LEFT JOINs@.
54-- to step through multiple @LEFT JOINs@.
56--
55--
57-- Note that @traverseMaybeTable@ takes a @a -> Query b@ function, which means
56-- Note that @traverseMaybeTable@ takes a @a -> Query b@ function, which means
58−-- you also have the ability to "expand" one row into multiple rows. If the
57+-- you also have the ability to "expand" one row into multiple rows. If the
59-- @a -> Query b@ function returns no rows, then the resulting query will also
58-- @a -> Query b@ function returns no rows, then the resulting query will also
60-- have no rows. However, regardless of the given @a -> Query b@ function, if
59-- have no rows. However, regardless of the given @a -> Query b@ function, if
61-- the input is @nothingTable@, you will always get exactly one @nothingTable@
60-- the input is @nothingTable@, you will always get exactly one @nothingTable@
62-- back.
61-- back.
63traverseMaybeTable :: (a -> Query b) -> MaybeTable Expr a -> Query (MaybeTable Expr b)
62traverseMaybeTable :: (a -> Query b) -> MaybeTable Expr a -> Query (MaybeTable Expr b)
64−traverseMaybeTable query ma@(MaybeTable input _) = do
63+traverseMaybeTable query ma@(MaybeTable (E input) _) = do
65− optional (query =<< catMaybeTable ma) >>= \case
64+ MaybeTable (E output) b <- optional (query =<< catMaybeTable ma)
66− MaybeTable output b -> do
67− where_ $ output ==. input
65+ where_ $ output ==. input
68− pure $ MaybeTable input b
66+ pure $ MaybeTable (E input) b
src/Rel8/Query/Null.hs−15
@@ -1,8 +1,5 @@
1−{-# language FlexibleContexts #-}
2−
3module Rel8.Query.Null
1module Rel8.Query.Null
4 ( catNull
2 ( catNull
5− , catNullTable
6 )
3 )
7where
4where
8
5
@@ -12,8 +9,6 @@ import Prelude
12-- rel8
9-- rel8
13import Rel8.Expr ( Expr )
10import Rel8.Expr ( Expr )
14import Rel8.Expr.Null ( isNonNull, unsafeUnnullify )
11import Rel8.Expr.Null ( isNonNull, unsafeUnnullify )
15−import Rel8.Table ( Table )
16−import Rel8.Table.Null ( NullTable, isNonNullTable, unsafeUnnullifyTable )
17import Rel8.Query ( Query )
12import Rel8.Query ( Query )
18import Rel8.Query.Filter ( where_ )
13import Rel8.Query.Filter ( where_ )
19
14
@@ -26,13 +21,3 @@ catNull :: Expr (Maybe a) -> Query (Expr a)
26catNull a = do
21catNull a = do
27 where_ $ isNonNull a
22 where_ $ isNonNull a
28 pure $ unsafeUnnullify a
23 pure $ unsafeUnnullify a
29−
30−
31−-- | Filter a 'Query' that might return @nullTable@ to a 'Query' without any
32−-- @nullTable@s.
33−--
34−-- Corresponds to 'Data.Maybe.catMaybes'.
35−catNullTable :: Table Expr a => NullTable Expr a -> Query a
36−catNullTable a = do
37− where_ $ isNonNullTable a
38− pure $ unsafeUnnullifyTable a
src/Rel8/Query/Opaleye.hs+10−18
@@ -5,7 +5,6 @@ module Rel8.Query.Opaleye
5 , toOpaleye
5 , toOpaleye
6 , mapOpaleye
6 , mapOpaleye
7 , zipOpaleyeWith
7 , zipOpaleyeWith
8− , unsafePeekQuery
9 )
8 )
10where
9where
11
10
@@ -15,7 +14,6 @@ import Prelude
15
14
16-- opaleye
15-- opaleye
17import qualified Opaleye.Internal.QueryArr as Opaleye
16import qualified Opaleye.Internal.QueryArr as Opaleye
18−import qualified Opaleye.Internal.Tag as Opaleye
19
17
20-- rel8
18-- rel8
21import {-# SOURCE #-} Rel8.Query ( Query( Query ) )
19import {-# SOURCE #-} Rel8.Query ( Query( Query ) )
@@ -39,32 +37,26 @@ zipOpaleyeWith :: ()
39zipOpaleyeWith f (Query a) (Query b) = Query $ liftA2 (zipping f) a b
37zipOpaleyeWith f (Query a) (Query b) = Query $ liftA2 (zipping f) a b
40
38
41
39
42−unsafePeekQuery :: Query a -> a
43−unsafePeekQuery (Query q) = case q mempty of
44− f -> case Opaleye.runStateQueryArr f () Opaleye.start of
45− ((_, a), _, _) -> a
46−
47−
48mapping :: ()
40mapping :: ()
49 => (Opaleye.Select a -> Opaleye.Select b)
41 => (Opaleye.Select a -> Opaleye.Select b)
50 -> Opaleye.Select (m, a) -> Opaleye.Select (m, b)
42 -> Opaleye.Select (m, a) -> Opaleye.Select (m, b)
51−mapping f q = Opaleye.stateQueryArr $ \_ tag ->
43+mapping f q@(Opaleye.QueryArr qa) = Opaleye.QueryArr $ \(_, tag) ->
52 let
44 let
53− ((m, _), _, _) = Opaleye.runStateQueryArr q () tag
45+ ((m, _), _, _) = qa ((), tag)
54− q' = (m,) <$> f (snd <$> q)
46+ Opaleye.QueryArr qa' = (m,) <$> f (snd <$> q)
55 in
47 in
56− Opaleye.runStateQueryArr q' () tag
48+ qa' ((), tag)
57
49
58
50
59zipping :: Semigroup m
51zipping :: Semigroup m
60 => (Opaleye.Select a -> Opaleye.Select b -> Opaleye.Select c)
52 => (Opaleye.Select a -> Opaleye.Select b -> Opaleye.Select c)
61 -> Opaleye.Select (m, a) -> Opaleye.Select (m, b) -> Opaleye.Select (m, c)
53 -> Opaleye.Select (m, a) -> Opaleye.Select (m, b) -> Opaleye.Select (m, c)
62−zipping f q q' =
54+zipping f q@(Opaleye.QueryArr qa) q'@(Opaleye.QueryArr qa') =
63− Opaleye.stateQueryArr $ \_ tag ->
55+ Opaleye.QueryArr $ \(_, tag) ->
64 let
56 let
65− ((m, _), _, _) = Opaleye.runStateQueryArr q () tag
57+ ((m, _), _, _) = qa ((), tag)
66− ((m', _), _, _) = Opaleye.runStateQueryArr q' () tag
58+ ((m', _), _, _) = qa' ((), tag)
67 m'' = m <> m'
59 m'' = m <> m'
68− q'' = (m'',) <$> f (snd <$> q) (snd <$> q')
60+ Opaleye.QueryArr qa'' = (m'',) <$> f (snd <$> q) (snd <$> q')
69 in
61 in
70− Opaleye.runStateQueryArr q'' () tag
62+ qa'' ((), tag)
src/Rel8/Query/Rebind.hsdeleted−27
@@ -1,27 +0,0 @@
1−{-# language FlexibleContexts #-}
2−
3−module Rel8.Query.Rebind
4− ( rebind
5− )
6−where
7−
8−-- base
9−import Prelude
10−import Control.Arrow ((<<<))
11−
12−-- opaleye
13−import qualified Opaleye.Internal.Rebind as Opaleye
14−
15−-- rel8
16−import Rel8.Expr ( Expr )
17−import Rel8.Query ( Query )
18−import Rel8.Table ( Table )
19−import Rel8.Table.Opaleye ( unpackspec )
20−import Rel8.Query.Opaleye (fromOpaleye)
21−
22−
23−-- | 'rebind' takes a variable name, some expressions, and binds each of them
24−-- to a new variable in the SQL. The @a@ returned consists only of these
25−-- variables. It's essentially a @let@ binding for Postgres expressions.
26−rebind :: Table Expr a => String -> a -> Query a
27−rebind prefix a = fromOpaleye (Opaleye.rebindExplicitPrefix prefix unpackspec <<< pure a)
src/Rel8/Query/SQL.hs+59−6
@@ -1,21 +1,74 @@
1{-# language FlexibleContexts #-}
1{-# language FlexibleContexts #-}
2−{-# language MonoLocalBinds #-}
2+{-# language TypeFamilies #-}
3+{-# language ViewPatterns #-}
3
4
4module Rel8.Query.SQL
5module Rel8.Query.SQL
5 ( showQuery
6 ( showQuery
7+ , sqlForQuery, sqlForQueryWithNames
6 )
8 )
7where
9where
8
10
9-- base
11-- base
12+import Data.Foldable ( fold )
13+import Data.Functor.Const ( Const( Const ), getConst )
14+import Data.Void ( Void )
10import Prelude
15import Prelude
11
16
17+-- opaleye
18+import qualified Opaleye.Internal.HaskellDB.Sql as Opaleye
19+import qualified Opaleye.Internal.PrimQuery as Opaleye
20+import qualified Opaleye.Internal.Print as Opaleye
21+import qualified Opaleye.Internal.Optimize as Opaleye
22+import qualified Opaleye.Internal.QueryArr as Opaleye hiding ( Select )
23+import qualified Opaleye.Internal.Sql as Opaleye
24+
12-- rel8
25-- rel8
13−import Rel8.Expr ( Expr )
26+import Rel8.Expr ( Expr, Col( E ) )
27+import Rel8.Expr.Opaleye ( toPrimExpr )
14import Rel8.Query ( Query )
28import Rel8.Query ( Query )
15−import Rel8.Statement.Select ( ppSelect )
29+import Rel8.Query.Opaleye ( toOpaleye )
30+import Rel8.Schema.Name ( Name( Name ), Selects, Col( N ) )
31+import Rel8.Schema.HTable ( htabulateA, hfield )
32+import Rel8.Table ( Table, toColumns )
16−import Rel8.Table ( Table )
33+import Rel8.Table.Name ( namesFromLabels )
34+import Rel8.Table.Opaleye ( castTable )
17
35
18
36
19−-- | Convert a 'Query' to a 'String' containing a @SELECT@ statement.
37+-- | Convert a query to a 'String' containing the query as a @SELECT@
38+-- statement.
20showQuery :: Table Expr a => Query a -> String
39showQuery :: Table Expr a => Query a -> String
21−showQuery = show . ppSelect
40+showQuery = fold . sqlForQuery
41+
42+
43+sqlForQuery :: Table Expr a
44+ => Query a -> Maybe String
45+sqlForQuery = sqlForQueryWithNames namesFromLabels . fmap toColumns
46+
47+
48+sqlForQueryWithNames :: Selects names exprs
49+ => names -> Query exprs -> Maybe String
50+sqlForQueryWithNames names query =
51+ show . Opaleye.ppSql . selectFrom names exprs <$> optimize primQuery
52+ where
53+ (exprs, primQuery, _) =
54+ Opaleye.runSimpleQueryArrStart (toOpaleye query) ()
55+
56+
57+optimize :: Opaleye.PrimQuery' a -> Maybe (Opaleye.PrimQuery' Void)
58+optimize = Opaleye.removeEmpty . Opaleye.optimize
59+
60+
61+selectFrom :: Selects names exprs
62+ => names -> exprs -> Opaleye.PrimQuery' Void -> Opaleye.Select
63+selectFrom (toColumns -> names) (toColumns . castTable -> exprs) query =
64+ Opaleye.SelectFrom $ Opaleye.newSelect
65+ { Opaleye.attrs = Opaleye.SelectAttrs attributes
66+ , Opaleye.tables = Opaleye.oneTable select
67+ }
68+ where
69+ select = Opaleye.foldPrimQuery Opaleye.sqlQueryGenerator query
70+ attributes = getConst $ htabulateA $ \field -> case hfield names field of
71+ N (Name name) -> case hfield exprs field of
72+ E (toPrimExpr -> expr) -> Const (pure (makeAttr name expr))
73+ makeAttr label expr =
74+ (Opaleye.sqlExpr expr, Just (Opaleye.SqlColumn label))
src/Rel8/Query/Set.hs+6−6
@@ -23,36 +23,36 @@ import Rel8.Table.Opaleye ( binaryspec )
23
23
24
24
25-- | Combine the results of two queries of the same type, collapsing
25-- | Combine the results of two queries of the same type, collapsing
26−-- duplicates. @union a b@ is the same as the SQL statement @a UNION b@.
26+-- duplicates. @union a b@ is the same as the SQL statement @x UNION b@.
27union :: EqTable a => Query a -> Query a -> Query a
27union :: EqTable a => Query a -> Query a -> Query a
28union = zipOpaleyeWith (Opaleye.unionExplicit binaryspec)
28union = zipOpaleyeWith (Opaleye.unionExplicit binaryspec)
29
29
30
30
31-- | Combine the results of two queries of the same type, retaining duplicates.
31-- | Combine the results of two queries of the same type, retaining duplicates.
32−-- @unionAll a b@ is the same as the SQL statement @a UNION ALL b@.
32+-- @unionAll a b@ is the same as the SQL statement @x UNION ALL b@.
33unionAll :: Table Expr a => Query a -> Query a -> Query a
33unionAll :: Table Expr a => Query a -> Query a -> Query a
34unionAll = zipOpaleyeWith (Opaleye.unionAllExplicit binaryspec)
34unionAll = zipOpaleyeWith (Opaleye.unionAllExplicit binaryspec)
35
35
36
36
37-- | Find the intersection of two queries, collapsing duplicates. @intersect a
37-- | Find the intersection of two queries, collapsing duplicates. @intersect a
38−-- b@ is the same as the SQL statement @a INTERSECT b@.
38+-- b@ is the same as the SQL statement @x INTERSECT b@.
39intersect :: EqTable a => Query a -> Query a -> Query a
39intersect :: EqTable a => Query a -> Query a -> Query a
40intersect = zipOpaleyeWith (Opaleye.intersectExplicit binaryspec)
40intersect = zipOpaleyeWith (Opaleye.intersectExplicit binaryspec)
41
41
42
42
43-- | Find the intersection of two queries, retaining duplicates. @intersectAll
43-- | Find the intersection of two queries, retaining duplicates. @intersectAll
44−-- a b@ is the same as the SQL statement @a INTERSECT ALL b@.
44+-- a b@ is the same as the SQL statement @x INTERSECT ALL b@.
45intersectAll :: EqTable a => Query a -> Query a -> Query a
45intersectAll :: EqTable a => Query a -> Query a -> Query a
46intersectAll = zipOpaleyeWith (Opaleye.intersectAllExplicit binaryspec)
46intersectAll = zipOpaleyeWith (Opaleye.intersectAllExplicit binaryspec)
47
47
48
48
49-- | Find the difference of two queries, collapsing duplicates @except a b@ is
49-- | Find the difference of two queries, collapsing duplicates @except a b@ is
50−-- the same as the SQL statement @a EXCEPT b@.
50+-- the same as the SQL statement @x INTERSECT b@.
51except :: EqTable a => Query a -> Query a -> Query a
51except :: EqTable a => Query a -> Query a -> Query a
52except = zipOpaleyeWith (Opaleye.exceptExplicit binaryspec)
52except = zipOpaleyeWith (Opaleye.exceptExplicit binaryspec)
53
53
54
54
55-- | Find the difference of two queries, retaining duplicates. @exceptAll a b@
55-- | Find the difference of two queries, retaining duplicates. @exceptAll a b@
56−-- is the same as the SQL statement @a EXCEPT ALL b@.
56+-- is the same as the SQL statement @x EXCEPT ALL b@.
57exceptAll :: EqTable a => Query a -> Query a -> Query a
57exceptAll :: EqTable a => Query a -> Query a -> Query a
58exceptAll = zipOpaleyeWith (Opaleye.exceptAllExplicit binaryspec)
58exceptAll = zipOpaleyeWith (Opaleye.exceptAllExplicit binaryspec)
src/Rel8/Query/These.hs+14−14
@@ -25,7 +25,7 @@ import qualified Opaleye.Internal.QueryArr as Opaleye
25import qualified Opaleye.Internal.Tag as Opaleye
25import qualified Opaleye.Internal.Tag as Opaleye
26
26
27-- rel8
27-- rel8
28−import Rel8.Expr ( Expr )
28+import Rel8.Expr ( Col( E ), Expr )
29import Rel8.Expr.Bool ( boolExpr, not_ )
29import Rel8.Expr.Bool ( boolExpr, not_ )
30import Rel8.Expr.Eq ( (==.) )
30import Rel8.Expr.Eq ( (==.) )
31import Rel8.Expr.Opaleye ( toPrimExpr, traversePrimExpr )
31import Rel8.Expr.Opaleye ( toPrimExpr, traversePrimExpr )
@@ -48,27 +48,27 @@ import Rel8.Type.Tag ( EitherTag( IsLeft, IsRight ) )
48alignBy :: ()
48alignBy :: ()
49 => (a -> b -> Expr Bool)
49 => (a -> b -> Expr Bool)
50 -> Query a -> Query b -> Query (TheseTable Expr a b)
50 -> Query a -> Query b -> Query (TheseTable Expr a b)
51−alignBy condition = zipOpaleyeWith $ \left right -> Opaleye.stateQueryArr $ \_ t -> case t of
51+alignBy condition = zipOpaleyeWith $ \left right -> Opaleye.QueryArr $ \i -> case i of
52− tag -> (tab, join', tag''')
52+ (_, tag) -> (tab, join', tag''')
53 where
53 where
54− (ma, left', tag') = Opaleye.runStateQueryArr (pure <$> left) () tag
54+ (ma, left', tag') = Opaleye.runSimpleQueryArr (pure <$> left) ((), tag)
55− (mb, right', tag'') = Opaleye.runStateQueryArr (pure <$> right) () tag'
55+ (mb, right', tag'') = Opaleye.runSimpleQueryArr (pure <$> right) ((), tag')
56− MaybeTable hasHere a = ma
56+ MaybeTable (E hasHere) a = ma
57− MaybeTable hasThere b = mb
57+ MaybeTable (E hasThere) b = mb
58 (hasHere', lbindings) = Opaleye.run $ do
58 (hasHere', lbindings) = Opaleye.run $ do
59 traversePrimExpr (Opaleye.extractAttr "hasHere" tag'') hasHere
59 traversePrimExpr (Opaleye.extractAttr "hasHere" tag'') hasHere
60 (hasThere', rbindings) = Opaleye.run $ do
60 (hasThere', rbindings) = Opaleye.run $ do
61 traversePrimExpr (Opaleye.extractAttr "hasThere" tag'') hasThere
61 traversePrimExpr (Opaleye.extractAttr "hasThere" tag'') hasThere
62 tag''' = Opaleye.next tag''
62 tag''' = Opaleye.next tag''
63− join = Opaleye.Join Opaleye.FullJoin on left'' right''
63+ join lateral = Opaleye.Join Opaleye.FullJoin on left'' right''
64 where
64 where
65 on = toPrimExpr $ condition (extract a) (extract b)
65 on = toPrimExpr $ condition (extract a) (extract b)
66− left'' = (Opaleye.NonLateral, Opaleye.toPrimQuery (left' <> Opaleye.aRebind lbindings))
66+ left'' = (lateral, Opaleye.Rebind True lbindings left')
67− right'' = (Opaleye.NonLateral, Opaleye.toPrimQuery (right' <> Opaleye.aRebind rbindings))
67+ right'' = (lateral, Opaleye.Rebind True rbindings right')
68− ma' = MaybeTable hasHere' a
68+ ma' = MaybeTable (E hasHere') a
69− mb' = MaybeTable hasThere' b
69+ mb' = MaybeTable (E hasThere') b
70 tab = TheseTable {here = ma', there = mb'}
70 tab = TheseTable {here = ma', there = mb'}
71− join' = Opaleye.aProduct join
71+ join' lateral input = Opaleye.times lateral input (join lateral)
72
72
73
73
74keepHereTable :: TheseTable Expr a b -> Query (a, MaybeTable Expr b)
74keepHereTable :: TheseTable Expr a b -> Query (a, MaybeTable Expr b)
@@ -120,7 +120,7 @@ keepThoseTable t@(TheseTable (MaybeTable _ a) (MaybeTable _ b)) = do
120loseThoseTable :: TheseTable Expr a b -> Query (EitherTable Expr a b)
120loseThoseTable :: TheseTable Expr a b -> Query (EitherTable Expr a b)
121loseThoseTable t@(TheseTable (MaybeTable _ a) (MaybeTable _ b)) = do
121loseThoseTable t@(TheseTable (MaybeTable _ a) (MaybeTable _ b)) = do
122 where_ $ not_ $ isThoseTable t
122 where_ $ not_ $ isThoseTable t
123− pure $ EitherTable tag a b
123+ pure $ EitherTable (E tag) a b
124 where
124 where
125 tag = boolExpr (litExpr IsLeft) (litExpr IsRight) (isThatTable t)
125 tag = boolExpr (litExpr IsLeft) (litExpr IsRight) (isThatTable t)
126
126
src/Rel8/Query/Window.hsdeleted−26
@@ -1,26 +0,0 @@
1−module Rel8.Query.Window
2− ( window
3− )
4−where
5−
6−-- base
7−import Prelude ()
8−
9−-- opaleye
10−import qualified Opaleye.Window as Opaleye
11−
12−-- rel8
13−import Rel8.Query ( Query )
14−import Rel8.Query.Opaleye ( mapOpaleye )
15−import Rel8.Window ( Window( Window ) )
16−
17−
18−-- | 'window' runs a query composed of expressions containing
19−-- [window functions](https://www.postgresql.org/docs/current/tutorial-window.html).
20−-- 'window' is similar to 'Rel8.aggregate', with the main difference being
21−-- that in a window query, each input row corresponds to one output row,
22−-- whereas aggregation queries fold the entire input query down into a single
23−-- row. To put this into a Haskell context, 'Rel8.aggregate' is to 'foldl' as
24−-- 'window' is to 'scanl'.
25−window :: Window a b -> Query a -> Query b
26−window (Window a) = mapOpaleye (Opaleye.runWindows a)
src/Rel8/Schema/Context.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# language DataKinds #-}
2+{-# language StandaloneKindSignatures #-}
3+{-# language TypeFamilies #-}
4+
5+module Rel8.Schema.Context
6+ ( Interpretation( Col )
7+ )
8+where
9+
10+-- base
11+import Data.Kind ( Constraint )
12+import Prelude ()
13+
14+-- rel8
15+import Rel8.Schema.Kind ( Context, HContext )
16+
17+
18+type Interpretation :: Context -> Constraint
19+class Interpretation context where
20+ data Col context :: HContext
src/Rel8/Schema/Context/Abstract.hsnew file+80
@@ -0,0 +1,80 @@
1+{-# language DataKinds #-}
2+{-# language GADTs #-}
3+{-# language LambdaCase #-}
4+{-# language StandaloneKindSignatures #-}
5+{-# language TypeFamilies #-}
6+{-# language TypeOperators #-}
7+
8+module Rel8.Schema.Context.Abstract
9+ ( Abstract, virtual
10+ , Virtual(..), virtualOrResult, exclusivity
11+ )
12+where
13+
14+-- base
15+import Data.Kind ( Constraint, Type )
16+import Data.Type.Equality ( (:~:)( Refl) )
17+import Prelude
18+
19+-- rel8
20+import Rel8.Aggregate ( Aggregate )
21+import Rel8.Expr ( Expr )
22+import Rel8.Kind.Context ( SContext(..) )
23+import qualified Rel8.Schema.Kind as K
24+import Rel8.Schema.Name ( Name )
25+import Rel8.Schema.Reify ( Reify )
26+import Rel8.Schema.Result ( Result, NotResult( NotResult ) )
27+
28+
29+type Abstract :: K.Context -> Constraint
30+type family Abstract context where
31+ Abstract (Reify context) = IsVirtual context
32+ Abstract _ = ()
33+
34+
35+type IsVirtual :: K.Context -> Constraint
36+class IsVirtual context where
37+ virtual :: Virtual context
38+
39+
40+instance IsVirtual Aggregate where
41+ virtual = VAggregate
42+
43+
44+instance IsVirtual Expr where
45+ virtual = VExpr
46+
47+
48+instance IsVirtual Name where
49+ virtual = VName
50+
51+
52+instance IsVirtual (Reify context) where
53+ virtual = VReify
54+
55+
56+type Virtual :: K.Context -> Type
57+data Virtual context where
58+ VAggregate :: Virtual Aggregate
59+ VExpr :: Virtual Expr
60+ VName :: Virtual Name
61+ VReify :: Virtual (Reify context)
62+
63+
64+virtualOrResult :: ()
65+ => SContext context
66+ -> Either (context :~: Result) (Virtual context)
67+virtualOrResult = \case
68+ SAggregate -> Right VAggregate
69+ SExpr -> Right VExpr
70+ SName -> Right VName
71+ SResult -> Left Refl
72+ SReify _ -> Right VReify
73+
74+
75+exclusivity :: Virtual context -> NotResult context
76+exclusivity = \case
77+ VAggregate -> NotResult
78+ VExpr -> NotResult
79+ VName -> NotResult
80+ VReify -> NotResult
src/Rel8/Schema/Context/Nullify.hs+59−38
@@ -15,27 +15,31 @@ module Rel8.Schema.Context.Nullify
15where
15where
16
16
17-- base
17-- base
18+import Data.Bifunctor ( bimap )
18import Data.Bool ( bool )
19import Data.Bool ( bool )
19−import Data.Functor.Identity ( Identity( Identity ) )
20import Data.Kind ( Constraint, Type )
20import Data.Kind ( Constraint, Type )
21+import Data.Monoid ( getFirst )
21import Prelude hiding ( null )
22import Prelude hiding ( null )
22
23
23-- opaleye
24-- opaleye
24import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
25import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
25
26
26-- rel8
27-- rel8
27−import Rel8.Aggregate ( Aggregate(..), zipOutputs )
28+import Rel8.Aggregate
29+ ( Col( A ), Aggregate( Aggregate )
30+ , foldInputs, mapInputs
31+ )
28−import Rel8.Expr ( Expr )
32+import Rel8.Expr ( Col( E ), Expr )
29import Rel8.Expr.Bool ( boolExpr )
33import Rel8.Expr.Bool ( boolExpr )
30import Rel8.Expr.Null ( nullify, unsafeUnnullify )
34import Rel8.Expr.Null ( nullify, unsafeUnnullify )
31−import Rel8.Expr.Opaleye ( fromPrimExpr )
35+import Rel8.Expr.Opaleye ( fromPrimExpr, toPrimExpr )
32import Rel8.Kind.Context ( SContext(..) )
36import Rel8.Kind.Context ( SContext(..) )
33−import Rel8.Schema.Field ( Field )
34import qualified Rel8.Schema.Kind as K
37import qualified Rel8.Schema.Kind as K
35−import Rel8.Schema.Name ( Name( Name ) )
38+import Rel8.Schema.Name ( Col( N ), Name( Name ) )
36import Rel8.Schema.Null ( Nullify, Nullity( Null, NotNull ) )
39import Rel8.Schema.Null ( Nullify, Nullity( Null, NotNull ) )
37−import Rel8.Schema.Result ( Result )
40+import Rel8.Schema.Reify ( Col( Reify ), Reify )
41+import Rel8.Schema.Result ( Col( R ), Result )
38−import Rel8.Schema.Spec ( Spec(..) )
42+import Rel8.Schema.Spec ( Spec( Spec ), SSpec(..) )
39
43
40
44
41type Nullifiability :: K.Context -> Type
45type Nullifiability :: K.Context -> Type
@@ -43,6 +47,7 @@ data Nullifiability context where
43 NAggregate :: Nullifiability Aggregate
47 NAggregate :: Nullifiability Aggregate
44 NExpr :: Nullifiability Expr
48 NExpr :: Nullifiability Expr
45 NName :: Nullifiability Name
49 NName :: Nullifiability Name
50+ NReify :: Nullifiability context -> Nullifiability (Reify context)
46
51
47
52
48type Nullifiable :: K.Context -> Constraint
53type Nullifiable :: K.Context -> Constraint
@@ -62,10 +67,14 @@ instance Nullifiable Name where
62 nullifiability = NName
67 nullifiability = NName
63
68
64
69
70+instance Nullifiable context => Nullifiable (Reify context) where
71+ nullifiability = NReify nullifiability
72+
73+
65type NonNullifiability :: K.Context -> Type
74type NonNullifiability :: K.Context -> Type
66data NonNullifiability context where
75data NonNullifiability context where
67− NField :: NonNullifiability (Field table)
76+ NNResult :: NonNullifiability Result
68− NResult :: NonNullifiability Result
77+ NNReify :: NonNullifiability context -> NonNullifiability (Reify context)
69
78
70
79
71nullifiableOrNot :: ()
80nullifiableOrNot :: ()
@@ -74,9 +83,9 @@ nullifiableOrNot :: ()
74nullifiableOrNot = \case
83nullifiableOrNot = \case
75 SAggregate -> Right NAggregate
84 SAggregate -> Right NAggregate
76 SExpr -> Right NExpr
85 SExpr -> Right NExpr
77− SField -> Left NField
78 SName -> Right NName
86 SName -> Right NName
79− SResult -> Left NResult
87+ SResult -> Left NNResult
88+ SReify context -> bimap NNReify NReify $ nullifiableOrNot context
80
89
81
90
82absurd :: Nullifiability context -> NonNullifiability context -> a
91absurd :: Nullifiability context -> NonNullifiability context -> a
@@ -84,46 +93,58 @@ absurd = \case
84 NAggregate -> \case
93 NAggregate -> \case
85 NExpr -> \case
94 NExpr -> \case
86 NName -> \case
95 NName -> \case
96+ NReify context -> \case
97+ NNReify context' -> absurd context context'
87
98
88
99
89guarder :: ()
100guarder :: ()
90 => SContext context
101 => SContext context
91− -> context tag
102+ -> Col context ('Spec tag)
92 -> (tag -> Bool)
103 -> (tag -> Bool)
93 -> (Expr tag -> Expr Bool)
104 -> (Expr tag -> Expr Bool)
94− -> context (Maybe a)
105+ -> Col context ('Spec (Maybe a))
95− -> context (Maybe a)
106+ -> Col context ('Spec (Maybe a))
96−guarder = \case
97− SAggregate -> \tag _ isNonNull -> zipOutputs (sguard . isNonNull) tag
107+guarder SAggregate (A tag) _ isNonNull (A (Aggregate a)) =
108+ A $
109+ mapInputs (toPrimExpr . run . fromPrimExpr) $
110+ Aggregate $
111+ run <$> a
112+ where
113+ mtag = foldInputs (\_ -> pure . fromPrimExpr) tag
114+ run = maybe id (sguard . isNonNull) (getFirst mtag)
98− SExpr -> \tag _ isNonNull -> sguard (isNonNull tag)
115+guarder SExpr (E tag) _ isNonNull (E a) = E $ sguard condition a
99− SField -> \_ _ _ -> id
116+ where
117+ condition = isNonNull tag
100− SName -> \_ _ _ -> id
118+guarder SName _ _ _ name = name
101− SResult -> \(Identity tag) isNonNull _ (Identity a) ->
119+guarder SResult (R tag) isNonNull _ (R a) = R (bool Nothing a condition)
120+ where
102− Identity (bool Nothing a (isNonNull tag))
121+ condition = isNonNull tag
122+guarder (SReify context) (Reify tag) isNonNull isNonNullExpr (Reify a) =
123+ Reify $ guarder context tag isNonNull isNonNullExpr a
103
124
104
125
105nullifier :: ()
126nullifier :: ()
106 => Nullifiability context
127 => Nullifiability context
107− -> Spec a
128+ -> SSpec ('Spec a)
108− -> context a
129+ -> Col context ('Spec a)
109− -> context (Nullify a)
130+ -> Col context ('Spec (Nullify a))
110−nullifier = \case
111− NAggregate -> \Spec {nullity} (Aggregate a) ->
131+nullifier NAggregate SSpec {nullity} (A (Aggregate a)) =
112− Aggregate $ snullify nullity <$> a
132+ A $ Aggregate $ snullify nullity <$> a
113− NExpr -> \Spec {nullity} a -> snullify nullity a
133+nullifier NExpr SSpec {nullity} (E a) = E $ snullify nullity a
114− NName -> \_ (Name a) -> Name a
134+nullifier NName _ (N (Name a)) = N $ Name a
135+nullifier (NReify context) spec (Reify a) = Reify $ nullifier context spec a
115
136
116
137
117unnullifier :: ()
138unnullifier :: ()
118 => Nullifiability context
139 => Nullifiability context
119− -> Spec a
140+ -> SSpec ('Spec a)
120− -> context (Nullify a)
141+ -> Col context ('Spec (Nullify a))
121− -> context a
142+ -> Col context ('Spec a)
122−unnullifier = \case
123− NAggregate -> \Spec {nullity} (Aggregate a) ->
143+unnullifier NAggregate SSpec {nullity} (A (Aggregate a)) =
124− Aggregate $ sunnullify nullity <$> a
144+ A $ Aggregate $ sunnullify nullity <$> a
125− NExpr -> \Spec {nullity} a -> sunnullify nullity a
145+unnullifier NExpr SSpec {nullity} (E a) = E $ sunnullify nullity a
126− NName -> \_ (Name a) -> Name a
146+unnullifier NName _ (N (Name a)) = N $ Name a
147+unnullifier (NReify context) spec (Reify a) = Reify (unnullifier context spec a)
127
148
128
149
129sguard :: Expr Bool -> Expr (Maybe a) -> Expr (Maybe a)
150sguard :: Expr Bool -> Expr (Maybe a) -> Expr (Maybe a)
src/Rel8/Schema/Field.hsdeleted−50
@@ -1,50 +0,0 @@
1−{-# language DataKinds #-}
2−{-# language FlexibleContexts #-}
3−{-# language MultiParamTypeClasses #-}
4−{-# language StandaloneKindSignatures #-}
5−{-# language TypeFamilies #-}
6−
7−module Rel8.Schema.Field
8− ( Field(..)
9− , fields
10− )
11−where
12−
13−-- base
14−import Data.Functor.Identity ( Identity( Identity ) )
15−import Data.Kind ( Type )
16−import Prelude
17−
18−-- rel8
19−import Rel8.Schema.HTable ( HField, htabulate )
20−import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )
21−import Rel8.Schema.Kind as K
22−import Rel8.Schema.Null ( Sql )
23−import Rel8.Table
24− ( Table, Columns, Context, fromColumns, toColumns
25− , FromExprs, fromResult, toResult
26− , Transpose
27− )
28−import Rel8.Table.Transpose ( Transposes )
29−import Rel8.Type ( DBType )
30−
31−
32−-- | A special context used in the construction of 'Rel8.Projection's.
33−type Field :: Type -> K.Context
34−newtype Field table a = Field (HField (Columns table) a)
35−
36−
37−instance Sql DBType a => Table (Field table) (Field table a) where
38− type Columns (Field table a) = HIdentity a
39− type Context (Field table a) = Field table
40− type FromExprs (Field table a) = a
41− type Transpose to (Field table a) = to a
42−
43− toColumns = HIdentity
44− fromColumns (HIdentity a) = a
45− toResult a = HIdentity (Identity a)
46− fromResult (HIdentity (Identity a)) = a
47−
48−
49−fields :: Transposes context (Field table) table fields => fields
50−fields = fromColumns $ htabulate Field
src/Rel8/Schema/HTable.hs+24−51
@@ -16,12 +16,11 @@
16module Rel8.Schema.HTable
16module Rel8.Schema.HTable
17 ( HTable (HField, HConstrainTable)
17 ( HTable (HField, HConstrainTable)
18 , hfield, htabulate, htraverse, hdicts, hspecs
18 , hfield, htabulate, htraverse, hdicts, hspecs
19− , hfoldMap, hmap, htabulateA, htraverseP, htraversePWithField
19+ , hmap, htabulateA
20 )
20 )
21where
21where
22
22
23-- base
23-- base
24−import Data.Functor.Const ( Const( Const ), getConst )
25import Data.Kind ( Constraint, Type )
24import Data.Kind ( Constraint, Type )
26import Data.Functor.Compose ( Compose( Compose ), getCompose )
25import Data.Functor.Compose ( Compose( Compose ), getCompose )
27import Data.Proxy ( Proxy )
26import Data.Proxy ( Proxy )
@@ -33,21 +32,16 @@ import GHC.Generics
33 )
32 )
34import Prelude
33import Prelude
35
34
36−-- profunctors
37−import Data.Profunctor ( rmap, Profunctor (lmap) )
38−
39−-- product-profunctors
40−import Data.Profunctor.Product ( ProductProfunctor ((****)) )
41−
42-- rel8
35-- rel8
43import Rel8.Schema.Dict ( Dict )
36import Rel8.Schema.Dict ( Dict )
44−import Rel8.Schema.Spec ( Spec )
37+import Rel8.Schema.Spec ( Spec, SSpec )
45import Rel8.Schema.HTable.Product ( HProduct( HProduct ) )
38import Rel8.Schema.HTable.Product ( HProduct( HProduct ) )
46import qualified Rel8.Schema.Kind as K
39import qualified Rel8.Schema.Kind as K
47
40
48-- semigroupoids
41-- semigroupoids
49import Data.Functor.Apply ( Apply, (<.>) )
42import Data.Functor.Apply ( Apply, (<.>) )
50
43
44+
51-- | A @HTable@ is a functor-indexed/higher-kinded data type that is
45-- | A @HTable@ is a functor-indexed/higher-kinded data type that is
52-- representable ('htabulate'/'hfield'), constrainable ('hdicts'), and
46-- representable ('htabulate'/'hfield'), constrainable ('hdicts'), and
53-- specified ('hspecs').
47-- specified ('hspecs').
@@ -56,14 +50,14 @@ import Data.Functor.Apply ( Apply, (<.>) )
56-- instances yourself or specify this constraint.
50-- instances yourself or specify this constraint.
57type HTable :: K.HTable -> Constraint
51type HTable :: K.HTable -> Constraint
58class HTable t where
52class HTable t where
59− type HField t = (field :: Type -> Type) | field -> t
53+ type HField t = (field :: Spec -> Type) | field -> t
60− type HConstrainTable t (c :: Type -> Constraint) :: Constraint
54+ type HConstrainTable t (c :: Spec -> Constraint) :: Constraint
61
55
62− hfield :: t context -> HField t a -> context a
56+ hfield :: t context -> HField t spec -> context spec
63− htabulate :: (forall a. HField t a -> context a) -> t context
57+ htabulate :: (forall spec. HField t spec -> context spec) -> t context
64− htraverse :: Apply m => (forall a. f a -> m (g a)) -> t f -> m (t g)
58+ htraverse :: Apply m => (forall spec. f spec -> m (g spec)) -> t f -> m (t g)
65 hdicts :: HConstrainTable t c => t (Dict c)
59 hdicts :: HConstrainTable t c => t (Dict c)
66− hspecs :: t Spec
60+ hspecs :: t SSpec
67
61
68 type HField t = GHField t
62 type HField t = GHField t
69 type HConstrainTable t c = HConstrainTable (GHColumns (Rep (t Proxy))) c
63 type HConstrainTable t c = HConstrainTable (GHColumns (Rep (t Proxy))) c
@@ -74,7 +68,7 @@ class HTable t where
74 , HField (GHColumns (Rep (t Proxy))) ~ HField (GHColumns (Rep (t context)))
68 , HField (GHColumns (Rep (t Proxy))) ~ HField (GHColumns (Rep (t context)))
75 , GHTable context (Rep (t context))
69 , GHTable context (Rep (t context))
76 )
70 )
77− => t context -> HField t a -> context a
71+ => t context -> HField t spec -> context spec
78 hfield table (GHField field) = hfield (toGHColumns (from table)) field
72 hfield table (GHField field) = hfield (toGHColumns (from table)) field
79
73
80 default htabulate ::
74 default htabulate ::
@@ -83,7 +77,7 @@ class HTable t where
83 , HField (GHColumns (Rep (t Proxy))) ~ HField (GHColumns (Rep (t context)))
77 , HField (GHColumns (Rep (t Proxy))) ~ HField (GHColumns (Rep (t context)))
84 , GHTable context (Rep (t context))
78 , GHTable context (Rep (t context))
85 )
79 )
86− => (forall a. HField t a -> context a) -> t context
80+ => (forall spec. HField t spec -> context spec) -> t context
87 htabulate f = to $ fromGHColumns $ htabulate (f . GHField)
81 htabulate f = to $ fromGHColumns $ htabulate (f . GHField)
88
82
89 default htraverse
83 default htraverse
@@ -93,7 +87,7 @@ class HTable t where
93 , Generic (t g), GHTable g (Rep (t g))
87 , Generic (t g), GHTable g (Rep (t g))
94 , GHColumns (Rep (t f)) ~ GHColumns (Rep (t g))
88 , GHColumns (Rep (t f)) ~ GHColumns (Rep (t g))
95 )
89 )
96− => (forall a. f a -> m (g a)) -> t f -> m (t g)
90+ => (forall spec. f spec -> m (g spec)) -> t f -> m (t g)
97 htraverse f = fmap (to . fromGHColumns) . htraverse f . toGHColumns . from
91 htraverse f = fmap (to . fromGHColumns) . htraverse f . toGHColumns . from
98
92
99 default hdicts
93 default hdicts
@@ -107,10 +101,10 @@ class HTable t where
107 hdicts = to $ fromGHColumns (hdicts @(GHColumns (Rep (t Proxy))) @c)
101 hdicts = to $ fromGHColumns (hdicts @(GHColumns (Rep (t Proxy))) @c)
108
102
109 default hspecs ::
103 default hspecs ::
110− ( Generic (t Spec)
104+ ( Generic (t SSpec)
111− , GHTable Spec (Rep (t Spec))
105+ , GHTable SSpec (Rep (t SSpec))
112 )
106 )
113− => t Spec
107+ => t SSpec
114 hspecs = to $ fromGHColumns hspecs
108 hspecs = to $ fromGHColumns hspecs
115
109
116 {-# INLINABLE hfield #-}
110 {-# INLINABLE hfield #-}
@@ -120,43 +114,22 @@ class HTable t where
120 {-# INLINABLE hspecs #-}
114 {-# INLINABLE hspecs #-}
121
115
122
116
123−hfoldMap :: (HTable t, Semigroup s)
124− => (forall a. context a -> s) -> t context -> s
125−hfoldMap f a = getConst $ htraverse (Const . f) a
126−
127−
128hmap :: HTable t
117hmap :: HTable t
129− => (forall a. context a -> context' a) -> t context -> t context'
118+ => (forall spec. context spec -> context' spec) -> t context -> t context'
130hmap f a = htabulate $ \field -> f (hfield a field)
119hmap f a = htabulate $ \field -> f (hfield a field)
131
120
132
121
133htabulateA :: (HTable t, Apply m)
122htabulateA :: (HTable t, Apply m)
134− => (forall a. HField t a -> m (context a)) -> m (t context)
123+ => (forall spec. HField t spec -> m (context spec)) -> m (t context)
135htabulateA f = htraverse getCompose $ htabulate $ Compose . f
124htabulateA f = htraverse getCompose $ htabulate $ Compose . f
136{-# INLINABLE htabulateA #-}
125{-# INLINABLE htabulateA #-}
137
126
138−newtype ApplyP p a b = ApplyP { unApplyP :: p a b }
139−
140−instance Profunctor p => Functor (ApplyP p a) where
141− fmap f = ApplyP . rmap f . unApplyP
142−
143−instance ProductProfunctor p => Apply (ApplyP p a) where
144− ApplyP f <.> ApplyP x = ApplyP (rmap id f **** x)
145−
146−htraverseP :: (HTable t, ProductProfunctor p)
147− => (forall a. p (f a) (g a)) -> p (t f) (t g)
148−htraverseP f = htraversePWithField (const f)
149−
150−htraversePWithField :: (HTable t, ProductProfunctor p)
151− => (forall a. HField t a -> p (f a) (g a)) -> p (t f) (t g)
152−htraversePWithField f = unApplyP $ htabulateA $ \field -> ApplyP $
153− lmap (flip hfield field) (f field)
154
127
155−type GHField :: K.HTable -> Type -> Type
128+type GHField :: K.HTable -> Spec -> Type
156−newtype GHField t a = GHField (HField (GHColumns (Rep (t Proxy))) a)
129+newtype GHField t spec = GHField (HField (GHColumns (Rep (t Proxy))) spec)
157
130
158
131
159−type GHTable :: K.Context -> (Type -> Type) -> Constraint
132+type GHTable :: K.HContext -> (Type -> Type) -> Constraint
160class HTable (GHColumns rep) => GHTable context rep | rep -> context where
133class HTable (GHColumns rep) => GHTable context rep | rep -> context where
161 type GHColumns rep :: K.HTable
134 type GHColumns rep :: K.HTable
162 toGHColumns :: rep x -> GHColumns rep context
135 toGHColumns :: rep x -> GHColumns rep context
@@ -182,10 +155,10 @@ instance (GHTable context a, GHTable context b) => GHTable context (a :*: b) whe
182
155
183
156
184-- | A HField type for indexing into HProduct.
157-- | A HField type for indexing into HProduct.
185−type HProductField :: K.HTable -> K.HTable -> Type -> Type
158+type HProductField :: K.HTable -> K.HTable -> Spec -> Type
186−data HProductField x y a
159+data HProductField x y spec
187− = HFst (HField x a)
160+ = HFst (HField x spec)
188− | HSnd (HField y a)
161+ | HSnd (HField y spec)
189
162
190
163
191instance (HTable x, HTable y) => HTable (HProduct x y) where
164instance (HTable x, HTable y) => HTable (HProduct x y) where
src/Rel8/Schema/HTable/Either.hs+2−2
@@ -15,7 +15,7 @@ import Prelude ()
15
15
16-- rel8
16-- rel8
17import Rel8.Schema.HTable ( HTable )
17import Rel8.Schema.HTable ( HTable )
18−import Rel8.Schema.HTable.Identity ( HIdentity )
18+import Rel8.Schema.HTable.Identity ( HType )
19import Rel8.Schema.HTable.Label ( HLabel )
19import Rel8.Schema.HTable.Label ( HLabel )
20import Rel8.Schema.HTable.Nullify ( HNullify )
20import Rel8.Schema.HTable.Nullify ( HNullify )
21import qualified Rel8.Schema.Kind as K
21import qualified Rel8.Schema.Kind as K
@@ -24,7 +24,7 @@ import Rel8.Type.Tag ( EitherTag )
24
24
25type HEitherTable :: K.HTable -> K.HTable -> K.HTable
25type HEitherTable :: K.HTable -> K.HTable -> K.HTable
26data HEitherTable left right context = HEitherTable
26data HEitherTable left right context = HEitherTable
27− { htag :: HLabel "isRight" (HIdentity EitherTag) context
27+ { htag :: HLabel "isRight" (HType EitherTag) context
28 , hleft :: HLabel "Left" (HNullify left) context
28 , hleft :: HLabel "Left" (HNullify left) context
29 , hright :: HLabel "Right" (HNullify right) context
29 , hright :: HLabel "Right" (HNullify right) context
30 }
30 }
src/Rel8/Schema/HTable/Identity.hs+28−16
@@ -1,17 +1,17 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2−{-# language FlexibleContexts #-}
2+{-# language GADTs #-}
3+{-# language PatternSynonyms #-}
3{-# language StandaloneKindSignatures #-}
4{-# language StandaloneKindSignatures #-}
4{-# language TypeFamilies #-}
5{-# language TypeFamilies #-}
5−{-# language UndecidableInstances #-}
6
6
7module Rel8.Schema.HTable.Identity
7module Rel8.Schema.HTable.Identity
8− ( HIdentity( HIdentity, unHIdentity )
8+ ( HIdentity( HIdentity, HType, unHIdentity )
9+ , HType
9 )
10 )
10where
11where
11
12
12-- base
13-- base
13import Data.Kind ( Type )
14import Data.Kind ( Type )
14−import Data.Type.Equality ( (:~:)( Refl ) )
15import Prelude
15import Prelude
16
16
17-- rel8
17-- rel8
@@ -21,23 +21,35 @@ import Rel8.Schema.HTable
21 , hfield, htabulate, htraverse, hdicts, hspecs
21 , hfield, htabulate, htraverse, hdicts, hspecs
22 )
22 )
23import qualified Rel8.Schema.Kind as K
23import qualified Rel8.Schema.Kind as K
24−import Rel8.Schema.Null ( Sql )
24+import Rel8.Schema.Spec ( Spec( Spec ), KnownSpec, specSing )
25−import Rel8.Schema.Spec ( specification )
26−import Rel8.Type ( DBType )
27
25
28
26
29−type HIdentity :: Type -> K.HTable
27+type HType :: Type -> K.HTable
28+type HType a = HIdentity ('Spec a)
29+
30+
31+pattern HType :: context ('Spec a) -> HType a context
32+pattern HType a = HIdentity a
33+{-# COMPLETE HType #-}
34+
35+
36+type HIdentity :: Spec -> K.HTable
30−newtype HIdentity a context = HIdentity
37+newtype HIdentity spec context = HIdentity
31− { unHIdentity :: context a
38+ { unHIdentity :: context spec
32 }
39 }
33
40
34
41
42+type HIdentityField :: Spec -> Spec -> Type
43+data HIdentityField _spec spec where
44+ HIdentityField :: HIdentityField spec spec
45+
46+
35−instance Sql DBType a => HTable (HIdentity a) where
47+instance KnownSpec spec => HTable (HIdentity spec) where
36− type HConstrainTable (HIdentity a) constraint = constraint a
48+ type HConstrainTable (HIdentity spec) c = c spec
37− type HField (HIdentity a) = (:~:) a
49+ type HField (HIdentity spec) = HIdentityField spec
38
50
39− hfield (HIdentity a) Refl = a
51+ hfield (HIdentity a) HIdentityField = a
40− htabulate f = HIdentity $ f Refl
52+ htabulate f = HIdentity $ f HIdentityField
41 htraverse f (HIdentity a) = HIdentity <$> f a
53 htraverse f (HIdentity a) = HIdentity <$> f a
42 hdicts = HIdentity Dict
54 hdicts = HIdentity Dict
43− hspecs = HIdentity specification
55+ hspecs = HIdentity specSing
src/Rel8/Schema/HTable/Label.hs+4−15
@@ -1,5 +1,4 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2−{-# language RankNTypes #-}
3{-# language RecordWildCards #-}
2{-# language RecordWildCards #-}
4{-# language ScopedTypeVariables #-}
3{-# language ScopedTypeVariables #-}
5{-# language StandaloneKindSignatures #-}
4{-# language StandaloneKindSignatures #-}
@@ -8,7 +7,6 @@
8
7
9module Rel8.Schema.HTable.Label
8module Rel8.Schema.HTable.Label
10 ( HLabel, hlabel, hrelabel, hunlabel
9 ( HLabel, hlabel, hrelabel, hunlabel
11− , hproject
12 )
10 )
13where
11where
14
12
@@ -20,19 +18,16 @@ import Prelude
20
18
21-- rel8
19-- rel8
22import Rel8.Schema.HTable
20import Rel8.Schema.HTable
23− ( HTable, HConstrainTable, HField
24− , htabulate, hfield, htraverse, hdicts, hspecs
25− )
26import qualified Rel8.Schema.Kind as K
21import qualified Rel8.Schema.Kind as K
27−import Rel8.Schema.Spec ( Spec(..) )
22+import Rel8.Schema.Spec ( Spec, SSpec(..) )
28
23
29
24
30type HLabel :: Symbol -> K.HTable -> K.HTable
25type HLabel :: Symbol -> K.HTable -> K.HTable
31newtype HLabel label table context = HLabel (table context)
26newtype HLabel label table context = HLabel (table context)
32
27
33
28
34−type HLabelField :: Symbol -> K.HTable -> Type -> Type
29+type HLabelField :: Symbol -> K.HTable -> Spec -> Type
35−newtype HLabelField label table a = HLabelField (HField table a)
30+newtype HLabelField label table spec = HLabelField (HField table spec)
36
31
37
32
38instance (HTable table, KnownSymbol label) => HTable (HLabel label table) where
33instance (HTable table, KnownSymbol label) => HTable (HLabel label table) where
@@ -45,7 +40,7 @@ instance (HTable table, KnownSymbol label) => HTable (HLabel label table) where
45 htraverse f (HLabel a) = HLabel <$> htraverse f a
40 htraverse f (HLabel a) = HLabel <$> htraverse f a
46 hdicts = HLabel (hdicts @table)
41 hdicts = HLabel (hdicts @table)
47 hspecs = HLabel $ htabulate $ \field -> case hfield (hspecs @table) field of
42 hspecs = HLabel $ htabulate $ \field -> case hfield (hspecs @table) field of
48− Spec {..} -> Spec {labels = symbolVal (Proxy @label) : labels, ..}
43+ SSpec {..} -> SSpec {labels = symbolVal (Proxy @label) : labels, ..}
49 {-# INLINABLE hspecs #-}
44 {-# INLINABLE hspecs #-}
50
45
51
46
@@ -62,9 +57,3 @@ hrelabel = hlabel . hunlabel
62hunlabel :: forall label t context. HLabel label t context -> t context
57hunlabel :: forall label t context. HLabel label t context -> t context
63hunlabel (HLabel a) = a
58hunlabel (HLabel a) = a
64{-# INLINABLE hunlabel #-}
59{-# INLINABLE hunlabel #-}
65−
66−
67−hproject :: ()
68− => (forall ctx. t ctx -> t' ctx)
69− -> HLabel label t context -> HLabel label t' context
70−hproject f (HLabel a) = HLabel (f a)
src/Rel8/Schema/HTable/MapTable.hs+12−22
@@ -6,7 +6,7 @@
6{-# language GADTs #-}
6{-# language GADTs #-}
7{-# language InstanceSigs #-}
7{-# language InstanceSigs #-}
8{-# language MultiParamTypeClasses #-}
8{-# language MultiParamTypeClasses #-}
9−{-# language RankNTypes #-}
9+{-# language PolyKinds #-}
10{-# language ScopedTypeVariables #-}
10{-# language ScopedTypeVariables #-}
11{-# language StandaloneKindSignatures #-}
11{-# language StandaloneKindSignatures #-}
12{-# language TypeApplications #-}
12{-# language TypeApplications #-}
@@ -19,38 +19,34 @@ module Rel8.Schema.HTable.MapTable
19 , MapSpec(..)
19 , MapSpec(..)
20 , Precompose(..)
20 , Precompose(..)
21 , HMapTableField(..)
21 , HMapTableField(..)
22− , hproject
23 )
22 )
24where
23where
25
24
26-- base
25-- base
27import Data.Kind ( Constraint, Type )
26import Data.Kind ( Constraint, Type )
28−import Prelude
27+import Prelude ( ($), (.), (<$>), fmap )
29
28
30-- rel8
29-- rel8
31−import Rel8.FCF ( Exp, Eval )
30+import Rel8.FCF
32import Rel8.Schema.HTable
31import Rel8.Schema.HTable
33− ( HTable, HConstrainTable, HField
34− , hfield, htabulate, htraverse, hdicts, hspecs
35− )
36−import Rel8.Schema.Spec ( Spec )
32+import Rel8.Schema.Spec ( Spec, SSpec )
37import qualified Rel8.Schema.Kind as K
33import qualified Rel8.Schema.Kind as K
38import Rel8.Schema.Dict ( Dict( Dict ) )
34import Rel8.Schema.Dict ( Dict( Dict ) )
39
35
40
36
41−type HMapTable :: (Type -> Exp Type) -> K.HTable -> K.HTable
37+type HMapTable :: (a -> Exp b) -> ((a -> Type) -> Type) -> (b -> Type) -> Type
42−newtype HMapTable f t context = HMapTable
38+newtype HMapTable f t g = HMapTable
43− { unHMapTable :: t (Precompose f context)
39+ { unHMapTable :: t (Precompose f g)
44 }
40 }
45
41
46
42
47−type Precompose :: (Type -> Exp Type) -> K.Context -> K.Context
43+type Precompose :: (a -> Exp b) -> (b -> Type) -> a -> Type
48newtype Precompose f g x = Precompose
44newtype Precompose f g x = Precompose
49 { precomposed :: g (Eval (f x))
45 { precomposed :: g (Eval (f x))
50 }
46 }
51
47
52
48
53−type HMapTableField :: (Type -> Exp Type) -> K.HTable -> K.Context
49+type HMapTableField :: (Spec -> Exp a) -> K.HTable -> a -> Type
54data HMapTableField f t x where
50data HMapTableField f t x where
55 HMapTableField :: HField t a -> HMapTableField f t (Eval (f a))
51 HMapTableField :: HField t a -> HMapTableField f t (Eval (f a))
56
52
@@ -83,17 +79,11 @@ instance (HTable t, MapSpec f) => HTable (HMapTable f t) where
83 {-# INLINABLE hspecs #-}
79 {-# INLINABLE hspecs #-}
84
80
85
81
86−type MapSpec :: (Type -> Exp Type) -> Constraint
82+type MapSpec :: (Spec -> Exp Spec) -> Constraint
87class MapSpec f where
83class MapSpec f where
88− mapInfo :: Spec x -> Spec (Eval (f x))
84+ mapInfo :: SSpec x -> SSpec (Eval (f x))
89
85
90
86
91−type ComposeConstraint :: (Type -> Exp Type) -> (Type -> Constraint) -> Type -> Constraint
87+type ComposeConstraint :: (a -> Exp b) -> (b -> Constraint) -> a -> Constraint
92class c (Eval (f a)) => ComposeConstraint f c a
88class c (Eval (f a)) => ComposeConstraint f c a
93instance c (Eval (f a)) => ComposeConstraint f c a
89instance c (Eval (f a)) => ComposeConstraint f c a
94−
95−
96−hproject :: ()
97− => (forall ctx. t ctx -> t' ctx)
98− -> HMapTable f t context -> HMapTable f t' context
99−hproject f (HMapTable a) = HMapTable (f a)
src/Rel8/Schema/HTable/Maybe.hs+2−2
@@ -15,7 +15,7 @@ import Prelude
15
15
16-- rel8
16-- rel8
17import Rel8.Schema.HTable ( HTable )
17import Rel8.Schema.HTable ( HTable )
18−import Rel8.Schema.HTable.Identity ( HIdentity )
18+import Rel8.Schema.HTable.Identity ( HType )
19import Rel8.Schema.HTable.Label ( HLabel )
19import Rel8.Schema.HTable.Label ( HLabel )
20import Rel8.Schema.HTable.Nullify ( HNullify )
20import Rel8.Schema.HTable.Nullify ( HNullify )
21import qualified Rel8.Schema.Kind as K
21import qualified Rel8.Schema.Kind as K
@@ -24,7 +24,7 @@ import Rel8.Type.Tag ( MaybeTag )
24
24
25type HMaybeTable :: K.HTable -> K.HTable
25type HMaybeTable :: K.HTable -> K.HTable
26data HMaybeTable table context = HMaybeTable
26data HMaybeTable table context = HMaybeTable
27− { htag :: HLabel "isJust" (HIdentity (Maybe MaybeTag)) context
27+ { htag :: HLabel "isJust" (HType (Maybe MaybeTag)) context
28 , hjust :: HLabel "Just" (HNullify table) context
28 , hjust :: HLabel "Just" (HNullify table) context
29 }
29 }
30 deriving stock Generic
30 deriving stock Generic
src/Rel8/Schema/HTable/Nullify.hs+24−22
@@ -23,12 +23,10 @@ module Rel8.Schema.HTable.Nullify
23 , hnulls
23 , hnulls
24 , hnullify
24 , hnullify
25 , hunnullify
25 , hunnullify
26− , hproject
27 )
26 )
28where
27where
29
28
30-- base
29-- base
31−import Data.Kind ( Type )
32import GHC.Generics ( Generic )
30import GHC.Generics ( Generic )
33import Prelude hiding ( null )
31import Prelude hiding ( null )
34
32
@@ -39,11 +37,10 @@ import Rel8.Schema.HTable.MapTable
39 ( HMapTable, HMapTableField( HMapTableField )
37 ( HMapTable, HMapTableField( HMapTableField )
40 , MapSpec, mapInfo
38 , MapSpec, mapInfo
41 )
39 )
42−import qualified Rel8.Schema.HTable.MapTable as HMapTable ( hproject )
43import qualified Rel8.Schema.Kind as K
40import qualified Rel8.Schema.Kind as K
44import Rel8.Schema.Null ( Nullity( Null, NotNull ) )
41import Rel8.Schema.Null ( Nullity( Null, NotNull ) )
45import qualified Rel8.Schema.Null as Type ( Nullify )
42import qualified Rel8.Schema.Null as Type ( Nullify )
46−import Rel8.Schema.Spec ( Spec(..) )
43+import Rel8.Schema.Spec ( Spec( Spec ), SSpec(..) )
47
44
48-- semigroupoids
45-- semigroupoids
49import Data.Functor.Apply ( Apply )
46import Data.Functor.Apply ( Apply )
@@ -55,14 +52,17 @@ newtype HNullify table context = HNullify (HMapTable Nullify table context)
55 deriving anyclass HTable
52 deriving anyclass HTable
56
53
57
54
58−-- | Transform a 'Type' by allowing it to be @null@.
55+-- | Transform a 'Spec' by allowing it to be @null@.
59−data Nullify :: Type -> Exp Type
56+data Nullify :: Spec -> Exp Spec
57+
58+
60−type instance Eval (Nullify a) = Type.Nullify a
59+type instance Eval (Nullify ('Spec a)) =
60+ 'Spec (Type.Nullify a)
61
61
62
62
63instance MapSpec Nullify where
63instance MapSpec Nullify where
64 mapInfo = \case
64 mapInfo = \case
65− Spec {nullity, ..} -> Spec
65+ SSpec {nullity, ..} -> SSpec
66 { nullity = case nullity of
66 { nullity = case nullity of
67 Null -> Null
67 Null -> Null
68 NotNull -> Null
68 NotNull -> Null
@@ -71,47 +71,49 @@ instance MapSpec Nullify where
71
71
72
72
73hguard :: HTable t
73hguard :: HTable t
74− => (forall a. context (Maybe a) -> context (Maybe a))
74+ => (forall a. context ('Spec (Maybe a)) -> context ('Spec (Maybe a)))
75 -> HNullify t context -> HNullify t context
75 -> HNullify t context -> HNullify t context
76hguard guarder (HNullify as) = HNullify $ htabulate $ \(HMapTableField field) ->
76hguard guarder (HNullify as) = HNullify $ htabulate $ \(HMapTableField field) ->
77 case hfield hspecs field of
77 case hfield hspecs field of
78− Spec {nullity} -> case hfield as (HMapTableField field) of
78+ SSpec {nullity} -> case hfield as (HMapTableField field) of
79 a -> case nullity of
79 a -> case nullity of
80 Null -> guarder a
80 Null -> guarder a
81 NotNull -> guarder a
81 NotNull -> guarder a
82
82
83
83
84hnulls :: HTable t
84hnulls :: HTable t
85+ => (forall a. ()
86+ => SSpec ('Spec a)
85− => (forall a. Spec a -> context (Type.Nullify a))
87+ -> context ('Spec (Type.Nullify a)))
86 -> HNullify t context
88 -> HNullify t context
87hnulls null = HNullify $ htabulate $ \(HMapTableField field) ->
89hnulls null = HNullify $ htabulate $ \(HMapTableField field) ->
88 case hfield hspecs field of
90 case hfield hspecs field of
89− spec@Spec {} -> null spec
91+ spec@SSpec {} -> null spec
90{-# INLINABLE hnulls #-}
92{-# INLINABLE hnulls #-}
91
93
92
94
93hnullify :: HTable t
95hnullify :: HTable t
96+ => (forall a. ()
97+ => SSpec ('Spec a)
98+ -> context ('Spec a)
94− => (forall a. Spec a -> context a -> context (Type.Nullify a))
99+ -> context ('Spec (Type.Nullify a)))
95 -> t context
100 -> t context
96 -> HNullify t context
101 -> HNullify t context
97hnullify nullifier a = HNullify $ htabulate $ \(HMapTableField field) ->
102hnullify nullifier a = HNullify $ htabulate $ \(HMapTableField field) ->
98 case hfield hspecs field of
103 case hfield hspecs field of
99− spec@Spec {} -> nullifier spec (hfield a field)
104+ spec@SSpec {} -> nullifier spec (hfield a field)
100{-# INLINABLE hnullify #-}
105{-# INLINABLE hnullify #-}
101
106
102
107
103hunnullify :: (HTable t, Apply m)
108hunnullify :: (HTable t, Apply m)
109+ => (forall a. ()
110+ => SSpec ('Spec a)
104− => (forall a. Spec a -> context (Type.Nullify a) -> m (context a))
111+ -> context ('Spec (Type.Nullify a))
112+ -> m (context ('Spec a)))
105 -> HNullify t context
113 -> HNullify t context
106 -> m (t context)
114 -> m (t context)
107hunnullify unnullifier (HNullify as) =
115hunnullify unnullifier (HNullify as) =
108 htabulateA $ \field -> case hfield hspecs field of
116 htabulateA $ \field -> case hfield hspecs field of
109− spec@Spec {} -> case hfield as (HMapTableField field) of
117+ spec@SSpec {} -> case hfield as (HMapTableField field) of
110 a -> unnullifier spec a
118 a -> unnullifier spec a
111{-# INLINABLE hunnullify #-}
119{-# INLINABLE hunnullify #-}
112−
113−
114−hproject :: ()
115− => (forall ctx. t ctx -> t' ctx)
116− -> HNullify t context -> HNullify t' context
117−hproject f (HNullify a) = HNullify (HMapTable.hproject f a)
src/Rel8/Schema/HTable/These.hs+3−3
@@ -15,7 +15,7 @@ import Prelude
15
15
16-- rel8
16-- rel8
17import Rel8.Schema.HTable ( HTable )
17import Rel8.Schema.HTable ( HTable )
18−import Rel8.Schema.HTable.Identity ( HIdentity )
18+import Rel8.Schema.HTable.Identity ( HType )
19import Rel8.Schema.HTable.Label ( HLabel )
19import Rel8.Schema.HTable.Label ( HLabel )
20import Rel8.Schema.HTable.Nullify ( HNullify )
20import Rel8.Schema.HTable.Nullify ( HNullify )
21import qualified Rel8.Schema.Kind as K
21import qualified Rel8.Schema.Kind as K
@@ -24,9 +24,9 @@ import Rel8.Type.Tag ( MaybeTag )
24
24
25type HTheseTable :: K.HTable -> K.HTable -> K.HTable
25type HTheseTable :: K.HTable -> K.HTable -> K.HTable
26data HTheseTable here there context = HTheseTable
26data HTheseTable here there context = HTheseTable
27− { hhereTag :: HLabel "hereTag" (HIdentity (Maybe MaybeTag)) context
27+ { hhereTag :: HLabel "hereTag" (HType (Maybe MaybeTag)) context
28 , hhere :: HLabel "Here" (HNullify here) context
28 , hhere :: HLabel "Here" (HNullify here) context
29− , hthereTag :: HLabel "thereTag" (HIdentity (Maybe MaybeTag)) context
29+ , hthereTag :: HLabel "thereTag" (HType (Maybe MaybeTag)) context
30 , hthere :: HLabel "There" (HNullify there) context
30 , hthere :: HLabel "There" (HNullify there) context
31 }
31 }
32 deriving stock Generic
32 deriving stock Generic
src/Rel8/Schema/HTable/Vectorize.hs+40−39
@@ -9,6 +9,7 @@
9{-# language GADTs #-}
9{-# language GADTs #-}
10{-# language LambdaCase #-}
10{-# language LambdaCase #-}
11{-# language MultiParamTypeClasses #-}
11{-# language MultiParamTypeClasses #-}
12+{-# language NamedFieldPuns #-}
12{-# language RankNTypes #-}
13{-# language RankNTypes #-}
13{-# language RecordWildCards #-}
14{-# language RecordWildCards #-}
14{-# language ScopedTypeVariables #-}
15{-# language ScopedTypeVariables #-}
@@ -21,39 +22,33 @@ module Rel8.Schema.HTable.Vectorize
21 ( HVectorize
22 ( HVectorize
22 , hvectorize, hunvectorize
23 , hvectorize, hunvectorize
23 , happend, hempty
24 , happend, hempty
24− , hproject
25− , hcolumn
26 )
25 )
27where
26where
28
27
29-- base
28-- base
30−import Data.Kind ( Constraint, Type )
29+import Data.Kind ( Type )
31import Data.List.NonEmpty ( NonEmpty )
30import Data.List.NonEmpty ( NonEmpty )
32−import GHC.Generics (Generic)
33import Prelude
31import Prelude
34
32
35-- rel8
33-- rel8
36−import Rel8.FCF ( Eval, Exp )
37import Rel8.Schema.Dict ( Dict( Dict ) )
34import Rel8.Schema.Dict ( Dict( Dict ) )
38import qualified Rel8.Schema.Kind as K
35import qualified Rel8.Schema.Kind as K
36+import Rel8.Schema.HTable
37+ ( HTable
39−import Rel8.Schema.HTable ( HTable, hfield, htabulate, htabulateA, hspecs )
38+ , hfield, htabulate, htabulateA, hspecs
40−import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )
41−import Rel8.Schema.HTable.MapTable
42− ( HMapTable( HMapTable ), HMapTableField( HMapTableField )
43− , MapSpec, mapInfo
44− , Precompose( Precompose )
45 )
39 )
46−import qualified Rel8.Schema.HTable.MapTable as HMapTable ( hproject )
47import Rel8.Schema.Null ( Unnullify, NotNull, Nullity( NotNull ) )
40import Rel8.Schema.Null ( Unnullify, NotNull, Nullity( NotNull ) )
48−import Rel8.Schema.Spec ( Spec(..) )
41+import Rel8.Schema.Spec ( Spec( Spec ), SSpec(..) )
49import Rel8.Type.Array ( listTypeInformation, nonEmptyTypeInformation )
42import Rel8.Type.Array ( listTypeInformation, nonEmptyTypeInformation )
50import Rel8.Type.Information ( TypeInformation )
43import Rel8.Type.Information ( TypeInformation )
51
44
52-- semialign
45-- semialign
53import Data.Zip ( Unzip, Zip, Zippy(..) )
46import Data.Zip ( Unzip, Zip, Zippy(..) )
47+import Rel8.FCF
48+import Rel8.Schema.HTable.MapTable
49+import GHC.Generics (Generic)
54
50
55
51
56−type Vector :: (Type -> Type) -> Constraint
57class Vector list where
52class Vector list where
58 listNotNull :: proxy a -> Dict NotNull (list a)
53 listNotNull :: proxy a -> Dict NotNull (list a)
59 vectorTypeInformation :: ()
54 vectorTypeInformation :: ()
@@ -78,16 +73,16 @@ newtype HVectorize list table context = HVectorize (HMapTable (Vectorize list) t
78 deriving anyclass HTable
73 deriving anyclass HTable
79
74
80
75
81−data Vectorize :: (Type -> Type) -> Type -> Exp Type
76+data Vectorize :: (Type -> Type) -> Spec -> Exp Spec
82
77
83
78
84−type instance Eval (Vectorize list a) = list a
79+type instance Eval (Vectorize list ('Spec a)) = 'Spec (list a)
85
80
86
81
87instance Vector list => MapSpec (Vectorize list) where
82instance Vector list => MapSpec (Vectorize list) where
88 mapInfo = \case
83 mapInfo = \case
89− Spec {..} -> case listNotNull @list nullity of
84+ SSpec {..} -> case listNotNull @list nullity of
90− Dict -> Spec
85+ Dict -> SSpec
91 { nullity = NotNull
86 { nullity = NotNull
92 , info = vectorTypeInformation nullity info
87 , info = vectorTypeInformation nullity info
93 , ..
88 , ..
@@ -95,49 +90,55 @@ instance Vector list => MapSpec (Vectorize list) where
95
90
96
91
97hvectorize :: (HTable t, Unzip f, Vector list)
92hvectorize :: (HTable t, Unzip f, Vector list)
93+ => (forall a. ()
94+ => SSpec ('Spec a)
95+ -> f (context ('Spec a))
98− => (forall a. Spec a -> f (context a) -> context' (list a))
96+ -> context' ('Spec (list a)))
99 -> f (t context)
97 -> f (t context)
100 -> HVectorize list t context'
98 -> HVectorize list t context'
101hvectorize vectorizer as = HVectorize $ htabulate $ \(HMapTableField field) ->
99hvectorize vectorizer as = HVectorize $ htabulate $ \(HMapTableField field) ->
102 case hfield hspecs field of
100 case hfield hspecs field of
103− spec -> vectorizer spec (fmap (`hfield` field) as)
101+ spec@SSpec {} -> vectorizer spec (fmap (`hfield` field) as)
104{-# INLINABLE hvectorize #-}
102{-# INLINABLE hvectorize #-}
105
103
106
104
107hunvectorize :: (HTable t, Zip f, Vector list)
105hunvectorize :: (HTable t, Zip f, Vector list)
106+ => (forall a. ()
107+ => SSpec ('Spec a)
108− => (forall a. Spec a -> context (list a) -> f (context' a))
108+ -> context ('Spec (list a))
109+ -> f (context' ('Spec a)))
109 -> HVectorize list t context
110 -> HVectorize list t context
110 -> f (t context')
111 -> f (t context')
111hunvectorize unvectorizer (HVectorize table) =
112hunvectorize unvectorizer (HVectorize table) =
112 getZippy $ htabulateA $ \field -> case hfield hspecs field of
113 getZippy $ htabulateA $ \field -> case hfield hspecs field of
113− spec -> case hfield table (HMapTableField field) of
114+ spec@SSpec{} -> case hfield table (HMapTableField field) of
114 a -> Zippy (unvectorizer spec a)
115 a -> Zippy (unvectorizer spec a)
115{-# INLINABLE hunvectorize #-}
116{-# INLINABLE hunvectorize #-}
116
117
117
118
118−happend :: (HTable t, Vector list)
119+happend :: (HTable t, Vector list) =>
119− => (forall a. Spec a -> context (list a) -> context (list a) -> context (list a))
120+ ( forall a. ()
121+ => Nullity a
122+ -> TypeInformation (Unnullify a)
123+ -> context ('Spec (list a))
124+ -> context ('Spec (list a))
125+ -> context ('Spec (list a))
126+ )
120 -> HVectorize list t context
127 -> HVectorize list t context
121 -> HVectorize list t context
128 -> HVectorize list t context
122 -> HVectorize list t context
129 -> HVectorize list t context
123happend append (HVectorize as) (HVectorize bs) = HVectorize $
130happend append (HVectorize as) (HVectorize bs) = HVectorize $
124 htabulate $ \field@(HMapTableField j) -> case (hfield as field, hfield bs field) of
131 htabulate $ \field@(HMapTableField j) -> case (hfield as field, hfield bs field) of
125 (a, b) -> case hfield hspecs j of
132 (a, b) -> case hfield hspecs j of
126− spec -> append spec a b
133+ SSpec {nullity, info} -> append nullity info a b
127
134
128
135
129−hempty :: HTable t
136+hempty :: HTable t =>
130− => (forall a. Spec a -> context [a])
137+ ( forall a. ()
138+ => Nullity a
139+ -> TypeInformation (Unnullify a)
140+ -> context ('Spec [a])
141+ )
131 -> HVectorize [] t context
142 -> HVectorize [] t context
132−hempty empty = HVectorize $ htabulate $ \(HMapTableField field) ->
143+hempty empty = HVectorize $ htabulate $ \(HMapTableField field) -> case hfield hspecs field of
133− empty (hfield hspecs field)
144+ SSpec {nullity, info} -> empty nullity info
134−
135−
136−hproject :: ()
137− => (forall ctx. t ctx -> t' ctx)
138− -> HVectorize list t context -> HVectorize list t' context
139−hproject f (HVectorize a) = HVectorize (HMapTable.hproject f a)
140−
141−
142−hcolumn :: HVectorize list (HIdentity a) context -> context (list a)
143−hcolumn (HVectorize (HMapTable (HIdentity (Precompose a)))) = a
src/Rel8/Schema/Kind.hs+15−6
@@ -1,9 +1,8 @@
1{-# language StandaloneKindSignatures #-}
1{-# language StandaloneKindSignatures #-}
2
2
3module Rel8.Schema.Kind
3module Rel8.Schema.Kind
4− ( Rel8able
4+ ( Context, Rel8able
5− , Context
6− , HTable
5+ , HContext, HTable
7 )
6 )
8where
7where
9
8
@@ -11,13 +10,23 @@ where
11import Data.Kind ( Type )
10import Data.Kind ( Type )
12import Prelude ()
11import Prelude ()
13
12
13+-- rel8
14+import Rel8.Schema.Spec ( Spec )
14
15
16+
15−type Context :: Type
17+type HContext :: Type
16−type Context = Type -> Type
18+type HContext = Spec -> Type
17
19
18
20
19type HTable :: Type
21type HTable :: Type
22+type HTable = HContext -> Type
23+
24+
25+data X
26+
27+
28+type Context :: Type
20−type HTable = Context -> Type
29+type Context = X -> Type
21
30
22
31
23type Rel8able :: Type
32type Rel8able :: Type
src/Rel8/Schema/Name.hs+52−33
@@ -3,44 +3,41 @@
3{-# language FlexibleContexts #-}
3{-# language FlexibleContexts #-}
4{-# language FlexibleInstances #-}
4{-# language FlexibleInstances #-}
5{-# language GADTs #-}
5{-# language GADTs #-}
6−{-# language GeneralizedNewtypeDeriving #-}
7{-# language MultiParamTypeClasses #-}
6{-# language MultiParamTypeClasses #-}
7+{-# language PolyKinds #-}
8{-# language RankNTypes #-}
8{-# language RankNTypes #-}
9+{-# language StandaloneDeriving #-}
9{-# language StandaloneKindSignatures #-}
10{-# language StandaloneKindSignatures #-}
10{-# language TypeFamilies #-}
11{-# language TypeFamilies #-}
11{-# language UndecidableInstances #-}
12{-# language UndecidableInstances #-}
13+{-# language UndecidableSuperClasses #-}
12
14
13module Rel8.Schema.Name
15module Rel8.Schema.Name
14 ( Name(..)
16 ( Name(..)
17+ , Col( N, unN )
15 , Selects
18 , Selects
16− , ppColumn
17 )
19 )
18where
20where
19
21
20-- base
22-- base
21−import Data.Functor.Identity ( Identity( Identity ) )
23+import Data.Functor.Identity ( Identity )
22import Data.Kind ( Constraint, Type )
24import Data.Kind ( Constraint, Type )
23−import Data.String ( IsString )
25+import Data.String ( IsString, fromString )
24import Prelude
26import Prelude
25
27
26−-- opaleye
27−import qualified Opaleye.Internal.HaskellDB.Sql as Opaleye
28−import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye
29−
30−-- pretty
31−import Text.PrettyPrint ( Doc )
32−
33-- rel8
28-- rel8
34import Rel8.Expr ( Expr )
29import Rel8.Expr ( Expr )
35−import qualified Rel8.Schema.Kind as K
30+import Rel8.Schema.Context ( Interpretation, Col )
36−import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )
31+import Rel8.Schema.HTable.Identity ( HIdentity( HType ), HType )
37import Rel8.Schema.Null ( Sql )
32import Rel8.Schema.Null ( Sql )
33+import Rel8.Schema.Reify ( notReify )
34+import Rel8.Schema.Result ( Result )
35+import Rel8.Schema.Spec ( Spec( Spec ) )
38import Rel8.Table
36import Rel8.Table
39 ( Table, Columns, Context, fromColumns, toColumns
37 ( Table, Columns, Context, fromColumns, toColumns
40− , FromExprs, fromResult, toResult
38+ , reify, unreify, coherence, congruence
41− , Transpose
42 )
39 )
43−import Rel8.Table.Transpose ( Transposes )
40+import Rel8.Table.Recontextualize ( Recontextualize )
44import Rel8.Type ( DBType )
41import Rel8.Type ( DBType )
45
42
46
43
@@ -48,30 +45,52 @@ import Rel8.Type ( DBType )
48-- schema definition. You can construct names by using the @OverloadedStrings@
45-- schema definition. You can construct names by using the @OverloadedStrings@
49-- extension and writing string literals. This is typically done when providing
46-- extension and writing string literals. This is typically done when providing
50-- a 'TableSchema' value.
47-- a 'TableSchema' value.
51−type Name :: K.Context
48+type Name :: k -> Type
52−newtype Name a = Name String
49+data Name a where
50+ Name :: k ~ Type => !String -> Name (a :: k)
51+
52+
53− deriving stock Show
53+deriving stock instance Show (Name a)
54− deriving newtype IsString
54+
55+
56+instance k ~ Type => IsString (Name (a :: k)) where
57+ fromString = Name
55
58
56
59
57instance Sql DBType a => Table Name (Name a) where
60instance Sql DBType a => Table Name (Name a) where
58− type Columns (Name a) = HIdentity a
61+ type Columns (Name a) = HType a
59 type Context (Name a) = Name
62 type Context (Name a) = Name
60− type FromExprs (Name a) = a
61− type Transpose to (Name a) = to a
62
63
63− toColumns a = HIdentity a
64+ toColumns a = HType (N a)
64− fromColumns (HIdentity a) = a
65+ fromColumns (HType (N a)) = a
65− toResult a = HIdentity (Identity a)
66+ reify = notReify
66− fromResult (HIdentity (Identity a)) = a
67+ unreify = notReify
68+ coherence = notReify
69+ congruence = notReify
70+
71+
72+instance Sql DBType a => Recontextualize Expr Name (Expr a) (Name a)
73+
74+
75+instance Sql DBType a => Recontextualize Result Name (Identity a) (Name a)
76+
77+
78+instance Sql DBType a => Recontextualize Name Expr (Name a) (Expr a)
79+
80+
81+instance Sql DBType a => Recontextualize Name Result (Name a) (Identity a)
82+
83+
84+instance Sql DBType a => Recontextualize Name Name (Name a) (Name a)
85+
86+
87+instance Interpretation Name where
88+ data Col Name _spec where
89+ N :: {unN :: !(Name a)} -> Col Name ('Spec a)
67
90
68
91
69-- | @Selects a b@ means that @a@ is a schema (i.e., a 'Table' of 'Name's) for
92-- | @Selects a b@ means that @a@ is a schema (i.e., a 'Table' of 'Name's) for
70-- the 'Expr' columns in @b@.
93-- the 'Expr' columns in @b@.
71type Selects :: Type -> Type -> Constraint
94type Selects :: Type -> Type -> Constraint
72−class Transposes Name Expr names exprs => Selects names exprs
95+class Recontextualize Name Expr names exprs => Selects names exprs
73−instance Transposes Name Expr names exprs => Selects names exprs
96+instance Recontextualize Name Expr names exprs => Selects names exprs
74−
75−
76−ppColumn :: String -> Doc
77−ppColumn = Opaleye.ppSqlExpr . Opaleye.ColumnSqlExpr . Opaleye.SqlColumn
src/Rel8/Schema/Reify.hsnew file+68
@@ -0,0 +1,68 @@
1+{-# language AllowAmbiguousTypes #-}
2+{-# language EmptyCase #-}
3+{-# language DataKinds #-}
4+{-# language FlexibleInstances #-}
5+{-# language ScopedTypeVariables #-}
6+{-# language StandaloneKindSignatures #-}
7+{-# language TypeApplications #-}
8+{-# language TypeFamilies #-}
9+{-# language TypeOperators #-}
10+{-# language UndecidableInstances #-}
11+
12+module Rel8.Schema.Reify
13+ ( Reify, Col( Reify ), hreify, hunreify
14+ , UnwrapReify
15+ , NotReify, notReify
16+ )
17+where
18+
19+-- base
20+import Data.Kind ( Constraint )
21+import Data.Type.Equality ( (:~:)( Refl ) )
22+import Prelude
23+
24+-- rel8
25+import Rel8.Schema.Context ( Interpretation, Col )
26+import Rel8.Schema.HTable ( HTable, hmap )
27+import Rel8.Schema.Kind ( Context )
28+
29+
30+type Reify :: Context -> Context
31+data Reify context a
32+
33+
34+instance Interpretation (Reify context) where
35+ newtype Col (Reify context) spec = Reify (Col context spec)
36+
37+
38+hreify :: HTable t => t (Col context) -> t (Col (Reify context))
39+hreify = hmap Reify
40+
41+
42+hunreify :: HTable t => t (Col (Reify context)) -> t (Col context)
43+hunreify = hmap (\(Reify a) -> a)
44+
45+
46+type UnwrapReify :: Context -> Context
47+type family UnwrapReify context where
48+ UnwrapReify (Reify context) = context
49+
50+
51+type IsReify :: Context -> Bool
52+type family IsReify context where
53+ IsReify (Reify _) = 'True
54+ IsReify _ = 'False
55+
56+
57+type NotReify :: Context -> Constraint
58+class IsReify context ~ 'False => NotReify context
59+instance IsReify context ~ 'False => NotReify context
60+
61+
62+notReify :: forall context ctx a. NotReify context => context :~: Reify ctx -> a
63+notReify refl = case lemma @context of
64+ Refl -> case refl of
65+
66+
67+lemma :: NotReify context => IsReify context :~: 'False
68+lemma = Refl
src/Rel8/Schema/Result.hs+52−16
@@ -1,24 +1,28 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2+{-# language EmptyCase #-}
2{-# language GADTs #-}
3{-# language GADTs #-}
4+{-# language LambdaCase #-}
3{-# language NamedFieldPuns #-}
5{-# language NamedFieldPuns #-}
4{-# language StandaloneKindSignatures #-}
6{-# language StandaloneKindSignatures #-}
5{-# language TypeFamilies #-}
7{-# language TypeFamilies #-}
6
8
7module Rel8.Schema.Result
9module Rel8.Schema.Result
8− ( Result
10+ ( Col( R, unR ), Result
11+ , NotResult( NotResult ), absurd
9 , null, nullifier, unnullifier
12 , null, nullifier, unnullifier
10 , vectorizer, unvectorizer
13 , vectorizer, unvectorizer
11 )
14 )
12where
15where
13
16
14-- base
17-- base
15−import Data.Functor.Identity ( Identity( Identity), runIdentity )
18+import Data.Kind ( Type )
16import Prelude hiding ( null )
19import Prelude hiding ( null )
17
20
18-- rel8
21-- rel8
22+import Rel8.Schema.Context ( Interpretation( Col ) )
19import Rel8.Schema.Kind ( Context )
23import Rel8.Schema.Kind ( Context )
20import Rel8.Schema.Null ( Nullify, Nullity( Null, NotNull ) )
24import Rel8.Schema.Null ( Nullify, Nullity( Null, NotNull ) )
21−import Rel8.Schema.Spec ( Spec(..) )
25+import Rel8.Schema.Spec ( Spec( Spec ), SSpec(..) )
22
26
23
27
24-- | The @Result@ context is the context used for decoded query results.
28-- | The @Result@ context is the context used for decoded query results.
@@ -26,29 +30,61 @@ import Rel8.Schema.Spec ( Spec(..) )
26-- When a query is executed against a PostgreSQL database, Rel8 parses the
30-- When a query is executed against a PostgreSQL database, Rel8 parses the
27-- returned rows, decoding each row into the @Result@ context.
31-- returned rows, decoding each row into the @Result@ context.
28type Result :: Context
32type Result :: Context
29−type Result = Identity
33+data Result a
30
34
31
35
36+instance Interpretation Result where
37+ data Col Result _spec where
32−null :: Result (Maybe a)
38+ R :: {unR :: !a} -> Col Result ('Spec a)
33−null = Identity Nothing
34
39
35
40
41+type IsResult :: Context -> Bool
42+type family IsResult context where
43+ IsResult Result = 'True
44+ IsResult _ = 'False
45+
46+
47+type NotResult :: Context -> Type
48+data NotResult context where
49+ NotResult :: IsResult context ~ 'False => NotResult context
50+
51+
52+absurd :: NotResult Result -> a
53+absurd = \case
54+
55+
56+null :: Col Result ('Spec (Maybe a))
57+null = R Nothing
58+
59+
60+nullifier :: ()
61+ => SSpec ('Spec a)
62+ -> Col Result ('Spec a)
36−nullifier :: Spec a -> Result a -> Result (Nullify a)
63+ -> Col Result ('Spec (Nullify a))
37−nullifier Spec {nullity} (Identity a) = Identity $ case nullity of
64+nullifier SSpec {nullity} (R a) = R $ case nullity of
38 Null -> a
65 Null -> a
39 NotNull -> Just a
66 NotNull -> Just a
40
67
41
68
69+unnullifier :: ()
70+ => SSpec ('Spec a)
42−unnullifier :: Spec a -> Result (Nullify a) -> Maybe (Result a)
71+ -> Col Result ('Spec (Nullify a))
72+ -> Maybe (Col Result ('Spec a))
43−unnullifier Spec {nullity} (Identity a) =
73+unnullifier SSpec {nullity} (R a) =
44 case nullity of
74 case nullity of
45− Null -> pure $ Identity a
75+ Null -> pure $ R a
46− NotNull -> Identity <$> a
76+ NotNull -> R <$> a
47
77
48
78
49−vectorizer :: Functor f => Spec a -> f (Result a) -> Result (f a)
79+vectorizer :: Functor f
80+ => SSpec ('Spec a)
81+ -> f (Col Result ('Spec a))
82+ -> Col Result ('Spec (f a))
50−vectorizer _ = Identity . fmap runIdentity
83+vectorizer _ = R . fmap unR
51
84
52
85
53−unvectorizer :: Functor f => Spec a -> Result (f a) -> f (Result a)
86+unvectorizer :: Functor f
87+ => SSpec ('Spec a)
88+ -> Col Result ('Spec (f a))
89+ -> f (Col Result ('Spec a))
54−unvectorizer _ (Identity results) = Identity <$> results
90+unvectorizer _ (R results) = R <$> results
src/Rel8/Schema/Spec.hs+30−16
@@ -1,15 +1,18 @@
1+{-# language DataKinds #-}
1{-# language FlexibleContexts #-}
2{-# language FlexibleContexts #-}
2−{-# language MonoLocalBinds #-}
3+{-# language GADTs #-}
3{-# language StandaloneKindSignatures #-}
4{-# language StandaloneKindSignatures #-}
5+{-# language UndecidableInstances #-}
4
6
5module Rel8.Schema.Spec
7module Rel8.Schema.Spec
8+ ( Spec( Spec )
6− ( Spec( Spec, labels, info, nullity )
9+ , SSpec( SSpec, labels, info, nullity )
7− , specification
10+ , KnownSpec( specSing )
8 )
11 )
9where
12where
10
13
11-- base
14-- base
12−import Data.Kind ( Type )
15+import Data.Kind ( Constraint, Type )
13import Prelude
16import Prelude
14
17
15-- rel8
18-- rel8
@@ -18,17 +21,28 @@ import Rel8.Type ( DBType, typeInformation )
18import Rel8.Type.Information ( TypeInformation )
21import Rel8.Type.Information ( TypeInformation )
19
22
20
23
21−type Spec :: Type -> Type
24+type Spec :: Type
22−data Spec a = Spec
25+newtype Spec = Spec Type
23− { labels :: [String]
24− , info :: TypeInformation (Unnullify a)
25− , nullity :: Nullity a
26− }
27
26
28
27
28+type SSpec :: Spec -> Type
29+data SSpec spec where
30+ SSpec ::
31+ { labels :: [String]
32+ , info :: TypeInformation (Unnullify a)
33+ , nullity :: Nullity a
34+ }
35+ -> SSpec ('Spec a)
36+
37+
38+type KnownSpec :: Spec -> Constraint
39+class KnownSpec spec where
40+ specSing :: SSpec spec
41+
42+
29−specification :: Sql DBType a => Spec a
43+instance Sql DBType a => KnownSpec ('Spec a) where
30−specification = Spec
44+ specSing = SSpec
31− { labels = []
45+ { labels = []
32− , info = typeInformation
46+ , info = typeInformation
33− , nullity = nullable
47+ , nullity = nullable
34− }
48+ }
src/Rel8/Schema/Spec/Constrain.hsnew file+32
@@ -0,0 +1,32 @@
1+{-# language ConstraintKinds #-}
2+{-# language DataKinds #-}
3+{-# language FlexibleInstances #-}
4+{-# language MultiParamTypeClasses #-}
5+{-# language StandaloneKindSignatures #-}
6+{-# language TypeFamilies #-}
7+{-# language UndecidableInstances #-}
8+{-# language UndecidableSuperClasses #-}
9+
10+module Rel8.Schema.Spec.Constrain
11+ ( ConstrainSpec
12+ )
13+where
14+
15+-- base
16+import Data.Kind ( Constraint, Type )
17+import Prelude ()
18+
19+-- rel8
20+import Rel8.Schema.Spec ( Spec( Spec ) )
21+
22+
23+type Unspec :: Spec -> Type
24+type family Unspec spec where
25+ Unspec ('Spec a) = a
26+
27+
28+type ConstrainSpec :: (Type -> Constraint) -> Spec -> Constraint
29+class (spec ~ 'Spec (Unspec spec), constraint (Unspec spec)) =>
30+ ConstrainSpec constraint spec
31+instance (spec ~ 'Spec (Unspec spec), constraint (Unspec spec)) =>
32+ ConstrainSpec constraint spec
src/Rel8/Schema/Table.hs−20
@@ -1,26 +1,14 @@
1{-# language DeriveFunctor #-}
1{-# language DeriveFunctor #-}
2{-# language DerivingStrategies #-}
2{-# language DerivingStrategies #-}
3−{-# language DisambiguateRecordFields #-}
4−{-# language NamedFieldPuns #-}
5−{-# language StandaloneKindSignatures #-}
6
3
7module Rel8.Schema.Table
4module Rel8.Schema.Table
8 ( TableSchema(..)
5 ( TableSchema(..)
9− , ppTable
10 )
6 )
11where
7where
12
8
13-- base
9-- base
14−import Data.Kind ( Type )
15import Prelude
10import Prelude
16
11
17−-- opaleye
18−import qualified Opaleye.Internal.HaskellDB.Sql as Opaleye
19−import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye
20−
21−-- pretty
22−import Text.PrettyPrint ( Doc )
23−
24
12
25-- | The schema for a table. This is used to specify the name and schema that a
13-- | The schema for a table. This is used to specify the name and schema that a
26-- table belongs to (the @FROM@ part of a SQL query), along with the schema of
14-- table belongs to (the @FROM@ part of a SQL query), along with the schema of
@@ -28,7 +16,6 @@ import Text.PrettyPrint ( Doc )
28--
16--
29-- For each selectable table in your database, you should provide a
17-- For each selectable table in your database, you should provide a
30-- @TableSchema@ in order to interact with the table via Rel8.
18-- @TableSchema@ in order to interact with the table via Rel8.
31−type TableSchema :: Type -> Type
32data TableSchema names = TableSchema
19data TableSchema names = TableSchema
33 { name :: String
20 { name :: String
34 -- ^ The name of the table.
21 -- ^ The name of the table.
@@ -40,10 +27,3 @@ data TableSchema names = TableSchema
40 -- data type here, parameterized by the 'Rel8.ColumnSchema.ColumnSchema' functor.
27 -- data type here, parameterized by the 'Rel8.ColumnSchema.ColumnSchema' functor.
41 }
28 }
42 deriving stock Functor
29 deriving stock Functor
43−
44−
45−ppTable :: TableSchema a -> Doc
46−ppTable TableSchema {name, schema} = Opaleye.ppTable Opaleye.SqlTable
47− { sqlTableSchemaName = schema
48− , sqlTableName = name
49− }
src/Rel8/Statement/Delete.hs+48−35
@@ -1,37 +1,40 @@
1{-# language DuplicateRecordFields #-}
1{-# language DuplicateRecordFields #-}
2{-# language GADTs #-}
2{-# language GADTs #-}
3{-# language NamedFieldPuns #-}
3{-# language NamedFieldPuns #-}
4−{-# language RankNTypes #-}
4+{-# language ScopedTypeVariables #-}
5−{-# language RecordWildCards #-}
6{-# language StandaloneKindSignatures #-}
5{-# language StandaloneKindSignatures #-}
7−{-# language StrictData #-}
6+{-# language TypeApplications #-}
8
7
9module Rel8.Statement.Delete
8module Rel8.Statement.Delete
10 ( Delete(..)
9 ( Delete(..)
11 , delete
10 , delete
12− , ppDelete
13 )
11 )
14where
12where
15
13
16-- base
14-- base
15+import Control.Exception ( throwIO )
17import Data.Kind ( Type )
16import Data.Kind ( Type )
18import Prelude
17import Prelude
19
18
20-- hasql
19-- hasql
20+import Hasql.Connection ( Connection )
21+import qualified Hasql.Decoders as Hasql
21import qualified Hasql.Encoders as Hasql
22import qualified Hasql.Encoders as Hasql
23+import qualified Hasql.Session as Hasql
22import qualified Hasql.Statement as Hasql
24import qualified Hasql.Statement as Hasql
23
25
24−-- pretty
26+-- opaleye
25−import Text.PrettyPrint ( Doc, (<+>), ($$), text )
27+import qualified Opaleye.Internal.Manipulation as Opaleye
26
28
27-- rel8
29-- rel8
28import Rel8.Expr ( Expr )
30import Rel8.Expr ( Expr )
29−import Rel8.Query ( Query )
31+import Rel8.Expr.Opaleye ( toColumn, toPrimExpr )
30import Rel8.Schema.Name ( Selects )
32import Rel8.Schema.Name ( Selects )
31−import Rel8.Schema.Table ( TableSchema, ppTable )
33+import Rel8.Schema.Table ( TableSchema )
32−import Rel8.Statement.Returning ( Returning, decodeReturning, ppReturning )
34+import Rel8.Statement.Returning ( Returning( NumberOfRowsAffected, Projection ) )
33−import Rel8.Statement.Using ( ppUsing )
35+import Rel8.Table ( fromColumns, toColumns )
34−import Rel8.Statement.Where ( ppWhere )
36+import Rel8.Table.Opaleye ( castTable, table, unpackspec )
37+import Rel8.Table.Serialize ( Serializable, parse )
35
38
36-- text
39-- text
37import qualified Data.Text as Text
40import qualified Data.Text as Text
@@ -44,10 +47,7 @@ data Delete a where
44 Delete :: Selects names exprs =>
47 Delete :: Selects names exprs =>
45 { from :: TableSchema names
48 { from :: TableSchema names
46 -- ^ Which table to delete from.
49 -- ^ Which table to delete from.
47− , using :: Query using
48− -- ^ @USING@ clause — this can be used to join against other tables,
49− -- and its results can be referenced in the @WHERE@ clause
50− , deleteWhere :: using -> exprs -> Expr Bool
50+ , deleteWhere :: exprs -> Expr Bool
51 -- ^ Which rows should be selected for deletion.
51 -- ^ Which rows should be selected for deletion.
52 , returning :: Returning names a
52 , returning :: Returning names a
53 -- ^ What to return from the @DELETE@ statement.
53 -- ^ What to return from the @DELETE@ statement.
@@ -55,25 +55,38 @@ data Delete a where
55 -> Delete a
55 -> Delete a
56
56
57
57
58−ppDelete :: Delete a -> Doc
58+-- | Run a @DELETE@ statement.
59−ppDelete Delete {..} = case ppUsing using of
59+delete :: Connection -> Delete a -> IO a
60− Nothing ->
60+delete c Delete {from, deleteWhere, returning} =
61− text "DELETE FROM" <+> ppTable from $$
61+ case returning of
62− text "WHERE false"
62+ NumberOfRowsAffected -> Hasql.run session c >>= either throwIO pure
63− Just (usingDoc, i) ->
63+ where
64− text "DELETE FROM" <+> ppTable from $$
64+ session = Hasql.statement () statement
65− usingDoc $$
65+ statement = Hasql.Statement bytes params decode prepare
66− ppWhere from (deleteWhere i) $$
66+ bytes = encodeUtf8 $ Text.pack sql
67− ppReturning from returning
67+ params = Hasql.noParams
68+ decode = Hasql.rowsAffected
69+ prepare = False
70+ sql = Opaleye.arrangeDeleteSql from' where'
71+ where
72+ from' = table $ toColumns <$> from
73+ where' = toColumn . toPrimExpr . deleteWhere . fromColumns
68
74
69−
75+ Projection project -> Hasql.run session c >>= either throwIO pure
70−-- | Run a 'Delete' statement.
76+ where
71−delete :: Delete a -> Hasql.Statement () a
77+ session = Hasql.statement () statement
72−delete d@Delete {returning} = Hasql.Statement bytes params decode prepare
78+ statement = Hasql.Statement bytes params decode prepare
79+ bytes = encodeUtf8 $ Text.pack sql
80+ params = Hasql.noParams
81+ decode = decoder project
82+ prepare = False
83+ sql =
84+ Opaleye.arrangeDeleteReturningSql unpackspec from' where' project'
85+ where
86+ from' = table $ toColumns <$> from
87+ where' = toColumn . toPrimExpr . deleteWhere . fromColumns
88+ project' = castTable . toColumns . project . fromColumns
73 where
89 where
74− bytes = encodeUtf8 $ Text.pack sql
90+ decoder :: forall exprs projection a. Serializable projection a
75− params = Hasql.noParams
91+ => (exprs -> projection) -> Hasql.Result [a]
76− decode = decodeReturning returning
92+ decoder _ = Hasql.rowList (parse @projection @a)
77− prepare = False
78− sql = show doc
79− doc = ppDelete d
src/Rel8/Statement/Insert.hs+72−43
@@ -1,59 +1,64 @@
1{-# language DuplicateRecordFields #-}
1{-# language DuplicateRecordFields #-}
2−{-# language FlexibleContexts #-}
3{-# language GADTs #-}
2{-# language GADTs #-}
4{-# language NamedFieldPuns #-}
3{-# language NamedFieldPuns #-}
5−{-# language RecordWildCards #-}
4+{-# language ScopedTypeVariables #-}
6{-# language StandaloneKindSignatures #-}
5{-# language StandaloneKindSignatures #-}
7−{-# language StrictData #-}
6+{-# language TypeApplications #-}
8
7
9module Rel8.Statement.Insert
8module Rel8.Statement.Insert
10 ( Insert(..)
9 ( Insert(..)
10+ , OnConflict(..)
11 , insert
11 , insert
12− , ppInsert
13− , ppInto
14 )
12 )
15where
13where
16
14
17-- base
15-- base
18−import Data.Foldable ( toList )
16+import Control.Exception ( throwIO )
17+import Data.List.NonEmpty ( NonEmpty( (:|) ) )
19import Data.Kind ( Type )
18import Data.Kind ( Type )
20import Prelude
19import Prelude
21
20
22-- hasql
21-- hasql
22+import Hasql.Connection ( Connection )
23+import qualified Hasql.Decoders as Hasql
23import qualified Hasql.Encoders as Hasql
24import qualified Hasql.Encoders as Hasql
25+import qualified Hasql.Session as Hasql
24import qualified Hasql.Statement as Hasql
26import qualified Hasql.Statement as Hasql
25
27
26-- opaleye
28-- opaleye
27−import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye
29+import qualified Opaleye.Internal.Manipulation as Opaleye
28−
30+import qualified Opaleye.Manipulation as Opaleye
29−-- pretty
30−import Text.PrettyPrint ( Doc, (<+>), ($$), parens, text )
31
31
32-- rel8
32-- rel8
33−import Rel8.Query ( Query )
34−import Rel8.Schema.Name ( Name, Selects, ppColumn )
33+import Rel8.Schema.Name ( Selects )
35−import Rel8.Schema.Table ( TableSchema(..), ppTable )
34+import Rel8.Schema.Table ( TableSchema )
36−import Rel8.Statement.OnConflict ( OnConflict, ppOnConflict )
35+import Rel8.Statement.Returning ( Returning( Projection, NumberOfRowsAffected ) )
37−import Rel8.Statement.Returning ( Returning, decodeReturning, ppReturning )
36+import Rel8.Table ( fromColumns, toColumns )
38−import Rel8.Statement.Select ( ppRows )
37+import Rel8.Table.Opaleye ( castTable, table, unpackspec )
39−import Rel8.Table ( Table )
40−import Rel8.Table.Name ( showNames )
38+import Rel8.Table.Serialize ( Serializable, parse )
41
39
42-- text
40-- text
43import qualified Data.Text as Text ( pack )
41import qualified Data.Text as Text ( pack )
44import Data.Text.Encoding ( encodeUtf8 )
42import Data.Text.Encoding ( encodeUtf8 )
45
43
46
44
45+-- | @OnConflict@ allows you to add an @ON CONFLICT@ clause to an @INSERT@
46+-- statement.
47+type OnConflict :: Type
48+data OnConflict
49+ = Abort -- ^ @ON CONFLICT ABORT@
50+ | DoNothing -- ^ @ON CONFLICT DO NOTHING@
51+
52+
47-- | The constituent parts of a SQL @INSERT@ statement.
53-- | The constituent parts of a SQL @INSERT@ statement.
48type Insert :: Type -> Type
54type Insert :: Type -> Type
49data Insert a where
55data Insert a where
50 Insert :: Selects names exprs =>
56 Insert :: Selects names exprs =>
51 { into :: TableSchema names
57 { into :: TableSchema names
52 -- ^ Which table to insert into.
58 -- ^ Which table to insert into.
53− , rows :: Query exprs
59+ , rows :: [exprs]
54− -- ^ The rows to insert. This can be an arbitrary query — use
60+ -- ^ The rows to insert.
55− -- 'Rel8.values' insert a static list of rows.
56− , onConflict :: OnConflict names
61+ , onConflict :: OnConflict
57 -- ^ What to do if the inserted rows conflict with data already in the
62 -- ^ What to do if the inserted rows conflict with data already in the
58 -- table.
63 -- table.
59 , returning :: Returning names a
64 , returning :: Returning names a
@@ -62,28 +67,52 @@ data Insert a where
62 -> Insert a
67 -> Insert a
63
68
64
69
65−ppInsert :: Insert a -> Doc
70+-- | Run an @INSERT@ statement
66−ppInsert Insert {..} =
71+insert :: Connection -> Insert a -> IO a
67− text "INSERT INTO" <+>
72+insert c Insert {into, rows, onConflict, returning} =
68− ppInto into $$
73+ case (rows, returning) of
69− ppRows rows $$
74+ ([], NumberOfRowsAffected) -> pure 0
70− ppOnConflict into onConflict $$
75+ ([], Projection _) -> pure []
71− ppReturning into returning
72
76
77+ (x:xs, NumberOfRowsAffected) -> Hasql.run session c >>= either throwIO pure
78+ where
79+ session = Hasql.statement () statement
80+ statement = Hasql.Statement bytes params decode prepare
81+ bytes = encodeUtf8 $ Text.pack sql
82+ params = Hasql.noParams
83+ decode = Hasql.rowsAffected
84+ prepare = False
85+ sql = Opaleye.arrangeInsertManySql into' rows' onConflict'
86+ where
87+ into' = table $ toColumns <$> into
88+ rows' = toColumns <$> x :| xs
73
89
74−ppInto :: Table Name a => TableSchema a -> Doc
90+ (x:xs, Projection project) -> Hasql.run session c >>= either throwIO pure
75−ppInto table@TableSchema {columns} =
91+ where
76− ppTable table <+>
92+ session = Hasql.statement () statement
77− parens (Opaleye.commaV ppColumn (toList (showNames columns)))
93+ statement = Hasql.Statement bytes params decode prepare
94+ bytes = encodeUtf8 $ Text.pack sql
95+ params = Hasql.noParams
96+ decode = decoder project
97+ prepare = False
98+ sql =
99+ Opaleye.arrangeInsertManyReturningSql
100+ unpackspec
101+ into'
102+ rows'
103+ project'
104+ onConflict'
105+ where
106+ into' = table $ toColumns <$> into
107+ rows' = toColumns <$> x :| xs
108+ project' = castTable . toColumns . project . fromColumns
78
109
79−
80−-- | Run an 'Insert' statement.
81−insert :: Insert a -> Hasql.Statement () a
82−insert i@Insert {returning} = Hasql.Statement bytes params decode prepare
83 where
110 where
84− bytes = encodeUtf8 $ Text.pack sql
111+ onConflict' =
85− params = Hasql.noParams
112+ case onConflict of
86− decode = decodeReturning returning
113+ DoNothing -> Just Opaleye.DoNothing
87− prepare = False
114+ Abort -> Nothing
88− sql = show doc
115+
89− doc = ppInsert i
116+ decoder :: forall exprs projection a. Serializable projection a
117+ => (exprs -> projection) -> Hasql.Result [a]
118+ decoder _ = Hasql.rowList (parse @projection @a)
src/Rel8/Statement/OnConflict.hsdeleted−106
@@ -1,106 +0,0 @@
1−{-# language DuplicateRecordFields #-}
2−{-# language FlexibleContexts #-}
3−{-# language GADTs #-}
4−{-# language LambdaCase #-}
5−{-# language NamedFieldPuns #-}
6−{-# language RecordWildCards #-}
7−{-# language StandaloneKindSignatures #-}
8−{-# language StrictData #-}
9−
10−module Rel8.Statement.OnConflict
11− ( OnConflict(..)
12− , Upsert(..)
13− , ppOnConflict
14− )
15−where
16−
17−-- base
18−import Data.Foldable ( toList )
19−import Data.Kind ( Type )
20−import Prelude
21−
22−-- opaleye
23−import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye
24−
25−-- pretty
26−import Text.PrettyPrint ( Doc, (<+>), ($$), parens, text )
27−
28−-- rel8
29−import Rel8.Expr ( Expr )
30−import Rel8.Schema.Name ( Name, Selects, ppColumn )
31−import Rel8.Schema.Table ( TableSchema(..) )
32−import Rel8.Statement.Set ( ppSet )
33−import Rel8.Statement.Where ( ppWhere )
34−import Rel8.Table ( Table, toColumns )
35−import Rel8.Table.Cols ( Cols( Cols ) )
36−import Rel8.Table.Name ( showNames )
37−import Rel8.Table.Opaleye ( attributes )
38−import Rel8.Table.Projection ( Projecting, Projection, apply )
39−
40−
41−-- | 'OnConflict' represents the @ON CONFLICT@ clause of an @INSERT@
42−-- statement. This specifies what ought to happen when one or more of the
43−-- rows proposed for insertion conflict with an existing row in the table.
44−type OnConflict :: Type -> Type
45−data OnConflict names
46− = Abort
47− -- ^ Abort the transaction if there are conflicting rows (Postgres' default)
48− | DoNothing
49− -- ^ @ON CONFLICT DO NOTHING@
50− | DoUpdate (Upsert names)
51− -- ^ @ON CONFLICT DO UPDATE@
52−
53−
54−-- | The @ON CONFLICT (...) DO UPDATE@ clause of an @INSERT@ statement, also
55−-- known as \"upsert\".
56−--
57−-- When an existing row conflicts with a row proposed for insertion,
58−-- @ON CONFLICT DO UPDATE@ allows you to instead update this existing row. The
59−-- conflicting row proposed for insertion is then \"excluded\", but its values
60−-- can still be referenced from the @SET@ and @WHERE@ clauses of the @UPDATE@
61−-- statement.
62−--
63−-- Upsert in Postgres requires an explicit set of \"conflict targets\" — the
64−-- set of columns comprising the @UNIQUE@ index from conflicts with which we
65−-- would like to recover.
66−type Upsert :: Type -> Type
67−data Upsert names where
68− Upsert :: (Selects names exprs, Projecting names index, excluded ~ exprs) =>
69− { index :: Projection names index
70− -- ^ The set of conflict targets, projected from the set of columns for
71− -- the whole table
72− , set :: excluded -> exprs -> exprs
73− -- ^ How to update each selected row.
74− , updateWhere :: excluded -> exprs -> Expr Bool
75− -- ^ Which rows to select for update.
76− }
77− -> Upsert names
78−
79−
80−ppOnConflict :: TableSchema names -> OnConflict names -> Doc
81−ppOnConflict schema = \case
82− Abort -> mempty
83− DoNothing -> text "ON CONFLICT DO NOTHING"
84− DoUpdate upsert -> ppUpsert schema upsert
85−
86−
87−ppUpsert :: TableSchema names -> Upsert names -> Doc
88−ppUpsert schema@TableSchema {columns} Upsert {..} =
89− text "ON CONFLICT" <+>
90− ppIndex schema index <+>
91− text "DO UPDATE" $$
92− ppSet schema (set excluded) $$
93− ppWhere schema (updateWhere excluded)
94− where
95− excluded = attributes TableSchema
96− { schema = Nothing
97− , name = "excluded"
98− , columns
99− }
100−
101−
102−ppIndex :: (Table Name names, Projecting names index)
103− => TableSchema names -> Projection names index -> Doc
104−ppIndex TableSchema {columns} index =
105− parens $ Opaleye.commaV ppColumn $ toList $
106− showNames $ Cols $ apply index $ toColumns columns
src/Rel8/Statement/Returning.hs+10−114
@@ -1,133 +1,29 @@
1{-# language GADTs #-}
1{-# language GADTs #-}
2−{-# language LambdaCase #-}
3−{-# language NamedFieldPuns #-}
4−{-# language RankNTypes #-}
5−{-# language ScopedTypeVariables #-}
6{-# language StandaloneKindSignatures #-}
2{-# language StandaloneKindSignatures #-}
7−{-# language StrictData #-}
8−{-# language TypeApplications #-}
9
3
10module Rel8.Statement.Returning
4module Rel8.Statement.Returning
11− ( Returning( NumberOfRowsAffected, Projection )
5+ ( Returning(..)
12− , decodeReturning
13− , ppReturning
14 )
6 )
15where
7where
16
8
17-- base
9-- base
18−import Control.Applicative ( liftA2 )
19−import Data.Foldable ( toList )
20import Data.Int ( Int64 )
10import Data.Int ( Int64 )
21import Data.Kind ( Type )
11import Data.Kind ( Type )
22−import Data.List.NonEmpty ( NonEmpty )
23−import Prelude
12+import Prelude ()
24−
25−-- hasql
26−import qualified Hasql.Decoders as Hasql
27−
28−-- opaleye
29−import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
30−import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye
31−import qualified Opaleye.Internal.Sql as Opaleye
32−
33−-- pretty
34−import Text.PrettyPrint ( Doc, (<+>), text )
35
13
36-- rel8
14-- rel8
37import Rel8.Schema.Name ( Selects )
15import Rel8.Schema.Name ( Selects )
38−import Rel8.Schema.Table ( TableSchema(..) )
39−import Rel8.Table.Opaleye ( castTable, exprs, view )
40−import Rel8.Table.Serialize ( Serializable, parse )
16+import Rel8.Table.Serialize ( Serializable )
41
17
42−-- semigropuoids
43−import Data.Functor.Apply ( Apply, (<.>) )
44
18
45−
46−-- | 'Rel8.Insert', 'Rel8.Update' and 'Rel8.Delete' all support returning either
19+-- | @INSERT@, @UPDATE@ and @DELETE@ all support returning either the number of
47−-- the number of rows affected, or the actual rows modified.
20+-- rows affected, or the actual rows modified. 'Projection' allows you to
21+-- project out of these returned rows, which can be useful if you want to log
22+-- exactly which rows were deleted, or to view a generated id (for example, if
23+-- using a column with an autoincrementing counter as a default value).
48type Returning :: Type -> Type -> Type
24type Returning :: Type -> Type -> Type
49data Returning names a where
25data Returning names a where
50− Pure :: a -> Returning names a
51− Ap :: Returning names (a -> b) -> Returning names a -> Returning names b
52−
53− -- | Return the number of rows affected.
54 NumberOfRowsAffected :: Returning names Int64
26 NumberOfRowsAffected :: Returning names Int64
55−
56− -- | 'Projection' allows you to project out of the affected rows, which can
57− -- be useful if you want to log exactly which rows were deleted, or to view
58− -- a generated id (for example, if using a column with an autoincrementing
59− -- counter via 'Rel8.nextval').
60− Projection :: (Selects names exprs, Serializable returning a)
27+ Projection :: (Selects names exprs, Serializable projection a)
61− => (exprs -> returning)
28+ => (exprs -> projection)
62 -> Returning names [a]
29 -> Returning names [a]
63−
64−
65−instance Functor (Returning names) where
66− fmap f = \case
67− Pure a -> Pure (f a)
68− Ap g a -> Ap (fmap (f .) g) a
69− m -> Ap (Pure f) m
70−
71−
72−instance Apply (Returning names) where
73− (<.>) = Ap
74−
75−
76−instance Applicative (Returning names) where
77− pure = Pure
78− (<*>) = Ap
79−
80−
81−projections :: ()
82− => TableSchema names -> Returning names a -> Maybe (NonEmpty Opaleye.PrimExpr)
83−projections schema@TableSchema {columns} = \case
84− Pure _ -> Nothing
85− Ap f a -> projections schema f <> projections schema a
86− NumberOfRowsAffected -> Nothing
87− Projection f -> Just (exprs (castTable (f (view columns))))
88−
89−
90−runReturning :: ()
91− => ((Int64 -> a) -> r)
92− -> (forall x. Hasql.Row x -> ([x] -> a) -> r)
93− -> Returning names a
94− -> r
95−runReturning rowCount rowList = \case
96− Pure a -> rowCount (const a)
97− Ap fs as ->
98− runReturning
99− (\withCount ->
100− runReturning
101− (\withCount' -> rowCount (withCount <*> withCount'))
102− (\decoder -> rowList decoder . liftA2 withCount length64)
103− as)
104− (\decoder withRows ->
105− runReturning
106− (\withCount -> rowList decoder $ withRows <*> withCount . length64)
107− (\decoder' withRows' ->
108− rowList (liftA2 (,) decoder decoder') $
109− withRows <$> fmap fst <*> withRows' . fmap snd)
110− as)
111− fs
112− NumberOfRowsAffected -> rowCount id
113− Projection (_ :: exprs -> returning) -> rowList decoder' id
114− where
115− decoder' = parse @returning
116− where
117− length64 :: Foldable f => f x -> Int64
118− length64 = fromIntegral . length
119−
120−
121−decodeReturning :: Returning names a -> Hasql.Result a
122−decodeReturning = runReturning
123− (<$> Hasql.rowsAffected)
124− (\decoder withRows -> withRows <$> Hasql.rowList decoder)
125−
126−
127−ppReturning :: TableSchema names -> Returning names a -> Doc
128−ppReturning schema returning = case projections schema returning of
129− Nothing -> mempty
130− Just columns ->
131− text "RETURNING" <+> Opaleye.commaV Opaleye.ppSqlExpr (toList sqlExprs)
132− where
133− sqlExprs = Opaleye.sqlExpr <$> columns
src/Rel8/Statement/SQL.hsdeleted−29
@@ -1,29 +0,0 @@
1−module Rel8.Statement.SQL
2− ( showDelete
3− , showInsert
4− , showUpdate
5− )
6−where
7−
8−-- base
9−import Prelude
10−
11−-- rel8
12−import Rel8.Statement.Delete ( Delete, ppDelete )
13−import Rel8.Statement.Insert ( Insert, ppInsert )
14−import Rel8.Statement.Update ( Update, ppUpdate )
15−
16−
17−-- | Convert a 'Delete' to a 'String' containing a @DELETE@ statement.
18−showDelete :: Delete a -> String
19−showDelete = show . ppDelete
20−
21−
22−-- | Convert an 'Insert' to a 'String' containing an @INSERT@ statement.
23−showInsert :: Insert a -> String
24−showInsert = show . ppInsert
25−
26−
27−-- | Convert an 'Update' to a 'String' containing an @UPDATE@ statement.
28−showUpdate :: Update a -> String
29−showUpdate = show . ppUpdate
src/Rel8/Statement/Select.hs+35−120
@@ -1,147 +1,62 @@
1−{-# language DeriveTraversable #-}
2−{-# language DerivingStrategies #-}
3−{-# language FlexibleContexts #-}
4{-# language MonoLocalBinds #-}
1{-# language MonoLocalBinds #-}
5{-# language ScopedTypeVariables #-}
2{-# language ScopedTypeVariables #-}
6−{-# language StandaloneKindSignatures #-}
7{-# language TypeApplications #-}
3{-# language TypeApplications #-}
8
4
9module Rel8.Statement.Select
5module Rel8.Statement.Select
10 ( select
6 ( select
11− , ppSelect
7+ , selectWithNames
12−
13− , Optimized(..)
14− , ppPrimSelect
15− , ppRows
16 )
8 )
17where
9where
18
10
19-- base
11-- base
20−import Data.Foldable ( toList )
12+import Control.Exception ( throwIO )
21−import Data.Kind ( Type )
22−import Data.Void ( Void )
23−import Prelude hiding ( undefined )
13+import Prelude
24
14
25-- hasql
15-- hasql
16+import Hasql.Connection ( Connection )
26import qualified Hasql.Decoders as Hasql
17import qualified Hasql.Decoders as Hasql
27import qualified Hasql.Encoders as Hasql
18import qualified Hasql.Encoders as Hasql
19+import qualified Hasql.Session as Hasql
28import qualified Hasql.Statement as Hasql
20import qualified Hasql.Statement as Hasql
29
21
30−-- opaleye
31−import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
32−import qualified Opaleye.Internal.HaskellDB.Sql as Opaleye
33−import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye
34−import qualified Opaleye.Internal.PrimQuery as Opaleye
35−import qualified Opaleye.Internal.Print as Opaleye
36−import qualified Opaleye.Internal.Optimize as Opaleye
37−import qualified Opaleye.Internal.QueryArr as Opaleye hiding ( Select )
38−import qualified Opaleye.Internal.Sql as Opaleye hiding ( Values )
39−import qualified Opaleye.Internal.Tag as Opaleye
40−
41−-- pretty
42−import Text.PrettyPrint ( Doc )
43−
44-- rel8
22-- rel8
45−import Rel8.Expr ( Expr )
46−import Rel8.Expr.Bool ( false )
47−import Rel8.Expr.Opaleye ( toPrimExpr )
48import Rel8.Query ( Query )
23import Rel8.Query ( Query )
49−import Rel8.Query.Opaleye ( toOpaleye )
24+import Rel8.Query.SQL ( sqlForQuery, sqlForQueryWithNames )
50import Rel8.Schema.Name ( Selects )
25import Rel8.Schema.Name ( Selects )
51−import Rel8.Table ( Table )
52−import Rel8.Table.Cols ( toCols )
53−import Rel8.Table.Name ( namesFromLabels )
54−import Rel8.Table.Opaleye ( castTable, exprsWithNames )
55−import qualified Rel8.Table.Opaleye as T
56import Rel8.Table.Serialize ( Serializable, parse )
26import Rel8.Table.Serialize ( Serializable, parse )
57−import Rel8.Table.Undefined ( undefined )
58
27
59-- text
28-- text
60import qualified Data.Text as Text
29import qualified Data.Text as Text
61import Data.Text.Encoding ( encodeUtf8 )
30import Data.Text.Encoding ( encodeUtf8 )
62
31
63
32
64−-- | Run a @SELECT@ statement, returning all rows.
33+-- | Run a @SELECT@ query, returning all rows.
65select :: forall exprs a. Serializable exprs a
34select :: forall exprs a. Serializable exprs a
66− => Query exprs -> Hasql.Statement () [a]
35+ => Connection -> Query exprs -> IO [a]
67−select query = Hasql.Statement bytes params decode prepare
36+select c query = case sqlForQuery query of
68− where
37+ Nothing -> pure []
69− bytes = encodeUtf8 (Text.pack sql)
38+ Just sql -> Hasql.run session c >>= either throwIO pure
70− params = Hasql.noParams
39+ where
71− decode = Hasql.rowList (parse @exprs @a)
40+ session = Hasql.statement () statement
72− prepare = False
41+ statement = Hasql.Statement bytes params decode prepare
73− sql = show doc
42+ bytes = encodeUtf8 (Text.pack sql)
74− doc = ppSelect query
43+ params = Hasql.noParams
75−
44+ decode = Hasql.rowList (parse @exprs @a)
76−
45+ prepare = False
77−ppSelect :: Table Expr a => Query a -> Doc
46+
78−ppSelect query =
47+
79− Opaleye.ppSql $ primSelectWith names (toCols exprs') primQuery'
48+selectWithNames :: forall exprs a names.
80− where
81− names = namesFromLabels
82− (exprs, primQuery, _) =
83− Opaleye.runSimpleQueryArrStart (toOpaleye query) ()
84− (exprs', primQuery') = case optimize primQuery of
85− Empty -> (undefined, Opaleye.Product (pure (pure Opaleye.Unit)) never)
86− Unit -> (exprs, Opaleye.Unit)
87− Optimized pq -> (exprs, pq)
88− never = pure (toPrimExpr false)
89−
90−
91−ppRows :: Table Expr a => Query a -> Doc
92−ppRows query = case optimize primQuery of
93− -- Special case VALUES because we can't use DEFAULT inside a SELECT
94− Optimized (Opaleye.Values symbols rows)
95− | eqSymbols symbols (toList (T.exprs a)) ->
96− Opaleye.ppValues_ (map Opaleye.sqlExpr <$> toList rows)
97− _ -> ppSelect query
98− where
99− (a, primQuery, _) = Opaleye.runSimpleQueryArrStart (toOpaleye query) ()
100−
101− eqSymbols (symbol : symbols) (Opaleye.AttrExpr symbol' : exprs)
102− | eqSymbol symbol symbol' = eqSymbols symbols exprs
103− | otherwise = False
104− eqSymbols [] [] = True
105− eqSymbols _ _ = False
106−
107− eqSymbol
108− (Opaleye.Symbol name (Opaleye.UnsafeTag tag))
109− (Opaleye.Symbol name' (Opaleye.UnsafeTag tag'))
110− = name == name' && tag == tag'
111−
112−
113−ppPrimSelect :: Query a -> (Optimized Doc, a)
114−ppPrimSelect query =
115− (Opaleye.ppSql . primSelect <$> optimize primQuery, a)
116− where
117− (a, primQuery, _) = Opaleye.runSimpleQueryArrStart (toOpaleye query) ()
118−
119−
120−type Optimized :: Type -> Type
121−data Optimized a = Empty | Unit | Optimized a
122− deriving stock (Functor, Foldable, Traversable, Show)
123−
124−
125−optimize :: Opaleye.PrimQuery' a -> Optimized (Opaleye.PrimQuery' Void)
126−optimize query = case Opaleye.removeEmpty (Opaleye.optimize query) of
127− Nothing -> Empty
128− Just Opaleye.Unit -> Unit
129− Just query' -> Optimized query'
130−
131−
132−primSelect :: Opaleye.PrimQuery' Void -> Opaleye.Select
133−primSelect = Opaleye.foldPrimQuery Opaleye.sqlQueryGenerator
134−
135−
136−primSelectWith :: Selects names exprs
49+ ( Selects names exprs
137− => names -> exprs -> Opaleye.PrimQuery' Void -> Opaleye.Select
50+ , Serializable exprs a
138−primSelectWith names exprs query =
51+ )
139− Opaleye.SelectFrom $ Opaleye.newSelect
52+ => Connection -> names -> Query exprs -> IO [a]
140− { Opaleye.attrs = Opaleye.SelectAttrs attrs
53+selectWithNames c names query = case sqlForQueryWithNames names query of
141− , Opaleye.tables = Opaleye.oneTable (primSelect query)
54+ Nothing -> pure []
142− }
55+ Just sql -> Hasql.run session c >>= either throwIO pure
143− where
56+ where
144− attrs = makeAttr <$> exprsWithNames names (castTable exprs)
57+ session = Hasql.statement () statement
145− where
58+ statement = Hasql.Statement bytes params decode prepare
146− makeAttr (label, expr) =
59+ bytes = encodeUtf8 (Text.pack sql)
147− (Opaleye.sqlExpr expr, Just (Opaleye.SqlColumn label))
60+ params = Hasql.noParams
61+ decode = Hasql.rowList (parse @exprs @a)
62+ prepare = False
src/Rel8/Statement/Set.hsdeleted−33
@@ -1,33 +0,0 @@
1−{-# language MonoLocalBinds #-}
2−{-# language NamedFieldPuns #-}
3−
4−module Rel8.Statement.Set
5− ( ppSet
6− )
7−where
8−
9−-- base
10−import Data.Foldable ( toList )
11−import Prelude ()
12−
13−-- opaleye
14−import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye
15−import qualified Opaleye.Internal.Sql as Opaleye
16−
17−-- pretty
18−import Text.PrettyPrint ( Doc, (<+>), equals, text )
19−
20−-- rel8
21−import Rel8.Schema.Name ( Selects, ppColumn )
22−import Rel8.Schema.Table ( TableSchema(..) )
23−import Rel8.Table.Opaleye ( attributes, exprsWithNames )
24−
25−
26−ppSet :: Selects names exprs
27− => TableSchema names -> (exprs -> exprs) -> Doc
28−ppSet schema@TableSchema {columns} f =
29− text "SET" <+> Opaleye.commaV ppAssign (toList assigns)
30− where
31− assigns = exprsWithNames columns (f (attributes schema))
32− ppAssign (column, expr) =
33− ppColumn column <+> equals <+> Opaleye.ppSqlExpr (Opaleye.sqlExpr expr)
src/Rel8/Statement/Update.hs+56−38
@@ -1,37 +1,39 @@
1−{-# language DuplicateRecordFields #-}
2{-# language GADTs #-}
1{-# language GADTs #-}
3{-# language NamedFieldPuns #-}
2{-# language NamedFieldPuns #-}
4−{-# language RecordWildCards #-}
3+{-# language ScopedTypeVariables #-}
5{-# language StandaloneKindSignatures #-}
4{-# language StandaloneKindSignatures #-}
6−{-# language StrictData #-}
5+{-# language TypeApplications #-}
7
6
8module Rel8.Statement.Update
7module Rel8.Statement.Update
9 ( Update(..)
8 ( Update(..)
10 , update
9 , update
11− , ppUpdate
12 )
10 )
13where
11where
14
12
15-- base
13-- base
14+import Control.Exception ( throwIO )
16import Data.Kind ( Type )
15import Data.Kind ( Type )
17import Prelude
16import Prelude
18
17
19-- hasql
18-- hasql
19+import Hasql.Connection ( Connection )
20+import qualified Hasql.Decoders as Hasql
20import qualified Hasql.Encoders as Hasql
21import qualified Hasql.Encoders as Hasql
22+import qualified Hasql.Session as Hasql
21import qualified Hasql.Statement as Hasql
23import qualified Hasql.Statement as Hasql
22
24
23−-- pretty
25+-- opaleye
24−import Text.PrettyPrint ( Doc, (<+>), ($$), text )
26+import qualified Opaleye.Internal.Manipulation as Opaleye
25
27
26-- rel8
28-- rel8
27import Rel8.Expr ( Expr )
29import Rel8.Expr ( Expr )
28−import Rel8.Query ( Query )
30+import Rel8.Expr.Opaleye ( toColumn, toPrimExpr )
29import Rel8.Schema.Name ( Selects )
31import Rel8.Schema.Name ( Selects )
30−import Rel8.Schema.Table ( TableSchema(..), ppTable )
32+import Rel8.Schema.Table ( TableSchema )
31−import Rel8.Statement.Returning ( Returning, decodeReturning, ppReturning )
33+import Rel8.Statement.Returning ( Returning( Projection, NumberOfRowsAffected ) )
32−import Rel8.Statement.Set ( ppSet )
34+import Rel8.Table ( fromColumns, toColumns )
33−import Rel8.Statement.Using ( ppFrom )
35+import Rel8.Table.Opaleye ( castTable, table, unpackspec )
34−import Rel8.Statement.Where ( ppWhere )
36+import Rel8.Table.Serialize ( Serializable, parse )
35
37
36-- text
38-- text
37import qualified Data.Text as Text
39import qualified Data.Text as Text
@@ -44,12 +46,9 @@ data Update a where
44 Update :: Selects names exprs =>
46 Update :: Selects names exprs =>
45 { target :: TableSchema names
47 { target :: TableSchema names
46 -- ^ Which table to update.
48 -- ^ Which table to update.
47− , from :: Query from
48− -- ^ @FROM@ clause — this can be used to join against other tables,
49− -- and its results can be referenced in the @SET@ and @WHERE@ clauses.
50− , set :: from -> exprs -> exprs
49+ , set :: exprs -> exprs
51 -- ^ How to update each selected row.
50 -- ^ How to update each selected row.
52− , updateWhere :: from -> exprs -> Expr Bool
51+ , updateWhere :: exprs -> Expr Bool
53 -- ^ Which rows to select for update.
52 -- ^ Which rows to select for update.
54 , returning :: Returning names a
53 , returning :: Returning names a
55 -- ^ What to return from the @UPDATE@ statement.
54 -- ^ What to return from the @UPDATE@ statement.
@@ -57,27 +56,46 @@ data Update a where
57 -> Update a
56 -> Update a
58
57
59
58
60−ppUpdate :: Update a -> Doc
59+-- | Run an @UPDATE@ statement.
61−ppUpdate Update {..} = case ppFrom from of
60+update :: Connection -> Update a -> IO a
62− Nothing ->
61+update c Update {target, set, updateWhere, returning} =
63− text "UPDATE" <+> ppTable target $$
62+ case returning of
64− ppSet target id $$
63+ NumberOfRowsAffected -> Hasql.run session c >>= either throwIO pure
65− text "WHERE false"
64+ where
66− Just (fromDoc, i) ->
65+ session = Hasql.statement () statement
67− text "UPDATE" <+> ppTable target $$
66+ statement = Hasql.Statement bytes params decode prepare
68− ppSet target (set i) $$
67+ bytes = encodeUtf8 $ Text.pack sql
69− fromDoc $$
68+ params = Hasql.noParams
70− ppWhere target (updateWhere i) $$
69+ decode = Hasql.rowsAffected
71− ppReturning target returning
70+ prepare = False
71+ sql = Opaleye.arrangeUpdateSql target' set' where'
72+ where
73+ target' = table $ toColumns <$> target
74+ set' = toColumns . set . fromColumns
75+ where' = toColumn . toPrimExpr . updateWhere . fromColumns
72
76
77+ Projection project -> Hasql.run session c >>= either throwIO pure
78+ where
79+ session = Hasql.statement () statement
80+ statement = Hasql.Statement bytes params decode prepare
81+ bytes = encodeUtf8 $ Text.pack sql
82+ params = Hasql.noParams
83+ decode = decoder project
84+ prepare = False
85+ sql =
86+ Opaleye.arrangeUpdateReturningSql
87+ unpackspec
88+ target'
89+ set'
90+ where'
91+ project'
92+ where
93+ target' = table $ toColumns <$> target
94+ set' = toColumns . set . fromColumns
95+ where' = toColumn . toPrimExpr . updateWhere . fromColumns
96+ project' = castTable . toColumns . project . fromColumns
73
97
74−-- | Run an @UPDATE@ statement.
75−update :: Update a -> Hasql.Statement () a
76−update u@Update {returning} = Hasql.Statement bytes params decode prepare
77 where
98 where
78− bytes = encodeUtf8 $ Text.pack sql
99+ decoder :: forall exprs projection a. Serializable projection a
79− params = Hasql.noParams
100+ => (exprs -> projection) -> Hasql.Result [a]
80− decode = decodeReturning returning
101+ decoder _ = Hasql.rowList (parse @projection @a)
81− prepare = False
82− sql = show doc
83− doc = ppUpdate u
src/Rel8/Statement/Using.hsdeleted−36
@@ -1,36 +0,0 @@
1−module Rel8.Statement.Using
2− ( ppFrom
3− , ppUsing
4− )
5−where
6−
7−-- base
8−import Prelude
9−
10−-- pretty
11−import Text.PrettyPrint ( Doc, (<+>), parens, text )
12−
13−-- rel8
14−import Rel8.Query ( Query )
15−import Rel8.Schema.Table ( TableSchema(..), ppTable )
16−import Rel8.Statement.Select ( Optimized(..), ppPrimSelect )
17−
18−
19−ppFrom :: Query a -> Maybe (Doc, a)
20−ppFrom = ppJoin "FROM"
21−
22−
23−ppUsing :: Query a -> Maybe (Doc, a)
24−ppUsing = ppJoin "USING"
25−
26−
27−ppJoin :: String -> Query a -> Maybe (Doc, a)
28−ppJoin clause join = do
29− doc <- case ofrom of
30− Empty -> Nothing
31− Unit -> Just mempty
32− Optimized doc -> Just $ text clause <+> parens doc <+> ppTable alias
33− pure (doc, a)
34− where
35− alias = TableSchema {name = "T1", schema = Nothing, columns = ()}
36− (ofrom, a) = ppPrimSelect join
src/Rel8/Statement/View.hs+28−43
@@ -3,76 +3,61 @@
3
3
4module Rel8.Statement.View
4module Rel8.Statement.View
5 ( createView
5 ( createView
6− , createOrReplaceView
7 )
6 )
8where
7where
9
8
10-- base
9-- base
10+import Control.Exception ( throwIO )
11+import Control.Monad ( (>=>) )
12+import Data.Foldable ( fold )
13+import Data.Maybe ( fromMaybe )
11import Prelude
14import Prelude
12
15
13-- hasql
16-- hasql
17+import Hasql.Connection ( Connection )
14import qualified Hasql.Decoders as Hasql
18import qualified Hasql.Decoders as Hasql
15import qualified Hasql.Encoders as Hasql
19import qualified Hasql.Encoders as Hasql
20+import qualified Hasql.Session as Hasql
16import qualified Hasql.Statement as Hasql
21import qualified Hasql.Statement as Hasql
17
22
18-- rel8
23-- rel8
19import Rel8.Query ( Query )
24import Rel8.Query ( Query )
25+import Rel8.Query.SQL ( sqlForQueryWithNames )
20import Rel8.Schema.Name ( Selects )
26import Rel8.Schema.Name ( Selects )
21−import Rel8.Schema.Table ( TableSchema )
27+import Rel8.Schema.Table ( TableSchema( TableSchema ) )
22−import Rel8.Statement.Insert ( ppInto )
28+import Rel8.Table.Alternative ( emptyTable )
23−import Rel8.Statement.Select ( ppSelect )
24−
25−-- pretty
26−import Text.PrettyPrint ( Doc, (<+>), ($$), text )
27
29
28-- text
30-- text
29import qualified Data.Text as Text
31import qualified Data.Text as Text
30import Data.Text.Encoding ( encodeUtf8 )
32import Data.Text.Encoding ( encodeUtf8 )
31
33
32
34
33−data CreateView = Create | CreateOrReplace
34−
35−
36-- | Given a 'TableSchema' and 'Query', @createView@ runs a @CREATE VIEW@
35-- | Given a 'TableSchema' and 'Query', @createView@ runs a @CREATE VIEW@
37-- statement that will save the given query as a view. This can be useful if
36-- statement that will save the given query as a view. This can be useful if
38-- you want to share Rel8 queries with other applications.
37-- you want to share Rel8 queries with other applications.
39createView :: Selects names exprs
38createView :: Selects names exprs
40− => TableSchema names -> Query exprs -> Hasql.Statement () ()
39+ => TableSchema names -> Query exprs -> Connection -> IO ()
41−createView =
40+createView (TableSchema name mschema names) query =
42− createViewGeneric Create
41+ Hasql.run session >=> either throwIO pure
43−
44−
45−-- | Given a 'TableSchema' and 'Query', @createOrReplaceView@ runs a
46−-- @CREATE OR REPLACE VIEW@ statement that will save the given query
47−-- as a view, replacing the current view definition if it exists and
48−-- adheres to the restrictions in place for replacing a view in
49−-- PostgreSQL.
50−createOrReplaceView :: Selects names exprs
51− => TableSchema names -> Query exprs -> Hasql.Statement () ()
52−createOrReplaceView =
53− createViewGeneric CreateOrReplace
54−
55−
56−createViewGeneric :: Selects names exprs
57− => CreateView -> TableSchema names -> Query exprs -> Hasql.Statement () ()
58−createViewGeneric replace schema query =
59− Hasql.Statement bytes params decode prepare
60 where
42 where
43+ session = Hasql.statement () statement
44+ statement = Hasql.Statement bytes params decode prepare
61 bytes = encodeUtf8 (Text.pack sql)
45 bytes = encodeUtf8 (Text.pack sql)
62 params = Hasql.noParams
46 params = Hasql.noParams
63 decode = Hasql.noResult
47 decode = Hasql.noResult
64 prepare = False
48 prepare = False
65− sql = show doc
49+ sql = "CREATE VIEW " <> title <> " AS " <> select
66− doc = ppCreateView schema query replace
50+ where
67−
51+ title = case mschema of
68−
52+ Nothing -> quote name
69−ppCreateView :: Selects names exprs
53+ Just schema -> quote schema <> "." <> quote name
70− => TableSchema names -> Query exprs -> CreateView -> Doc
54+ select = fromMaybe fallback $ sqlForQueryWithNames names query
71−ppCreateView schema query replace =
55+ where
72− createOrReplace replace <+>
56+ fallback = fold $ sqlForQueryWithNames names emptyTable
73− ppInto schema $$
57+
74− text "AS" <+>
58+
75− ppSelect query
59+quote :: String -> String
60+quote string = "\"" <> concatMap go string <> "\""
76 where
61 where
77− createOrReplace Create = text "CREATE VIEW"
62+ go '"' = "\"\""
78− createOrReplace CreateOrReplace = text "CREATE OR REPLACE VIEW"
63+ go c = [c]
src/Rel8/Statement/Where.hsdeleted−31
@@ -1,31 +0,0 @@
1−{-# language MonoLocalBinds #-}
2−
3−module Rel8.Statement.Where
4− ( ppWhere
5− )
6−where
7−
8−-- base
9−import Prelude
10−
11−-- opaleye
12−import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye
13−import qualified Opaleye.Internal.Sql as Opaleye
14−
15−-- pretty
16−import Text.PrettyPrint ( Doc, (<+>), text )
17−
18−-- rel8
19−import Rel8.Expr ( Expr )
20−import Rel8.Expr.Opaleye ( toPrimExpr )
21−import Rel8.Schema.Name ( Selects )
22−import Rel8.Schema.Table ( TableSchema )
23−import Rel8.Table.Opaleye ( attributes )
24−
25−
26−ppWhere :: Selects names exprs
27− => TableSchema names -> (exprs -> Expr Bool) -> Doc
28−ppWhere schema where_ = text "WHERE" <+> ppExpr condition
29− where
30− ppExpr = Opaleye.ppSqlExpr . Opaleye.sqlExpr . toPrimExpr
31− condition = where_ (attributes schema)
src/Rel8/Table.hs+313−83
@@ -1,47 +1,83 @@
1{-# language AllowAmbiguousTypes #-}
1{-# language AllowAmbiguousTypes #-}
2{-# language DataKinds #-}
2{-# language DataKinds #-}
3{-# language DefaultSignatures #-}
3{-# language DefaultSignatures #-}
4+{-# language DisambiguateRecordFields #-}
4{-# language FlexibleContexts #-}
5{-# language FlexibleContexts #-}
5{-# language FlexibleInstances #-}
6{-# language FlexibleInstances #-}
6{-# language FunctionalDependencies #-}
7{-# language FunctionalDependencies #-}
8+{-# language LambdaCase #-}
9+{-# language NamedFieldPuns #-}
7{-# language ScopedTypeVariables #-}
10{-# language ScopedTypeVariables #-}
8{-# language StandaloneKindSignatures #-}
11{-# language StandaloneKindSignatures #-}
9{-# language TypeApplications #-}
12{-# language TypeApplications #-}
10{-# language TypeFamilies #-}
13{-# language TypeFamilies #-}
14+{-# language TypeOperators #-}
11{-# language UndecidableInstances #-}
15{-# language UndecidableInstances #-}
12
16
13module Rel8.Table
17module Rel8.Table
14 ( Table
18 ( Table
15− ( Columns, Context, fromColumns, toColumns
19+ ( Columns, Context, toColumns, fromColumns
16− , FromExprs, fromResult, toResult
20+ , Unreify, reify, unreify, coherence, congruence
17− , Transpose
18 )
21 )
19 , Congruent
22 , Congruent
20− , TTable, TColumns, TContext, TFromExprs, TTranspose
23+ , TTable, TColumns, TContext, TUnreify
21− , TSerialize
22 )
24 )
23where
25where
24
26
25-- base
27-- base
28+import Data.Functor ( ($>) )
26import Data.Functor.Identity ( Identity( Identity ) )
29import Data.Functor.Identity ( Identity( Identity ) )
27import Data.Kind ( Constraint, Type )
30import Data.Kind ( Constraint, Type )
31+import Data.List.NonEmpty ( NonEmpty )
32+import Data.Proxy ( Proxy( Proxy ) )
33+import Data.Type.Equality ( (:~:)( Refl ) )
28import GHC.Generics ( Generic, Rep, from, to )
34import GHC.Generics ( Generic, Rep, from, to )
29import Prelude hiding ( null )
35import Prelude hiding ( null )
30
36
31-- rel8
37-- rel8
32import Rel8.FCF ( Eval, Exp )
38import Rel8.FCF ( Eval, Exp )
33−import Rel8.Generic.Map ( Map )
39+import Rel8.Kind.Algebra
40+ ( SAlgebra( SSum, SProduct )
41+ , KnownAlgebra, algebraSing
42+ )
43+import Rel8.Generic.Coherence ( GCoherent, gcoherence, gcongruence )
44+import Rel8.Generic.Map ( GMap, GMappable, gmap, gunmap )
34−import Rel8.Generic.Table.Record
45+import Rel8.Generic.Table
35− ( GTable, GColumns, GContext, gfromColumns, gtoColumns
46+ ( GGTable, GGColumns, GGContext, ggfromColumns, ggtoColumns
36− , GSerialize, gfromResult, gtoResult
47+ , GAlgebra
37 )
48 )
38import Rel8.Generic.Record ( Record(..) )
49import Rel8.Generic.Record ( Record(..) )
50+import Rel8.Generic.Reify ( ARep )
39import Rel8.Schema.HTable ( HTable )
51import Rel8.Schema.HTable ( HTable )
40−import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )
52+import Rel8.Schema.HTable.Either ( HEitherTable(..) )
53+import Rel8.Schema.HTable.Identity ( HIdentity(..), HType )
54+import Rel8.Schema.HTable.Label ( hlabel, hrelabel, hunlabel )
55+import Rel8.Schema.HTable.List ( HListTable )
56+import Rel8.Schema.HTable.Maybe ( HMaybeTable(..) )
57+import Rel8.Schema.HTable.NonEmpty ( HNonEmptyTable )
58+import Rel8.Schema.HTable.Nullify ( hnulls, hnullify, hunnullify )
59+import Rel8.Schema.HTable.These ( HTheseTable(..) )
60+import Rel8.Schema.HTable.Vectorize ( hvectorize, hunvectorize )
41import qualified Rel8.Schema.Kind as K
61import qualified Rel8.Schema.Kind as K
42import Rel8.Schema.Null ( Sql )
62import Rel8.Schema.Null ( Sql )
43−import Rel8.Schema.Result ( Result )
63+import Rel8.Schema.Reify
64+ ( Reify, Col( Reify ), hreify, hunreify
65+ , UnwrapReify
66+ , notReify
67+ )
68+import Rel8.Schema.Result
69+ ( Col( R ), Result
70+ , NotResult
71+ , null, nullifier, unnullifier
72+ , vectorizer, unvectorizer
73+ )
74+import Rel8.Schema.Spec ( KnownSpec )
44import Rel8.Type ( DBType )
75import Rel8.Type ( DBType )
76+import Rel8.Type.Tag ( EitherTag( IsLeft, IsRight ), MaybeTag( IsJust ) )
77+
78+-- these
79+import Data.These ( These( This, That, These ) )
80+import Data.These.Combinators ( justHere, justThere )
45
81
46
82
47-- | @Table@s are one of the foundational elements of Rel8, and describe data
83-- | @Table@s are one of the foundational elements of Rel8, and describe data
@@ -56,102 +92,130 @@ import Rel8.Type ( DBType )
56-- yourself, as anything that's an instance of 'Rel8.Rel8able' is always a
92-- yourself, as anything that's an instance of 'Rel8.Rel8able' is always a
57-- 'Table'.
93-- 'Table'.
58type Table :: K.Context -> Type -> Constraint
94type Table :: K.Context -> Type -> Constraint
59−class
60− ( HTable (Columns a)
61− , context ~ Context a
62− , a ~ Transpose context a
63− )
64− => Table context a | a -> context
95+class (HTable (Columns a), context ~ Context a) => Table context a | a -> context where
65− where
66 -- | The 'HTable' functor that describes the schema of this table.
96 -- | The 'HTable' functor that describes the schema of this table.
67 type Columns a :: K.HTable
97 type Columns a :: K.HTable
68
98
69 -- | The common context that all columns use as an interpretation.
99 -- | The common context that all columns use as an interpretation.
70 type Context a :: K.Context
100 type Context a :: K.Context
71
101
72− -- | The @FromExprs@ type family maps a type in the @Expr@ context to the
102+ type Unreify a :: Type
73− -- corresponding Haskell type.
74− type FromExprs a :: Type
75
103
76− type Transpose (context' :: K.Context) a :: Type
104+ toColumns :: a -> Columns a (Col context)
105+ fromColumns :: Columns a (Col context) -> a
77
106
107+ reify :: context :~: Reify ctx -> Unreify a -> a
108+ unreify :: context :~: Reify ctx -> a -> Unreify a
109+ coherence :: context :~: Reify ctx -> NotResult ctx -> Context (Unreify a) :~: ctx
110+ congruence :: context :~: Reify ctx -> NotResult ctx -> Columns a :~: Columns (Unreify a)
78
111
79− toColumns :: a -> Columns a context
80− fromColumns :: Columns a context -> a
81
112
82− fromResult :: Columns a Result -> FromExprs a
113+ type Columns a = Eval (GGColumns (GAlgebra (Rep (Record a))) TColumns (Rep (Record a)))
83− toResult :: FromExprs a -> Columns a Result
84−
85− type Columns a = GColumns TColumns (Rep (Record a))
86− type Context a = GContext TContext (Rep (Record a))
114+ type Context a = Eval (GGContext (GAlgebra (Rep (Record a))) TContext (Rep (Record a)))
87− type FromExprs a = Map TFromExprs a
115+ type Unreify a = DefaultUnreify a
88− type Transpose context a = Map (TTranspose context) a
89
116
90 default toColumns ::
117 default toColumns ::
91 ( Generic (Record a)
118 ( Generic (Record a)
119+ , KnownAlgebra (GAlgebra (Rep (Record a)))
92− , GTable (TTable context) TColumns (Rep (Record a))
120+ , Eval (GGTable (GAlgebra (Rep (Record a))) (TTable context) TColumns (Col context) (Rep (Record a)))
93− , Columns a ~ GColumns TColumns (Rep (Record a))
121+ , Columns a ~ Eval (GGColumns (GAlgebra (Rep (Record a))) TColumns (Rep (Record a)))
122+ , Context a ~ Eval (GGContext (GAlgebra (Rep (Record a))) TContext (Rep (Record a)))
94 )
123 )
95− => a -> Columns a context
124+ => a -> Columns a (Col context)
96 toColumns =
125 toColumns =
126+ ggtoColumns
127+ @(GAlgebra (Rep (Record a)))
97− gtoColumns @(TTable context) @TColumns toColumns .
128+ @(TTable context)
129+ @TColumns
130+ id
131+ id
132+ toColumns .
98 from .
133 from .
99 Record
134 Record
100
135
101 default fromColumns ::
136 default fromColumns ::
102 ( Generic (Record a)
137 ( Generic (Record a)
138+ , KnownAlgebra (GAlgebra (Rep (Record a)))
103− , GTable (TTable context) TColumns (Rep (Record a))
139+ , Eval (GGTable (GAlgebra (Rep (Record a))) (TTable context) TColumns (Col context) (Rep (Record a)))
104− , Columns a ~ GColumns TColumns (Rep (Record a))
140+ , Columns a ~ Eval (GGColumns (GAlgebra (Rep (Record a))) TColumns (Rep (Record a)))
141+ , Context a ~ Eval (GGContext (GAlgebra (Rep (Record a))) TContext (Rep (Record a)))
105 )
142 )
106− => Columns a context -> a
143+ => Columns a (Col context) -> a
107 fromColumns =
144 fromColumns =
108 unrecord .
145 unrecord .
109 to .
146 to .
147+ ggfromColumns
148+ @(GAlgebra (Rep (Record a)))
110− gfromColumns @(TTable context) @TColumns fromColumns
149+ @(TTable context)
150+ @TColumns
151+ id
152+ id
153+ fromColumns
111
154
112− default toResult ::
155+ default reify ::
113− ( Generic (Record (FromExprs a))
156+ ( Generic (Record a)
114− , GSerialize TSerialize TColumns (Rep (Record a)) (Rep (Record (FromExprs a)))
157+ , Generic (Record (Unreify a))
115− , Columns a ~ GColumns TColumns (Rep (Record a))
158+ , GMappable (TTable context) (Rep (Record a))
159+ , Rep (Record (Unreify a)) ~ GMap TUnreify (Rep (Record a))
116 )
160 )
117− => FromExprs a -> Columns a Result
161+ => context :~: Reify ctx -> Unreify a -> a
118− toResult =
162+ reify Refl =
119− gtoResult
163+ unrecord .
120− @TSerialize
164+ to .
121− @TColumns
165+ gunmap @(TTable context) (Proxy @TUnreify) (reify Refl) .
122− @(Rep (Record a))
123− @(Rep (Record (FromExprs a)))
124− (\(_ :: proxy x) -> toResult @(Context x) @x) .
125 from .
166 from .
126 Record
167 Record
127
168
128− default fromResult ::
169+ default unreify ::
129− ( Generic (Record (FromExprs a))
170+ ( Generic (Record a)
130− , GSerialize TSerialize TColumns (Rep (Record a)) (Rep (Record (FromExprs a)))
171+ , Generic (Record (Unreify a))
131− , Columns a ~ GColumns TColumns (Rep (Record a))
172+ , GMappable (TTable context) (Rep (Record a))
173+ , Rep (Record (Unreify a)) ~ GMap TUnreify (Rep (Record a))
132 )
174 )
133− => Columns a Result -> FromExprs a
175+ => context :~: Reify ctx -> a -> Unreify a
134− fromResult =
176+ unreify Refl =
135 unrecord .
177 unrecord .
136 to .
178 to .
137− gfromResult
179+ gmap @(TTable context) (Proxy @TUnreify) (unreify Refl) .
138− @TSerialize
180+ from .
139− @TColumns
181+ Record
140− @(Rep (Record a))
141− @(Rep (Record (FromExprs a)))
142− (\(_ :: proxy x) -> fromResult @(Context x) @x)
143−
144−
145−instance Sql DBType a => Table Result (Identity a) where
146− type Columns (Identity a) = HIdentity a
147− type Context (Identity a) = Result
148− type FromExprs (Identity a) = a
149− type Transpose to (Identity a) = to a
150
182
151− toColumns = HIdentity
183+ default coherence ::
152− fromColumns (HIdentity a) = a
184+ ( KnownAlgebra (GAlgebra (Rep (Record a)))
153− toResult a = HIdentity (Identity a)
185+ , GCoherent (TTable context) (Rep (Record a))
154− fromResult (HIdentity (Identity a)) = a
186+ , Context a ~ Eval (GGContext (GAlgebra (Rep (Record a))) TContext (Rep (Record a)))
187+ , Context (Unreify a) ~ Eval (GGContext (GAlgebra (Rep (Record a))) TContext (Rep (Record (Unreify a))))
188+ , Rep (Record (Unreify a)) ~ GMap TUnreify (Rep (Record a))
189+ )
190+ => context :~: Reify ctx -> NotResult ctx -> Context (Unreify a) :~: ctx
191+ coherence = case algebraSing @(GAlgebra (Rep (Record a))) of
192+ SSum -> notReify
193+ SProduct -> \proof abstract ->
194+ gcoherence
195+ @(TTable context)
196+ @(Rep (Record a))
197+ (Proxy @TContext)
198+ (Proxy @TUnreify)
199+ (\(_ :: _proxy x) -> coherence @context @x proof abstract)
200+
201+ default congruence ::
202+ ( KnownAlgebra (GAlgebra (Rep (Record a)))
203+ , GCoherent (TTable context) (Rep (Record a))
204+ , Context a ~ Eval (GGContext (GAlgebra (Rep (Record a))) TContext (Rep (Record a)))
205+ , Columns a ~ Eval (GGColumns (GAlgebra (Rep (Record a))) TColumns (Rep (Record a)))
206+ , Columns (Unreify a) ~ Eval (GGColumns (GAlgebra (Rep (Record a))) TColumns (Rep (Record (Unreify a))))
207+ , Rep (Record (Unreify a)) ~ GMap TUnreify (Rep (Record a))
208+ )
209+ => context :~: Reify ctx -> NotResult ctx -> Columns a :~: Columns (Unreify a)
210+ congruence = case algebraSing @(GAlgebra (Rep (Record a))) of
211+ SSum -> notReify
212+ SProduct -> \proof abstract ->
213+ gcongruence
214+ @(TTable context)
215+ @(Rep (Record a))
216+ (Proxy @TColumns)
217+ (Proxy @TUnreify)
218+ (\(_ :: _proxy x) -> congruence @context @x proof abstract)
155
219
156
220
157data TTable :: K.Context -> Type -> Exp Constraint
221data TTable :: K.Context -> Type -> Exp Constraint
@@ -166,19 +230,185 @@ data TContext :: Type -> Exp K.Context
166type instance Eval (TContext a) = Context a
230type instance Eval (TContext a) = Context a
167
231
168
232
169−data TFromExprs :: Type -> Exp Type
233+data TUnreify :: Type -> Exp Type
170−type instance Eval (TFromExprs a) = FromExprs a
234+type instance Eval (TUnreify a) = Unreify a
171
235
172
236
173−data TTranspose :: K.Context -> Type -> Exp Type
237+type DefaultUnreify :: Type -> Type
174−type instance Eval (TTranspose context a) = Transpose context a
238+type family DefaultUnreify a where
239+ DefaultUnreify (t a b c d e f g) =
240+ t (Unreify a) (Unreify b) (Unreify c) (Unreify d) (Unreify e) (Unreify f) (Unreify g)
241+ DefaultUnreify (t a b c d e f) =
242+ t (Unreify a) (Unreify b) (Unreify c) (Unreify d) (Unreify e) (Unreify f)
243+ DefaultUnreify (t a b c d e) =
244+ t (Unreify a) (Unreify b) (Unreify c) (Unreify d) (Unreify e)
245+ DefaultUnreify (t a b c d) =
246+ t (Unreify a) (Unreify b) (Unreify c) (Unreify d)
247+ DefaultUnreify (t a b c) = t (Unreify a) (Unreify b) (Unreify c)
248+ DefaultUnreify (t a b) = t (Unreify a) (Unreify b)
249+ DefaultUnreify (t a) = t (Unreify a)
250+ DefaultUnreify a = ARep (GMap TUnreify (Rep a))
175
251
176
252
177−data TSerialize :: Type -> Type -> Exp Constraint
253+-- | Any 'HTable' is also a 'Table'.
178−type instance Eval (TSerialize expr a) =
254+instance HTable t => Table context (t (Col context)) where
179− ( Table (Context expr) expr
255+ type Columns (t (Col context)) = t
180− , a ~ FromExprs expr
256+ type Context (t (Col context)) = context
181− )
257+ type Unreify (t (Col context)) = t (Col (UnwrapReify context))
258+
259+ toColumns = id
260+ fromColumns = id
261+
262+ reify Refl = hreify
263+ unreify Refl = hunreify
264+ coherence Refl _ = Refl
265+ congruence Refl _ = Refl
266+
267+
268+-- | Any context is trivially a table.
269+instance KnownSpec spec => Table context (Col context spec) where
270+ type Columns (Col context spec) = HIdentity spec
271+ type Context (Col context spec) = context
272+ type Unreify (Col context spec) = Col (UnwrapReify context) spec
273+
274+ toColumns = HIdentity
275+ fromColumns = unHIdentity
276+
277+ reify Refl = Reify
278+ unreify Refl (Reify a) = a
279+ coherence Refl _ = Refl
280+ congruence Refl _ = Refl
281+
282+
283+instance Sql DBType a => Table Result (Identity a) where
284+ type Columns (Identity a) = HType a
285+ type Context (Identity a) = Result
286+
287+ toColumns (Identity a) = HType (R a)
288+ fromColumns (HType (R a)) = Identity a
289+
290+ reify = notReify
291+ unreify = notReify
292+ coherence = notReify
293+ congruence = notReify
294+
295+
296+instance (context ~ Result, Table context a, Table context b) =>
297+ Table context (Either a b)
298+ where
299+ type Columns (Either a b) = HEitherTable (Columns a) (Columns b)
300+ type Context (Either a b) = Context a
301+
302+ toColumns = \case
303+ Left table -> HEitherTable
304+ { htag = hlabel (HType (R IsLeft))
305+ , hleft = hlabel (hnullify nullifier (toColumns table))
306+ , hright = hlabel (hnulls (const null))
307+ }
308+ Right table -> HEitherTable
309+ { htag = hlabel (HType (R IsRight))
310+ , hleft = hlabel (hnulls (const null))
311+ , hright = hlabel (hnullify nullifier (toColumns table))
312+ }
313+
314+ fromColumns HEitherTable {htag, hleft, hright} = case hunlabel htag of
315+ HType (R tag) -> case tag of
316+ IsLeft -> maybe err (Left . fromColumns) $ hunnullify unnullifier (hunlabel hleft)
317+ IsRight -> maybe err (Right . fromColumns) $ hunnullify unnullifier (hunlabel hright)
318+ where
319+ err = error "Either.fromColumns: mismatch between tag and data"
320+
321+ coherence = notReify
322+ congruence = notReify
323+
324+
325+instance (context ~ Result, Table context a) => Table context [a] where
326+ type Columns [a] = HListTable (Columns a)
327+ type Context [a] = Context a
328+
329+ toColumns = hvectorize vectorizer . fmap toColumns
330+ fromColumns = fmap fromColumns . hunvectorize unvectorizer
331+
332+ coherence = notReify
333+ congruence = notReify
334+
335+
336+instance (context ~ Result, Table context a) => Table context (Maybe a) where
337+ type Columns (Maybe a) = HMaybeTable (Columns a)
338+ type Context (Maybe a) = Context a
339+
340+ toColumns = \case
341+ Nothing -> HMaybeTable
342+ { htag = hlabel (HIdentity (R Nothing))
343+ , hjust = hlabel (hnulls (const null))
344+ }
345+ Just table -> HMaybeTable
346+ { htag = hlabel (HIdentity (R (Just IsJust)))
347+ , hjust = hlabel (hnullify nullifier (toColumns table))
348+ }
349+
350+ fromColumns HMaybeTable {htag, hjust} = case hunlabel htag of
351+ HType (R tag) -> tag $>
352+ case hunnullify unnullifier (hunlabel hjust) of
353+ Nothing -> error "Maybe.fromColumns: mismatch between tag and data"
354+ Just just -> fromColumns just
355+
356+ coherence = notReify
357+ congruence = notReify
358+
359+
360+instance (context ~ Result, Table context a) => Table context (NonEmpty a)
361+ where
362+ type Columns (NonEmpty a) = HNonEmptyTable (Columns a)
363+ type Context (NonEmpty a) = Context a
364+
365+ toColumns = hvectorize vectorizer . fmap toColumns
366+ fromColumns = fmap fromColumns . hunvectorize unvectorizer
367+
368+ coherence = notReify
369+ congruence = notReify
370+
371+
372+instance (context ~ Result, Table context a, Table context b) =>
373+ Table context (These a b)
374+ where
375+ type Columns (These a b) = HTheseTable (Columns a) (Columns b)
376+ type Context (These a b) = Context a
377+
378+ toColumns tables = HTheseTable
379+ { hhereTag = hrelabel hhereTag
380+ , hhere = hrelabel (toColumns hhere)
381+ , hthereTag = hrelabel hthereTag
382+ , hthere = hrelabel (toColumns hthere)
383+ }
384+ where
385+ HMaybeTable
386+ { htag = hhereTag
387+ , hjust = hhere
388+ } = toColumns (justHere tables)
389+ HMaybeTable
390+ { htag = hthereTag
391+ , hjust = hthere
392+ } = toColumns (justThere tables)
393+
394+ fromColumns HTheseTable {hhereTag, hhere, hthereTag, hthere} =
395+ case (fromColumns mhere, fromColumns mthere) of
396+ (Just a, Nothing) -> This (fromColumns a)
397+ (Nothing, Just b) -> That (fromColumns b)
398+ (Just a, Just b) -> These (fromColumns a) (fromColumns b)
399+ _ -> error "These.fromColumns: mismatch between tags and data"
400+ where
401+ mhere = HMaybeTable
402+ { htag = hrelabel hhereTag
403+ , hjust = hrelabel hhere
404+ }
405+ mthere = HMaybeTable
406+ { htag = hrelabel hthereTag
407+ , hjust = hrelabel hthere
408+ }
409+
410+ coherence = notReify
411+ congruence = notReify
182
412
183
413
184instance (Table context a, Table context b) => Table context (a, b)
414instance (Table context a, Table context b) => Table context (a, b)
src/Rel8/Table/ADT.hs+65−33
@@ -7,13 +7,13 @@
7{-# language ScopedTypeVariables #-}
7{-# language ScopedTypeVariables #-}
8{-# language StandaloneKindSignatures #-}
8{-# language StandaloneKindSignatures #-}
9{-# language TypeApplications #-}
9{-# language TypeApplications #-}
10−{-# language TypeFamilyDependencies #-}
10+{-# language TypeFamilies #-}
11{-# language UndecidableInstances #-}
11{-# language UndecidableInstances #-}
12{-# language UndecidableSuperClasses #-}
12{-# language UndecidableSuperClasses #-}
13
13
14module Rel8.Table.ADT
14module Rel8.Table.ADT
15 ( ADT( ADT )
15 ( ADT( ADT )
16− , ADTable
16+ , ADTable, fromADT, toADT
17 , BuildableADT
17 , BuildableADT
18 , BuildADT, buildADT
18 , BuildADT, buildADT
19 , ConstructableADT
19 , ConstructableADT
@@ -27,7 +27,9 @@ where
27
27
28-- base
28-- base
29import Data.Kind ( Constraint, Type )
29import Data.Kind ( Constraint, Type )
30+import Data.Proxy ( Proxy( Proxy ) )
31+import Data.Type.Equality ( (:~:)( Refl ) )
30−import GHC.Generics ( Generic, from, to )
32+import GHC.Generics ( Generic, Rep, from, to )
31import GHC.TypeLits ( Symbol )
33import GHC.TypeLits ( Symbol )
32import Prelude
34import Prelude
33
35
@@ -44,65 +46,95 @@ import Rel8.Generic.Construction
44 , GGName, ggname
46 , GGName, ggname
45 , GGAggregate, ggaggregate
47 , GGAggregate, ggaggregate
46 )
48 )
47−import Rel8.Generic.Record ( Record( Record ), unrecord )
49+import Rel8.Generic.Map ( GMappable, GMap, gmap, gunmap )
50+import Rel8.Generic.Record ( GRecordable, GRecord, grecord, gunrecord )
48import Rel8.Generic.Rel8able
51import Rel8.Generic.Rel8able
49 ( Rel8able
52 ( Rel8able
50 , GRep, GColumns, gfromColumns, gtoColumns
53 , GRep, GColumns, gfromColumns, gtoColumns
51− , GFromExprs, gfromResult, gtoResult
54+ , greify, gunreify
52− , TSerialize, deserialize, serialize
53 )
55 )
54import qualified Rel8.Generic.Table.ADT as G
56import qualified Rel8.Generic.Table.ADT as G
55import qualified Rel8.Kind.Algebra as K
57import qualified Rel8.Kind.Algebra as K
58+import Rel8.Schema.Context ( Col )
56import Rel8.Schema.HTable ( HTable )
59import Rel8.Schema.HTable ( HTable )
57import qualified Rel8.Schema.Kind as K
60import qualified Rel8.Schema.Kind as K
58import Rel8.Schema.Name ( Name )
61import Rel8.Schema.Name ( Name )
62+import Rel8.Schema.Reify ( Col( Reify ), Reify, hreify, hunreify )
59import Rel8.Schema.Result ( Result )
63import Rel8.Schema.Result ( Result )
60−import Rel8.Table ( Table, TColumns )
64+import Rel8.Table
65+ ( Table
66+ , fromColumns, toColumns, reify, unreify
67+ , TTable, TColumns, TUnreify
68+ )
61
69
62
70
63type ADT :: K.Rel8able -> K.Rel8able
71type ADT :: K.Rel8able -> K.Rel8able
64−newtype ADT t context = ADT (GColumnsADT t context)
72+newtype ADT t context = ADT (GColumnsADT t (Col context))
65
73
66
74
67instance ADTable t => Rel8able (ADT t) where
75instance ADTable t => Rel8able (ADT t) where
68 type GColumns (ADT t) = GColumnsADT t
76 type GColumns (ADT t) = GColumnsADT t
69− type GFromExprs (ADT t) = t Result
70
77
71− gfromColumns _ = ADT
78+ gfromColumns = ADT
72− gtoColumns _ (ADT a) = a
79+ gtoColumns (ADT a) = a
80+
81+ greify (ADT a) = ADT (hreify a)
82+ gunreify (ADT a) = ADT (hunreify a)
73
83
74− gfromResult =
75− unrecord .
76− to .
77− G.gfromResultADT
78− @TSerialize
79− @TColumns
80− @(Eval (ADTRep t Expr))
81− @(Eval (ADTRep t Result))
82− (\(_ :: proxy x) -> deserialize @_ @x)
83
84
84− gtoResult =
85+instance (ADTable t, context ~ Result) => Generic (ADT t context) where
85− G.gtoResultADT
86+ type Rep (ADT t context) = Rep (t context)
86− @TSerialize
87+
88+ from =
89+ gmap @(TTable (Reify Result)) (Proxy @TUnreify) (unreify Refl) .
90+ gunrecord @(Rep (t (Reify Result))) .
91+ G.gfromColumnsADT
92+ @(TTable (Reify Result))
93+ @TColumns
94+ (\(Reify a) -> a)
95+ Reify
96+ fromColumns .
97+ hreify .
98+ (\(ADT a) -> a)
99+
100+ to =
101+ ADT .
102+ hunreify .
103+ G.gtoColumnsADT
104+ @(TTable (Reify Result))
87 @TColumns
105 @TColumns
88− @(Eval (ADTRep t Expr))
106+ (\(Reify a) -> a)
89− @(Eval (ADTRep t Result))
107+ Reify
90− (\(_ :: proxy x) -> serialize @_ @x) .
108+ toColumns .
91− from .
109+ grecord @(Rep (t (Reify Result))) .
92− Record
110+ gunmap @(TTable (Reify Result)) (Proxy @TUnreify) (reify Refl)
111+
112+
113+fromADT :: ADTable t => ADT t Result -> t Result
114+fromADT = to . from
115+
116+
117+toADT :: ADTable t => t Result -> ADT t Result
118+toADT = to . from
93
119
94
120
95type ADTable :: K.Rel8able -> Constraint
121type ADTable :: K.Rel8able -> Constraint
96class
122class
97− ( Generic (Record (t Result))
123+ ( Generic (t Result)
98 , HTable (GColumnsADT t)
124 , HTable (GColumnsADT t)
99− , G.GSerializeADT TSerialize TColumns (Eval (ADTRep t Expr)) (Eval (ADTRep t Result))
125+ , G.GTableADT (TTable (Reify Result)) TColumns (Col (Reify Result)) (GRecord (Rep (t (Reify Result))))
126+ , GRecordable (Rep (t (Reify Result)))
127+ , GMappable (TTable (Reify Result)) (Rep (t (Reify Result)))
128+ , GMap TUnreify (Rep (t (Reify Result))) ~ Rep (t Result)
100 )
129 )
101 => ADTable t
130 => ADTable t
102instance
131instance
103− ( Generic (Record (t Result))
132+ ( Generic (t Result)
104 , HTable (GColumnsADT t)
133 , HTable (GColumnsADT t)
105− , G.GSerializeADT TSerialize TColumns (Eval (ADTRep t Expr)) (Eval (ADTRep t Result))
134+ , G.GTableADT (TTable (Reify Result)) TColumns (Col (Reify Result)) (GRecord (Rep (t (Reify Result))))
135+ , GRecordable (Rep (t (Reify Result)))
136+ , GMappable (TTable (Reify Result)) (Rep (t (Reify Result)))
137+ , GMap TUnreify (Rep (t (Reify Result))) ~ Rep (t Result)
106 )
138 )
107 => ADTable t
139 => ADTable t
108
140
@@ -170,4 +202,4 @@ type instance Eval (ADTRep t context) = GRep t context
170
202
171
203
172type GColumnsADT :: K.Rel8able -> K.HTable
204type GColumnsADT :: K.Rel8able -> K.HTable
173−type GColumnsADT t = G.GColumnsADT TColumns (GRep t Expr)
205+type GColumnsADT t = G.GColumnsADT TColumns (GRep t (Reify Result))
src/Rel8/Table/Aggregate.hs+10−20
@@ -16,8 +16,8 @@ import Data.Functor.Identity ( Identity( Identity ) )
16import Prelude
16import Prelude
17
17
18-- rel8
18-- rel8
19−import Rel8.Aggregate ( Aggregate, Aggregates )
19+import Rel8.Aggregate ( Aggregate, Aggregates, Col( A ) )
20−import Rel8.Expr ( Expr )
20+import Rel8.Expr ( Expr, Col( E ) )
21import Rel8.Expr.Aggregate
21import Rel8.Expr.Aggregate
22 ( groupByExpr
22 ( groupByExpr
23 , slistAggExpr
23 , slistAggExpr
@@ -27,7 +27,8 @@ import Rel8.Schema.Dict ( Dict( Dict ) )
27import Rel8.Schema.HTable ( HTable, hfield, htabulate )
27import Rel8.Schema.HTable ( HTable, hfield, htabulate )
28import Rel8.Schema.HTable.Vectorize ( hvectorize )
28import Rel8.Schema.HTable.Vectorize ( hvectorize )
29import Rel8.Schema.Null ( Sql )
29import Rel8.Schema.Null ( Sql )
30−import Rel8.Schema.Spec ( Spec( Spec, info ) )
30+import Rel8.Schema.Spec ( SSpec( SSpec, info ) )
31+import Rel8.Schema.Spec.Constrain ( ConstrainSpec )
31import Rel8.Table ( toColumns, fromColumns )
32import Rel8.Table ( toColumns, fromColumns )
32import Rel8.Table.Eq ( EqTable, eqTable )
33import Rel8.Table.Eq ( EqTable, eqTable )
33import Rel8.Table.List ( ListTable )
34import Rel8.Table.List ( ListTable )
@@ -37,28 +38,17 @@ import Rel8.Type.Eq ( DBEq )
37
38
38-- | Group equal tables together. This works by aggregating each column in the
39-- | Group equal tables together. This works by aggregating each column in the
39-- given table with 'groupByExpr'.
40-- given table with 'groupByExpr'.
40−--
41−-- For example, if we have a table of items, we could group the items by the
42−-- order they belong to:
43−--
44−-- @
45−-- itemsByOrder :: Query (OrderId Expr, ListTable Expr (Item Expr))
46−-- itemsByOrder = aggregate $ do
47−-- item <- each itemSchema
48−-- let orderId = groupBy (itemOrderId item)
49−-- let orderItems = listAgg item
50−-- pure (orderId, orderItems)
51−-- @
52groupBy :: forall exprs aggregates. (EqTable exprs, Aggregates aggregates exprs)
41groupBy :: forall exprs aggregates. (EqTable exprs, Aggregates aggregates exprs)
53 => exprs -> aggregates
42 => exprs -> aggregates
54groupBy = fromColumns . hgroupBy (eqTable @exprs) . toColumns
43groupBy = fromColumns . hgroupBy (eqTable @exprs) . toColumns
55
44
56
45
46+hgroupBy :: HTable t
57−hgroupBy :: HTable t => t (Dict (Sql DBEq)) -> t Expr -> t Aggregate
47+ => t (Dict (ConstrainSpec (Sql DBEq))) -> t (Col Expr) -> t (Col Aggregate)
58−hgroupBy eqs exprs = htabulate $ \field ->
48+hgroupBy eqs exprs = fromColumns $ htabulate $ \field ->
59 case hfield eqs field of
49 case hfield eqs field of
60 Dict -> case hfield exprs field of
50 Dict -> case hfield exprs field of
61− expr -> groupByExpr expr
51+ E expr -> A $ groupByExpr expr
62
52
63
53
64-- | Aggregate rows into a single row containing an array of all aggregated
54-- | Aggregate rows into a single row containing an array of all aggregated
@@ -80,7 +70,7 @@ hgroupBy eqs exprs = htabulate $ \field ->
80listAgg :: Aggregates aggregates exprs => exprs -> ListTable Aggregate aggregates
70listAgg :: Aggregates aggregates exprs => exprs -> ListTable Aggregate aggregates
81listAgg (toColumns -> exprs) = fromColumns $
71listAgg (toColumns -> exprs) = fromColumns $
82 hvectorize
72 hvectorize
83− (\Spec {info} (Identity a) -> slistAggExpr info a)
73+ (\SSpec {info} (Identity (E a)) -> A $ slistAggExpr info a)
84 (pure exprs)
74 (pure exprs)
85
75
86
76
@@ -88,5 +78,5 @@ listAgg (toColumns -> exprs) = fromColumns $
88nonEmptyAgg :: Aggregates aggregates exprs => exprs -> NonEmptyTable Aggregate aggregates
78nonEmptyAgg :: Aggregates aggregates exprs => exprs -> NonEmptyTable Aggregate aggregates
89nonEmptyAgg (toColumns -> exprs) = fromColumns $
79nonEmptyAgg (toColumns -> exprs) = fromColumns $
90 hvectorize
80 hvectorize
91− (\Spec {info} (Identity a) -> snonEmptyAggExpr info a)
81+ (\SSpec {info} (Identity (E a)) -> A $ snonEmptyAggExpr info a)
92 (pure exprs)
82 (pure exprs)
src/Rel8/Table/Bool.hs+6−5
@@ -13,7 +13,7 @@ where
13import Prelude
13import Prelude
14
14
15-- rel8
15-- rel8
16−import Rel8.Expr ( Expr )
16+import Rel8.Expr ( Expr, Col( E, unE ) )
17import Rel8.Expr.Bool ( boolExpr, caseExpr )
17import Rel8.Expr.Bool ( boolExpr, caseExpr )
18import Rel8.Expr.Null ( isNull, unsafeUnnullify )
18import Rel8.Expr.Null ( isNull, unsafeUnnullify )
19import Rel8.Schema.HTable ( htabulate, hfield )
19import Rel8.Schema.HTable ( htabulate, hfield )
@@ -28,7 +28,8 @@ bool :: Table Expr a => a -> a -> Expr Bool -> a
28bool (toColumns -> false) (toColumns -> true) condition =
28bool (toColumns -> false) (toColumns -> true) condition =
29 fromColumns $ htabulate $ \field ->
29 fromColumns $ htabulate $ \field ->
30 case (hfield false field, hfield true field) of
30 case (hfield false field, hfield true field) of
31+ (E falseExpr, E trueExpr) ->
31− (falseExpr, trueExpr) -> boolExpr falseExpr trueExpr condition
32+ E (boolExpr falseExpr trueExpr condition)
32{-# INLINABLE bool #-}
33{-# INLINABLE bool #-}
33
34
34
35
@@ -38,9 +39,9 @@ bool (toColumns -> false) (toColumns -> true) condition =
38case_ :: Table Expr a => [(Expr Bool, a)] -> a -> a
39case_ :: Table Expr a => [(Expr Bool, a)] -> a -> a
39case_ (map (fmap toColumns) -> branches) (toColumns -> fallback) =
40case_ (map (fmap toColumns) -> branches) (toColumns -> fallback) =
40 fromColumns $ htabulate $ \field -> case hfield fallback field of
41 fromColumns $ htabulate $ \field -> case hfield fallback field of
41− fallbackExpr ->
42+ E fallbackExpr ->
42− case map (fmap (`hfield` field)) branches of
43+ case map (fmap (unE . (`hfield` field))) branches of
43− branchExprs -> caseExpr branchExprs fallbackExpr
44+ branchExprs -> E (caseExpr branchExprs fallbackExpr)
44
45
45
46
46-- | Like 'maybe', but to eliminate @null@.
47-- | Like 'maybe', but to eliminate @null@.
src/Rel8/Table/Cols.hsdeleted−50
@@ -1,50 +0,0 @@
1−{-# language DataKinds #-}
2−{-# language FlexibleInstances #-}
3−{-# language MultiParamTypeClasses #-}
4−{-# language StandaloneKindSignatures #-}
5−{-# language TypeFamilies #-}
6−{-# language UndecidableInstances #-}
7−
8−module Rel8.Table.Cols
9− ( Cols( Cols )
10− , fromCols
11− , toCols
12− )
13−where
14−
15−-- base
16−import Data.Kind ( Type )
17−import Prelude
18−
19−-- rel8
20−import qualified Rel8.Schema.Kind as K
21−import Rel8.Schema.HTable ( HTable )
22−import Rel8.Schema.Result ( Result )
23−import Rel8.Table ( Table(..) )
24−
25−
26−type Cols :: K.Context -> K.HTable -> Type
27−newtype Cols context columns = Cols (columns context)
28−
29−
30−instance (HTable columns, context ~ context') =>
31− Table context' (Cols context columns)
32− where
33− type Columns (Cols context columns) = columns
34− type Context (Cols context columns) = context
35− type FromExprs (Cols context columns) = Cols Result columns
36− type Transpose to (Cols context columns) = Cols to columns
37−
38− toColumns (Cols a) = a
39− fromColumns = Cols
40−
41− toResult (Cols a) = a
42− fromResult = Cols
43−
44−
45−fromCols :: Table context a => Cols context (Columns a) -> a
46−fromCols (Cols a) = fromColumns a
47−
48−
49−toCols :: Table context a => a -> Cols context (Columns a)
50−toCols = Cols . toColumns
src/Rel8/Table/Either.hs+66−58
@@ -3,7 +3,6 @@
3{-# language DerivingStrategies #-}
3{-# language DerivingStrategies #-}
4{-# language FlexibleContexts #-}
4{-# language FlexibleContexts #-}
5{-# language FlexibleInstances #-}
5{-# language FlexibleInstances #-}
6−{-# language LambdaCase #-}
7{-# language MultiParamTypeClasses #-}
6{-# language MultiParamTypeClasses #-}
8{-# language NamedFieldPuns #-}
7{-# language NamedFieldPuns #-}
9{-# language ScopedTypeVariables #-}
8{-# language ScopedTypeVariables #-}
@@ -24,38 +23,40 @@ module Rel8.Table.Either
24where
23where
25
24
26-- base
25-- base
26+import Control.Category ( id )
27import Data.Bifunctor ( Bifunctor, bimap )
27import Data.Bifunctor ( Bifunctor, bimap )
28−import Data.Functor.Identity ( Identity( Identity ) )
29import Data.Kind ( Type )
28import Data.Kind ( Type )
29+import Data.Type.Equality ( apply )
30−import Prelude hiding ( undefined )
30+import Prelude hiding ( id, undefined )
31
31
32-- comonad
32-- comonad
33import Control.Comonad ( extract )
33import Control.Comonad ( extract )
34
34
35-- rel8
35-- rel8
36−import Rel8.Aggregate ( Aggregate )
36+import Rel8.Aggregate ( Col( A ), Aggregate )
37−import Rel8.Expr ( Expr )
37+import Rel8.Expr ( Col( E ), Expr )
38import Rel8.Expr.Aggregate ( groupByExpr )
38import Rel8.Expr.Aggregate ( groupByExpr )
39import Rel8.Expr.Serialize ( litExpr )
39import Rel8.Expr.Serialize ( litExpr )
40import Rel8.Kind.Context ( Reifiable )
40import Rel8.Kind.Context ( Reifiable )
41+import Rel8.Schema.Context.Abstract ( Abstract )
41import Rel8.Schema.Context.Nullify ( Nullifiable )
42import Rel8.Schema.Context.Nullify ( Nullifiable )
42import Rel8.Schema.Dict ( Dict( Dict ) )
43import Rel8.Schema.Dict ( Dict( Dict ) )
43import Rel8.Schema.HTable.Either ( HEitherTable(..) )
44import Rel8.Schema.HTable.Either ( HEitherTable(..) )
44import Rel8.Schema.HTable.Identity ( HIdentity(..) )
45import Rel8.Schema.HTable.Identity ( HIdentity(..) )
45import Rel8.Schema.HTable.Label ( hlabel, hunlabel )
46import Rel8.Schema.HTable.Label ( hlabel, hunlabel )
46import qualified Rel8.Schema.Kind as K
47import qualified Rel8.Schema.Kind as K
47−import Rel8.Schema.Name ( Name )
48+import Rel8.Schema.Name ( Col( N ), Name )
49+import Rel8.Schema.Spec ( Spec( Spec ) )
48import Rel8.Table
50import Rel8.Table
49 ( Table, Columns, Context, fromColumns, toColumns
51 ( Table, Columns, Context, fromColumns, toColumns
50− , FromExprs, fromResult, toResult
52+ , reify, unreify, coherence, congruence
51− , Transpose
52 )
53 )
53import Rel8.Table.Bool ( bool )
54import Rel8.Table.Bool ( bool )
54import Rel8.Table.Eq ( EqTable, eqTable )
55import Rel8.Table.Eq ( EqTable, eqTable )
55import Rel8.Table.Nullify ( Nullify, aggregateNullify, guard )
56import Rel8.Table.Nullify ( Nullify, aggregateNullify, guard )
56import Rel8.Table.Ord ( OrdTable, ordTable )
57import Rel8.Table.Ord ( OrdTable, ordTable )
57−import Rel8.Table.Projection ( Biprojectable, Projectable, biproject, project )
58+import Rel8.Table.Recontextualize ( Recontextualize )
58−import Rel8.Table.Serialize ( ToExprs )
59+import Rel8.Table.Serialize ( FromExprs, ToExprs, fromResult, toResult )
59import Rel8.Table.Undefined ( undefined )
60import Rel8.Table.Undefined ( undefined )
60import Rel8.Type.Tag ( EitherTag( IsLeft, IsRight ), isLeft, isRight )
61import Rel8.Type.Tag ( EitherTag( IsLeft, IsRight ), isLeft, isRight )
61
62
@@ -72,29 +73,20 @@ import Data.Functor.Bind ( Bind, (>>-) )
72-- adapted to work with Rel8.
73-- adapted to work with Rel8.
73type EitherTable :: K.Context -> Type -> Type -> Type
74type EitherTable :: K.Context -> Type -> Type -> Type
74data EitherTable context a b = EitherTable
75data EitherTable context a b = EitherTable
75− { tag :: context EitherTag
76+ { tag :: Col context ('Spec EitherTag)
76 , left :: Nullify context a
77 , left :: Nullify context a
77 , right :: Nullify context b
78 , right :: Nullify context b
78 }
79 }
79 deriving stock Functor
80 deriving stock Functor
80
81
81
82
82−instance Biprojectable (EitherTable context) where
83− biproject f g (EitherTable tag a b) =
84− EitherTable tag (project f a) (project g b)
85−
86−
87instance Nullifiable context => Bifunctor (EitherTable context) where
83instance Nullifiable context => Bifunctor (EitherTable context) where
88 bimap f g (EitherTable tag a b) = EitherTable tag (fmap f a) (fmap g b)
84 bimap f g (EitherTable tag a b) = EitherTable tag (fmap f a) (fmap g b)
89
85
90
86
91−instance Projectable (EitherTable context a) where
92− project f (EitherTable tag a b) = EitherTable tag a (project f b)
93−
94−
95instance (context ~ Expr, Table Expr a) => Apply (EitherTable context a) where
87instance (context ~ Expr, Table Expr a) => Apply (EitherTable context a) where
96− EitherTable tag l1 f <.> EitherTable tag' l2 a =
88+ EitherTable (E tag) l1 f <.> EitherTable (E tag') l2 a =
97− EitherTable (tag <> tag') (bool l1 l2 (isLeft tag)) (f <.> a)
89+ EitherTable (E (tag <> tag')) (bool l1 l2 (isLeft tag)) (f <.> a)
98
90
99
91
100instance (context ~ Expr, Table Expr a) => Applicative (EitherTable context a) where
92instance (context ~ Expr, Table Expr a) => Applicative (EitherTable context a) where
@@ -103,9 +95,9 @@ instance (context ~ Expr, Table Expr a) => Applicative (EitherTable context a) w
103
95
104
96
105instance (context ~ Expr, Table Expr a) => Bind (EitherTable context a) where
97instance (context ~ Expr, Table Expr a) => Bind (EitherTable context a) where
106− EitherTable tag l1 a >>- f = case f (extract a) of
98+ EitherTable (E tag) l1 a >>- f = case f (extract a) of
107− EitherTable tag' l2 b ->
99+ EitherTable (E tag') l2 b ->
108− EitherTable (tag <> tag') (bool l1 l2 (isRight tag)) b
100+ EitherTable (E (tag <> tag')) (bool l1 l2 (isRight tag)) b
109
101
110
102
111instance (context ~ Expr, Table Expr a) => Monad (EitherTable context a) where
103instance (context ~ Expr, Table Expr a) => Monad (EitherTable context a) where
@@ -120,18 +112,15 @@ instance (context ~ Expr, Table Expr a, Table Expr b) =>
120
112
121instance
113instance
122 ( Table context a, Table context b
114 ( Table context a, Table context b
123− , Reifiable context, context ~ context'
115+ , Reifiable context, Abstract context, context ~ context'
124 )
116 )
125 => Table context' (EitherTable context a b)
117 => Table context' (EitherTable context a b)
126 where
118 where
127 type Columns (EitherTable context a b) = HEitherTable (Columns a) (Columns b)
119 type Columns (EitherTable context a b) = HEitherTable (Columns a) (Columns b)
128 type Context (EitherTable context a b) = Context a
120 type Context (EitherTable context a b) = Context a
129− type FromExprs (EitherTable context a b) = Either (FromExprs a) (FromExprs b)
130− type Transpose to (EitherTable context a b) =
131− EitherTable to (Transpose to a) (Transpose to b)
132
121
133 toColumns EitherTable {tag, left, right} = HEitherTable
122 toColumns EitherTable {tag, left, right} = HEitherTable
134− { htag = hlabel $ HIdentity tag
123+ { htag = hlabel $ HType tag
135 , hleft = hlabel $ guard tag (== IsLeft) isLeft $ toColumns left
124 , hleft = hlabel $ guard tag (== IsLeft) isLeft $ toColumns left
136 , hright = hlabel $ guard tag (== IsRight) isRight $ toColumns right
125 , hright = hlabel $ guard tag (== IsRight) isRight $ toColumns right
137 }
126 }
@@ -142,31 +131,39 @@ instance
142 , right = fromColumns $ hunlabel hright
131 , right = fromColumns $ hunlabel hright
143 }
132 }
144
133
145− toResult = \case
134+ reify proof EitherTable {tag, left, right} = EitherTable
146− Left table -> HEitherTable
135+ { tag
147− { htag = hlabel (HIdentity (Identity IsLeft))
136+ , left = reify proof left
148− , hleft = hlabel (toResult @_ @(Nullify context a) (Just table))
137+ , right = reify proof right
149− , hright = hlabel (toResult @_ @(Nullify context b) Nothing)
138+ }
150− }
139+
151− Right table -> HEitherTable
140+ unreify proof EitherTable {tag, left, right} = EitherTable
152− { htag = hlabel (HIdentity (Identity IsRight))
141+ { tag
153− , hleft = hlabel (toResult @_ @(Nullify context a) Nothing)
142+ , left = unreify proof left
154− , hright = hlabel (toResult @_ @(Nullify context b) (Just table))
143+ , right = unreify proof right
155− }
144+ }
156−
145+
157− fromResult HEitherTable {htag, hleft, hright} = case hunlabel htag of
146+ coherence = coherence @context @a
158− HIdentity (Identity tag) -> case tag of
147+ congruence proof abstract =
159− IsLeft -> maybe err Left $ fromResult @_ @(Nullify context a) (hunlabel hleft)
148+ id `apply`
160− IsRight -> maybe err Right $ fromResult @_ @(Nullify context b) (hunlabel hright)
149+ congruence @context @a proof abstract `apply`
161− where
150+ congruence @context @b proof abstract
162− err = error "Either.fromColumns: mismatch between tag and data"
151+
152+
153+instance
154+ ( Reifiable from, Abstract from, from ~ from'
155+ , Reifiable to, Abstract to, to ~ to'
156+ , Recontextualize from to a1 b1
157+ , Recontextualize from to a2 b2
158+ )
159+ => Recontextualize from to (EitherTable from' a1 a2) (EitherTable to' b1 b2)
163
160
164
161
165instance (EqTable a, EqTable b, context ~ Expr) =>
162instance (EqTable a, EqTable b, context ~ Expr) =>
166 EqTable (EitherTable context a b)
163 EqTable (EitherTable context a b)
167 where
164 where
168 eqTable = HEitherTable
165 eqTable = HEitherTable
169− { htag = hlabel (HIdentity Dict)
166+ { htag = hlabel (HType Dict)
170 , hleft = hlabel (eqTable @(Nullify context a))
167 , hleft = hlabel (eqTable @(Nullify context a))
171 , hright = hlabel (eqTable @(Nullify context b))
168 , hright = hlabel (eqTable @(Nullify context b))
172 }
169 }
@@ -176,42 +173,53 @@ instance (OrdTable a, OrdTable b, context ~ Expr) =>
176 OrdTable (EitherTable context a b)
173 OrdTable (EitherTable context a b)
177 where
174 where
178 ordTable = HEitherTable
175 ordTable = HEitherTable
179− { htag = hlabel (HIdentity Dict)
176+ { htag = hlabel (HType Dict)
180 , hleft = hlabel (ordTable @(Nullify context a))
177 , hleft = hlabel (ordTable @(Nullify context a))
181 , hright = hlabel (ordTable @(Nullify context b))
178 , hright = hlabel (ordTable @(Nullify context b))
182 }
179 }
183
180
184
181
182+type instance FromExprs (EitherTable _context a b) =
183+ Either (FromExprs a) (FromExprs b)
184+
185+
185instance (ToExprs exprs1 a, ToExprs exprs2 b, x ~ EitherTable Expr exprs1 exprs2) =>
186instance (ToExprs exprs1 a, ToExprs exprs2 b, x ~ EitherTable Expr exprs1 exprs2) =>
186 ToExprs x (Either a b)
187 ToExprs x (Either a b)
188+ where
189+ fromResult =
190+ bimap (fromResult @exprs1) (fromResult @exprs2) .
191+ fromColumns
192+ toResult =
193+ toColumns .
194+ bimap (toResult @exprs1) (toResult @exprs2)
187
195
188
196
189-- | Test if an 'EitherTable' is a 'leftTable'.
197-- | Test if an 'EitherTable' is a 'leftTable'.
190isLeftTable :: EitherTable Expr a b -> Expr Bool
198isLeftTable :: EitherTable Expr a b -> Expr Bool
191−isLeftTable EitherTable {tag} = isLeft tag
199+isLeftTable EitherTable {tag = E tag} = isLeft tag
192
200
193
201
194-- | Test if an 'EitherTable' is a 'rightTable'.
202-- | Test if an 'EitherTable' is a 'rightTable'.
195isRightTable :: EitherTable Expr a b -> Expr Bool
203isRightTable :: EitherTable Expr a b -> Expr Bool
196−isRightTable EitherTable {tag} = isRight tag
204+isRightTable EitherTable {tag = E tag} = isRight tag
197
205
198
206
199-- | Pattern match/eliminate an 'EitherTable', by providing mappings from a
207-- | Pattern match/eliminate an 'EitherTable', by providing mappings from a
200-- 'leftTable' and 'rightTable'.
208-- 'leftTable' and 'rightTable'.
201eitherTable :: Table Expr c
209eitherTable :: Table Expr c
202 => (a -> c) -> (b -> c) -> EitherTable Expr a b -> c
210 => (a -> c) -> (b -> c) -> EitherTable Expr a b -> c
203−eitherTable f g EitherTable {tag, left, right} =
211+eitherTable f g EitherTable {tag = E tag, left, right} =
204 bool (f (extract left)) (g (extract right)) (isRight tag)
212 bool (f (extract left)) (g (extract right)) (isRight tag)
205
213
206
214
207-- | Construct a left 'EitherTable'. Like 'Left'.
215-- | Construct a left 'EitherTable'. Like 'Left'.
208leftTable :: Table Expr b => a -> EitherTable Expr a b
216leftTable :: Table Expr b => a -> EitherTable Expr a b
209−leftTable a = EitherTable (litExpr IsLeft) (pure a) undefined
217+leftTable a = EitherTable (E (litExpr IsLeft)) (pure a) undefined
210
218
211
219
212-- | Construct a right 'EitherTable'. Like 'Right'.
220-- | Construct a right 'EitherTable'. Like 'Right'.
213rightTable :: Table Expr a => b -> EitherTable Expr a b
221rightTable :: Table Expr a => b -> EitherTable Expr a b
214−rightTable = EitherTable (litExpr IsRight) undefined . pure
222+rightTable = EitherTable (E (litExpr IsRight)) undefined . pure
215
223
216
224
217-- | Lift a pair of aggregating functions to operate on an 'EitherTable'.
225-- | Lift a pair of aggregating functions to operate on an 'EitherTable'.
@@ -221,8 +229,8 @@ aggregateEitherTable :: ()
221 -> (exprs' -> aggregates')
229 -> (exprs' -> aggregates')
222 -> EitherTable Expr exprs exprs'
230 -> EitherTable Expr exprs exprs'
223 -> EitherTable Aggregate aggregates aggregates'
231 -> EitherTable Aggregate aggregates aggregates'
224−aggregateEitherTable f g (EitherTable tag a b) = EitherTable
232+aggregateEitherTable f g (EitherTable (E tag) a b) = EitherTable
225− { tag = groupByExpr tag
233+ { tag = A (groupByExpr tag)
226 , left = aggregateNullify f a
234 , left = aggregateNullify f a
227 , right = aggregateNullify g b
235 , right = aggregateNullify g b
228 }
236 }
@@ -240,4 +248,4 @@ nameEitherTable
240 -> b
248 -> b
241 -- ^ Names of the columns in the @b@ table.
249 -- ^ Names of the columns in the @b@ table.
242 -> EitherTable Name a b
250 -> EitherTable Name a b
243−nameEitherTable tag left right = EitherTable tag (pure left) (pure right)
251+nameEitherTable tag left right = EitherTable (N tag) (pure left) (pure right)
src/Rel8/Table/Eq.hs+39−12
@@ -11,6 +11,7 @@
11{-# language TypeFamilies #-}
11{-# language TypeFamilies #-}
12{-# language TypeOperators #-}
12{-# language TypeOperators #-}
13{-# language UndecidableInstances #-}
13{-# language UndecidableInstances #-}
14+{-# language UndecidableSuperClasses #-}
14{-# language ViewPatterns #-}
15{-# language ViewPatterns #-}
15
16
16module Rel8.Table.Eq
17module Rel8.Table.Eq
@@ -27,16 +28,24 @@ import GHC.Generics ( Rep )
27import Prelude
28import Prelude
28
29
29-- rel8
30-- rel8
30−import Rel8.Expr ( Expr )
31+import Rel8.Expr ( Expr, Col( E ) )
31import Rel8.Expr.Bool ( (||.), (&&.) )
32import Rel8.Expr.Bool ( (||.), (&&.) )
32import Rel8.Expr.Eq ( (==.), (/=.) )
33import Rel8.Expr.Eq ( (==.), (/=.) )
33import Rel8.FCF ( Eval, Exp )
34import Rel8.FCF ( Eval, Exp )
34import Rel8.Generic.Record ( Record )
35import Rel8.Generic.Record ( Record )
35−import Rel8.Generic.Table.Record ( GTable, GColumns, gtable )
36+import Rel8.Generic.Table
37+ ( GGTable, GGColumns, ggtable
38+ , GAlgebra
39+ )
40+import Rel8.Kind.Algebra ( KnownAlgebra )
36import Rel8.Schema.Dict ( Dict( Dict ) )
41import Rel8.Schema.Dict ( Dict( Dict ) )
37−import Rel8.Schema.HTable ( htabulateA, hfield )
42+import Rel8.Schema.HTable
43+ ( HTable, HConstrainTable
44+ , htabulateA, hfield, hdicts
45+ )
38−import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )
46+import Rel8.Schema.HTable.Identity ( HIdentity( HType ) )
39import Rel8.Schema.Null ( Sql )
47import Rel8.Schema.Null ( Sql )
48+import Rel8.Schema.Spec.Constrain ( ConstrainSpec )
40import Rel8.Table ( Table, Columns, toColumns, TColumns )
49import Rel8.Table ( Table, Columns, toColumns, TColumns )
41import Rel8.Type.Eq ( DBEq )
50import Rel8.Type.Eq ( DBEq )
42
51
@@ -46,14 +55,22 @@ import Rel8.Type.Eq ( DBEq )
46-- means "all columns in a 'Table' have an instance of 'DBEq'".
55-- means "all columns in a 'Table' have an instance of 'DBEq'".
47type EqTable :: Type -> Constraint
56type EqTable :: Type -> Constraint
48class Table Expr a => EqTable a where
57class Table Expr a => EqTable a where
49− eqTable :: Columns a (Dict (Sql DBEq))
58+ eqTable :: Columns a (Dict (ConstrainSpec (Sql DBEq)))
50
59
51 default eqTable ::
60 default eqTable ::
61+ ( KnownAlgebra (GAlgebra (Rep (Record a)))
52− ( GTable TEqTable TColumns (Rep (Record a))
62+ , Eval (GGTable (GAlgebra (Rep (Record a))) TEqTable TColumns (Dict (ConstrainSpec (Sql DBEq))) (Rep (Record a)))
53− , Columns a ~ GColumns TColumns (Rep (Record a))
63+ , Columns a ~ Eval (GGColumns (GAlgebra (Rep (Record a))) TColumns (Rep (Record a)))
54 )
64 )
55− => Columns a (Dict (Sql DBEq))
65+ => Columns a (Dict (ConstrainSpec (Sql DBEq)))
56− eqTable = gtable @TEqTable @TColumns @(Rep (Record a)) table
66+ eqTable =
67+ ggtable
68+ @(GAlgebra (Rep (Record a)))
69+ @TEqTable
70+ @TColumns
71+ @(Rep (Record a))
72+ table
73+ (\_ Dict -> Dict)
57 where
74 where
58 table (_ :: proxy x) = eqTable @x
75 table (_ :: proxy x) = eqTable @x
59
76
@@ -62,8 +79,18 @@ data TEqTable :: Type -> Exp Constraint
62type instance Eval (TEqTable a) = EqTable a
79type instance Eval (TEqTable a) = EqTable a
63
80
64
81
82+instance
83+ ( HTable t
84+ , f ~ Col Expr
85+ , HConstrainTable t (ConstrainSpec (Sql DBEq))
86+ )
87+ => EqTable (t f)
88+ where
89+ eqTable = hdicts @(Columns (t f)) @(ConstrainSpec (Sql DBEq))
90+
91+
65instance Sql DBEq a => EqTable (Expr a) where
92instance Sql DBEq a => EqTable (Expr a) where
66− eqTable = HIdentity Dict
93+ eqTable = HType Dict
67
94
68
95
69instance (EqTable a, EqTable b) => EqTable (a, b)
96instance (EqTable a, EqTable b) => EqTable (a, b)
@@ -97,7 +124,7 @@ instance
97(toColumns -> as) ==: (toColumns -> bs) =
124(toColumns -> as) ==: (toColumns -> bs) =
98 foldl1' (&&.) $ getConst $ htabulateA $ \field ->
125 foldl1' (&&.) $ getConst $ htabulateA $ \field ->
99 case (hfield as field, hfield bs field) of
126 case (hfield as field, hfield bs field) of
100− (a, b) -> case hfield (eqTable @a) field of
127+ (E a, E b) -> case hfield (eqTable @a) field of
101 Dict -> Const (pure (a ==. b))
128 Dict -> Const (pure (a ==. b))
102infix 4 ==:
129infix 4 ==:
103
130
@@ -109,7 +136,7 @@ infix 4 ==:
109(toColumns -> as) /=: (toColumns -> bs) =
136(toColumns -> as) /=: (toColumns -> bs) =
110 foldl1' (||.) $ getConst $ htabulateA $ \field ->
137 foldl1' (||.) $ getConst $ htabulateA $ \field ->
111 case (hfield as field, hfield bs field) of
138 case (hfield as field, hfield bs field) of
112− (a, b) -> case hfield (eqTable @a) field of
139+ (E a, E b) -> case hfield (eqTable @a) field of
113 Dict -> Const (pure (a /=. b))
140 Dict -> Const (pure (a /=. b))
114infix 4 /=:
141infix 4 /=:
115
142
src/Rel8/Table/HKD.hs+107−65
@@ -13,7 +13,7 @@
13
13
14module Rel8.Table.HKD
14module Rel8.Table.HKD
15 ( HKD( HKD )
15 ( HKD( HKD )
16− , HKDable
16+ , HKDable, fromHKD, toHKD, HKDT(..)
17 , BuildableHKD
17 , BuildableHKD
18 , BuildHKD, buildHKD
18 , BuildHKD, buildHKD
19 , ConstructableHKD
19 , ConstructableHKD
@@ -27,6 +27,9 @@ where
27
27
28-- base
28-- base
29import Data.Kind ( Constraint, Type )
29import Data.Kind ( Constraint, Type )
30+import Data.Proxy ( Proxy( Proxy ) )
31+import Data.Type.Equality ( (:~:)( Refl ) )
32+import Data.Void ( Void )
30import GHC.Generics ( Generic, Rep, from, to )
33import GHC.Generics ( Generic, Rep, from, to )
31import GHC.TypeLits ( Symbol )
34import GHC.TypeLits ( Symbol )
32import Prelude
35import Prelude
@@ -46,118 +49,131 @@ import Rel8.Generic.Construction
46 , GGName, ggname
49 , GGName, ggname
47 , GGAggregate, ggaggregate
50 , GGAggregate, ggaggregate
48 )
51 )
49−import Rel8.Generic.Map ( GMap )
52+import Rel8.Generic.Map ( GMap, GMappable, gmap, gunmap )
50−import Rel8.Generic.Record
51− ( GRecord, GRecordable, grecord, gunrecord
53+import Rel8.Generic.Record ( GRecord, GRecordable, grecord, gunrecord )
52− , Record( Record ), unrecord
53− )
54import Rel8.Generic.Rel8able
54import Rel8.Generic.Rel8able
55 ( Rel8able
55 ( Rel8able
56 , GColumns, gfromColumns, gtoColumns
56 , GColumns, gfromColumns, gtoColumns
57− , GFromExprs, gfromResult, gtoResult
57+ , greify, gunreify
58+ , TUnreifyContext
58 )
59 )
59import Rel8.Generic.Table
60import Rel8.Generic.Table
60− ( GGSerialize, GGColumns, GAlgebra, ggfromResult, ggtoResult
61+ ( GGTable, GGColumns, GGContext, ggfromColumns, ggtoColumns
62+ , GAlgebra
61 )
63 )
62−import Rel8.Generic.Table.Record ( GTable, GContext )
64+import Rel8.Schema.Context ( Col )
63−import qualified Rel8.Generic.Table.Record as G
64import qualified Rel8.Schema.Kind as K
65import qualified Rel8.Schema.Kind as K
65import Rel8.Schema.HTable ( HTable )
66import Rel8.Schema.HTable ( HTable )
66import Rel8.Schema.Name ( Name )
67import Rel8.Schema.Name ( Name )
68+import Rel8.Schema.Reify ( Col( Reify ), Reify, hreify, hunreify, notReify )
67import Rel8.Schema.Result ( Result )
69import Rel8.Schema.Result ( Result )
68import Rel8.Table
70import Rel8.Table
69− ( Table, fromColumns, toColumns, fromResult, toResult
71+ ( Table, Columns, Context, fromColumns, toColumns
72+ , Unreify, reify, unreify, coherence, congruence
70− , TTable, TColumns, TContext
73+ , TTable, TColumns, TUnreify
71− , TSerialize
72 )
74 )
75+import Rel8.Table.Serialize ( ToExprs, fromResult, toResult )
73
76
74
77
75type GColumnsHKD :: Type -> K.HTable
78type GColumnsHKD :: Type -> K.HTable
76type GColumnsHKD a =
79type GColumnsHKD a =
77− Eval (GGColumns (GAlgebra (Rep a)) TColumns (GRecord (GMap (TColumn Expr) (Rep a))))
80+ Eval (GGColumns (GAlgebra (Rep a)) TColumns (GRecord (GMap (TColumn (Reify Result)) (Rep a))))
78
81
79
82
80type HKD :: Type -> K.Rel8able
83type HKD :: Type -> K.Rel8able
81−newtype HKD a f = HKD (GColumnsHKD a f)
84+newtype HKD a f = HKD (GColumnsHKD a (Col f))
82
85
83
86
84instance HKDable a => Rel8able (HKD a) where
87instance HKDable a => Rel8able (HKD a) where
85 type GColumns (HKD a) = GColumnsHKD a
88 type GColumns (HKD a) = GColumnsHKD a
86− type GFromExprs (HKD a) = a
87
89
88− gfromColumns _ = HKD
90+ gfromColumns = HKD
89− gtoColumns _ (HKD a) = a
91+ gtoColumns (HKD a) = a
90
92
91− gfromResult =
93+ greify (HKD a) = HKD (hreify a)
92− unrecord .
94+ gunreify (HKD a) = HKD (hunreify a)
93− to .
94− ggfromResult
95− @(GAlgebra (Rep a))
96− @TSerialize
97− @TColumns
98− @(Eval (HKDRep a Expr))
99− @(Eval (HKDRep a Result))
100− (\(_ :: proxy x) -> fromResult @_ @x)
101−
102− gtoResult =
103− ggtoResult
104− @(GAlgebra (Rep a))
105− @TSerialize
106− @TColumns
107− @(Eval (HKDRep a Expr))
108− @(Eval (HKDRep a Result))
109− (\(_ :: proxy x) -> toResult @_ @x) .
110− from .
111− Record
112
95
113
96
114instance
97instance
98+ ( KnownAlgebra (GAlgebra (Rep a))
99+ , HTable (GColumnsHKD a)
115− ( GTable (TTable f) TColumns (GRecord (GMap (TColumn f) (Rep a)))
100+ , Eval (GGTable (GAlgebra (Rep a)) (TTable (Reify f)) TColumns (Col (Reify f)) (GRecord (GMap (TColumn (Reify f)) (Rep a))))
116− , G.GColumns TColumns (GRecord (GMap (TColumn f) (Rep a))) ~ GColumnsHKD a
101+ , Eval (GGColumns (GAlgebra (Rep a)) TColumns (GRecord (GMap (TColumn (Reify f)) (Rep a)))) ~ GColumnsHKD a
117− , GContext TContext (GRecord (GMap (TColumn f) (Rep a))) ~ f
102+ , Eval (GGContext (GAlgebra (Rep a)) TUnreifyContext (GRecord (GMap (TColumn (Reify f)) (Rep a)))) ~ f
118− , GRecordable (GMap (TColumn f) (Rep a))
103+ , GRecordable (GMap (TColumn (Reify f)) (Rep a))
104+ , GMappable (TTable (Reify f)) (GMap (TColumn (Reify f)) (Rep a))
105+ , GMap TUnreify (GMap (TColumn (Reify f)) (Rep a)) ~ GMap (TColumn f) (Rep a)
119 )
106 )
120 => Generic (HKD a f)
107 => Generic (HKD a f)
121 where
108 where
122 type Rep (HKD a f) = GMap (TColumn f) (Rep a)
109 type Rep (HKD a f) = GMap (TColumn f) (Rep a)
123
110
124 from =
111 from =
112+ gmap @(TTable (Reify f)) (Proxy @TUnreify) (unreify Refl) .
125− gunrecord @(GMap (TColumn f) (Rep a)) .
113+ gunrecord @(GMap (TColumn (Reify f)) (Rep a)) .
126− G.gfromColumns
114+ ggfromColumns
115+ @(GAlgebra (Rep a))
127− @(TTable f)
116+ @(TTable (Reify f))
128 @TColumns
117 @TColumns
118+ (\(Reify a) -> a)
119+ Reify
129 fromColumns .
120 fromColumns .
121+ hreify .
130 (\(HKD a) -> a)
122 (\(HKD a) -> a)
131
123
132 to =
124 to =
133 HKD .
125 HKD .
134− G.gtoColumns
126+ hunreify .
127+ ggtoColumns
128+ @(GAlgebra (Rep a))
135− @(TTable f)
129+ @(TTable (Reify f))
136 @TColumns
130 @TColumns
131+ (\(Reify a) -> a)
132+ Reify
137 toColumns .
133 toColumns .
138− grecord @(GMap (TColumn f) (Rep a))
134+ grecord @(GMap (TColumn (Reify f)) (Rep a)) .
135+ gunmap @(TTable (Reify f)) (Proxy @TUnreify) (reify Refl)
136+
137+
138+type HKDT :: Type -> Type
139+newtype HKDT a = HKDT
140+ { unHKDT :: a
141+ }
142+
143+
144+instance HKDable a => Table Result (HKDT a) where
145+ type Columns (HKDT a) = GColumnsHKD a
146+ type Context (HKDT a) = Result
147+ type Unreify (HKDT a) = Void
148+
149+ fromColumns = HKDT . fromHKD . HKD
150+ toColumns = (\(HKD a) -> a) . toHKD . (\(HKDT a) -> a)
151+ reify = notReify
152+ unreify = notReify
153+ coherence = notReify
154+ congruence = notReify
139
155
140
156
141−type HKDable :: Type -> Constraint
142−class
143− ( Generic (Record a)
144− , HTable (GColumns (HKD a))
145− , KnownAlgebra (GAlgebra (Rep a))
146− , Eval (GGSerialize (GAlgebra (Rep a)) TSerialize TColumns (Eval (HKDRep a Expr)) (Eval (HKDRep a Result)))
147− , GRecord (GMap (TColumn Result) (Rep a)) ~ Rep (Record a)
148− )
149− => HKDable a
150instance
157instance
151− ( Generic (Record a)
158+ ( Table Expr (HKD a Expr)
152− , HTable (GColumns (HKD a))
159+ , Columns (HKD a Expr) ~ GColumns (HKD a)
153− , KnownAlgebra (GAlgebra (Rep a))
160+ , HKDable a
154− , Eval (GGSerialize (GAlgebra (Rep a)) TSerialize TColumns (Eval (HKDRep a Expr)) (Eval (HKDRep a Result)))
161+ , x ~ HKD a Expr
155− , GRecord (GMap (TColumn Result) (Rep a)) ~ Rep (Record a)
156 )
162 )
163+ => ToExprs x (HKDT a)
164+ where
165+ toResult = (\(HKD a) -> a) . toHKD . (\(HKDT a) -> a)
166+ fromResult = HKDT . fromHKD . HKD
167+
168+
157− => HKDable a
169+fromHKD :: HKDable a => HKD a Result -> a
170+fromHKD = to . gunmap @Top (Proxy @(TColumn Result)) id . from
171+
172+
173+toHKD :: HKDable a => a -> HKD a Result
174+toHKD = to . gmap @Top (Proxy @(TColumn Result)) id . from
158
175
159
176
160−type Top_ :: Constraint
161class Top_
177class Top_
162instance Top_
178instance Top_
163
179
@@ -166,6 +182,32 @@ data Top :: Type -> Exp Constraint
166type instance Eval (Top _) = Top_
182type instance Eval (Top _) = Top_
167
183
168
184
185+class
186+ ( Generic a
187+ , HTable (GColumns (HKD a))
188+ , KnownAlgebra (GAlgebra (Rep a))
189+ , Eval (GGTable (GAlgebra (Rep a)) (TTable (Reify Result)) TColumns (Col (Reify Result)) (GRecord (GMap (TColumn (Reify Result)) (Rep a))))
190+ , Eval (GGContext (GAlgebra (Rep a)) TUnreifyContext (GRecord (GMap (TColumn (Reify Result)) (Rep a)))) ~ Result
191+ , GRecordable (GMap (TColumn (Reify Result)) (Rep a))
192+ , GMappable Top (Rep a)
193+ , GMappable (TTable (Reify Result)) (GMap (TColumn (Reify Result)) (Rep a))
194+ , GMap TUnreify (GMap (TColumn (Reify Result)) (Rep a)) ~ GMap (TColumn Result) (Rep a)
195+ )
196+ => HKDable a
197+instance
198+ ( Generic a
199+ , HTable (GColumns (HKD a))
200+ , KnownAlgebra (GAlgebra (Rep a))
201+ , Eval (GGTable (GAlgebra (Rep a)) (TTable (Reify Result)) TColumns (Col (Reify Result)) (GRecord (GMap (TColumn (Reify Result)) (Rep a))))
202+ , Eval (GGContext (GAlgebra (Rep a)) TUnreifyContext (GRecord (GMap (TColumn (Reify Result)) (Rep a)))) ~ Result
203+ , GRecordable (GMap (TColumn (Reify Result)) (Rep a))
204+ , GMappable Top (Rep a)
205+ , GMappable (TTable (Reify Result)) (GMap (TColumn (Reify Result)) (Rep a))
206+ , GMap TUnreify (GMap (TColumn (Reify Result)) (Rep a)) ~ GMap (TColumn Result) (Rep a)
207+ )
208+ => HKDable a
209+
210+
169type BuildableHKD :: Type -> Symbol -> Constraint
211type BuildableHKD :: Type -> Symbol -> Constraint
170class GGBuildable (GAlgebra (Rep a)) name (HKDRep a) => BuildableHKD a name
212class GGBuildable (GAlgebra (Rep a)) name (HKDRep a) => BuildableHKD a name
171instance GGBuildable (GAlgebra (Rep a)) name (HKDRep a) => BuildableHKD a name
213instance GGBuildable (GAlgebra (Rep a)) name (HKDRep a) => BuildableHKD a name
src/Rel8/Table/List.hs+55−43
@@ -11,36 +11,32 @@
11
11
12module Rel8.Table.List
12module Rel8.Table.List
13 ( ListTable(..)
13 ( ListTable(..)
14− , ($*)
15− , listTable
16− , nameListTable
14+ , listTable, nameListTable
17 )
15 )
18where
16where
19
17
20-- base
18-- base
19+import Control.Category ( id )
21import Data.Functor.Identity ( Identity( Identity ) )
20import Data.Functor.Identity ( Identity( Identity ) )
22import Data.Kind ( Type )
21import Data.Kind ( Type )
22+import Data.Type.Equality ( (:~:)( Refl ), apply )
23−import Prelude
23+import Prelude hiding ( id )
24
24
25-- rel8
25-- rel8
26−import Rel8.Expr ( Expr )
26+import Rel8.Expr ( Expr, Col( E, unE ) )
27import Rel8.Expr.Array ( sappend, sempty, slistOf )
27import Rel8.Expr.Array ( sappend, sempty, slistOf )
28+import Rel8.Schema.Context.Abstract ( Abstract, exclusivity, virtual )
28import Rel8.Schema.Dict ( Dict( Dict ) )
29import Rel8.Schema.Dict ( Dict( Dict ) )
29import Rel8.Schema.HTable.List ( HListTable )
30import Rel8.Schema.HTable.List ( HListTable )
30−import Rel8.Schema.HTable.Vectorize
31+import Rel8.Schema.HTable.Vectorize ( happend, hempty, hvectorize )
31− ( hvectorize, hunvectorize
32− , happend, hempty
33− , hproject, hcolumn
34− )
35import qualified Rel8.Schema.Kind as K
32import qualified Rel8.Schema.Kind as K
36−import Rel8.Schema.Name ( Name( Name ) )
33+import Rel8.Schema.Name ( Col( N ), Name( Name ) )
37import Rel8.Schema.Null ( Nullity( Null, NotNull ) )
34import Rel8.Schema.Null ( Nullity( Null, NotNull ) )
38−import Rel8.Schema.Result ( vectorizer, unvectorizer )
35+import Rel8.Schema.Spec ( SSpec(..) )
39−import Rel8.Schema.Spec ( Spec(..) )
36+import Rel8.Schema.Reify ( hreify, hunreify )
40import Rel8.Table
37import Rel8.Table
41 ( Table, Context, Columns, fromColumns, toColumns
38 ( Table, Context, Columns, fromColumns, toColumns
42− , FromExprs, fromResult, toResult
39+ , reify, unreify, coherence, congruence
43− , Transpose
44 )
40 )
45import Rel8.Table.Alternative
41import Rel8.Table.Alternative
46 ( AltTable, (<|>:)
42 ( AltTable, (<|>:)
@@ -48,41 +44,56 @@ import Rel8.Table.Alternative
48 )
44 )
49import Rel8.Table.Eq ( EqTable, eqTable )
45import Rel8.Table.Eq ( EqTable, eqTable )
50import Rel8.Table.Ord ( OrdTable, ordTable )
46import Rel8.Table.Ord ( OrdTable, ordTable )
51−import Rel8.Table.Projection
47+import Rel8.Table.Recontextualize ( Recontextualize )
52− ( Projectable, Projecting, Projection, project, apply
53− )
54−import Rel8.Table.Serialize ( ToExprs )
48+import Rel8.Table.Serialize ( FromExprs, ToExprs, fromResult, toResult )
55
49
56
50
57-- | A @ListTable@ value contains zero or more instances of @a@. You construct
51-- | A @ListTable@ value contains zero or more instances of @a@. You construct
58-- @ListTable@s with 'Rel8.many' or 'Rel8.listAgg'.
52-- @ListTable@s with 'Rel8.many' or 'Rel8.listAgg'.
59type ListTable :: K.Context -> Type -> Type
53type ListTable :: K.Context -> Type -> Type
60newtype ListTable context a =
54newtype ListTable context a =
61− ListTable (HListTable (Columns a) (Context a))
55+ ListTable (HListTable (Columns a) (Col (Context a)))
62−
63−
64−instance Projectable (ListTable context) where
65− project f (ListTable a) = ListTable (hproject (apply f) a)
66
56
67
57
68−instance (Table context a, context ~ context') =>
58+instance (Table context a, Abstract context, context ~ context') =>
69 Table context' (ListTable context a)
59 Table context' (ListTable context a)
70 where
60 where
71 type Columns (ListTable context a) = HListTable (Columns a)
61 type Columns (ListTable context a) = HListTable (Columns a)
72 type Context (ListTable context a) = Context a
62 type Context (ListTable context a) = Context a
73− type FromExprs (ListTable context a) = [FromExprs a]
74− type Transpose to (ListTable context a) = ListTable to (Transpose to a)
75
63
76 fromColumns = ListTable
64 fromColumns = ListTable
77 toColumns (ListTable a) = a
65 toColumns (ListTable a) = a
78− fromResult = fmap (fromResult @_ @a) . hunvectorize unvectorizer
66+
79− toResult = hvectorize vectorizer . fmap (toResult @_ @a)
67+ reify proof@Refl (ListTable a) =
68+ case coherence @context @a proof abstract of
69+ Refl -> case congruence @context @a proof abstract of
70+ Refl -> ListTable (hreify a)
71+ where
72+ abstract = exclusivity virtual
73+
74+ unreify proof@Refl (ListTable a) =
75+ case coherence @context @a proof abstract of
76+ Refl -> case congruence @context @a proof abstract of
77+ Refl -> ListTable (hunreify a)
78+ where
79+ abstract = exclusivity virtual
80+
81+ coherence = coherence @context @a
82+ congruence proof abstract = id `apply` congruence @context @a proof abstract
83+
84+
85+instance
86+ ( Recontextualize from to a b
87+ , Abstract from, from ~ from'
88+ , Abstract to, to ~ to'
89+ )
90+ => Recontextualize from to (ListTable from' a) (ListTable to' b)
80
91
81
92
82instance (EqTable a, context ~ Expr) => EqTable (ListTable context a) where
93instance (EqTable a, context ~ Expr) => EqTable (ListTable context a) where
83 eqTable =
94 eqTable =
84 hvectorize
95 hvectorize
85− (\Spec {nullity} (Identity Dict) -> case nullity of
96+ (\SSpec {nullity} (Identity Dict) -> case nullity of
86 Null -> Dict
97 Null -> Dict
87 NotNull -> Dict)
98 NotNull -> Dict)
88 (Identity (eqTable @a))
99 (Identity (eqTable @a))
@@ -91,14 +102,20 @@ instance (EqTable a, context ~ Expr) => EqTable (ListTable context a) where
91instance (OrdTable a, context ~ Expr) => OrdTable (ListTable context a) where
102instance (OrdTable a, context ~ Expr) => OrdTable (ListTable context a) where
92 ordTable =
103 ordTable =
93 hvectorize
104 hvectorize
94− (\Spec {nullity} (Identity Dict) -> case nullity of
105+ (\SSpec {nullity} (Identity Dict) -> case nullity of
95 Null -> Dict
106 Null -> Dict
96 NotNull -> Dict)
107 NotNull -> Dict)
97 (Identity (ordTable @a))
108 (Identity (ordTable @a))
98
109
99
110
111+type instance FromExprs (ListTable _context a) = [FromExprs a]
112+
113+
100instance (ToExprs exprs a, context ~ Expr) =>
114instance (ToExprs exprs a, context ~ Expr) =>
101 ToExprs (ListTable context exprs) [a]
115 ToExprs (ListTable context exprs) [a]
116+ where
117+ fromResult = fmap (fromResult @exprs) . fromColumns
118+ toResult = toColumns . fmap (toResult @exprs)
102
119
103
120
104instance context ~ Expr => AltTable (ListTable context) where
121instance context ~ Expr => AltTable (ListTable context) where
@@ -109,29 +126,24 @@ instance context ~ Expr => AlternativeTable (ListTable context) where
109 emptyTable = mempty
126 emptyTable = mempty
110
127
111
128
112−instance (context ~ Expr, Table Expr a) => Semigroup (ListTable context a)
129+instance (context ~ Expr, Table Expr a) =>
130+ Semigroup (ListTable context a)
113 where
131 where
114− ListTable as <> ListTable bs = ListTable $ happend (const sappend) as bs
132+ ListTable as <> ListTable bs = ListTable $
133+ happend (\_ _ (E a) (E b) -> E (sappend a b)) as bs
115
134
116
135
117instance (context ~ Expr, Table Expr a) =>
136instance (context ~ Expr, Table Expr a) =>
118 Monoid (ListTable context a)
137 Monoid (ListTable context a)
119 where
138 where
120− mempty = ListTable $ hempty $ \Spec {info} -> sempty info
139+ mempty = ListTable $ hempty $ \_ -> E . sempty
121−
122−
123−-- | Project a single expression out of a 'ListTable'.
124−($*) :: Projecting a (Expr b)
125− => Projection a (Expr b) -> ListTable Expr a -> Expr [b]
126−f $* ListTable a = hcolumn $ hproject (apply f) a
127−infixl 4 $*
128
140
129
141
130-- | Construct a @ListTable@ from a list of expressions.
142-- | Construct a @ListTable@ from a list of expressions.
131listTable :: Table Expr a => [a] -> ListTable Expr a
143listTable :: Table Expr a => [a] -> ListTable Expr a
132listTable =
144listTable =
133 ListTable .
145 ListTable .
134− hvectorize (\Spec {info} -> slistOf info) .
146+ hvectorize (\SSpec {info} -> E . slistOf info . fmap unE) .
135 fmap toColumns
147 fmap toColumns
136
148
137
149
@@ -144,6 +156,6 @@ nameListTable
144 -> ListTable Name a
156 -> ListTable Name a
145nameListTable =
157nameListTable =
146 ListTable .
158 ListTable .
147− hvectorize (\_ (Identity (Name a)) -> Name a) .
159+ hvectorize (\_ (Identity (N (Name a))) -> N (Name a)) .
148 pure .
160 pure .
149 toColumns
161 toColumns
src/Rel8/Table/Maybe.hs+49−48
@@ -15,7 +15,6 @@ module Rel8.Table.Maybe
15 ( MaybeTable(..)
15 ( MaybeTable(..)
16 , maybeTable, nothingTable, justTable
16 , maybeTable, nothingTable, justTable
17 , isNothingTable, isJustTable
17 , isNothingTable, isJustTable
18− , fromMaybeTable
19 , ($?)
18 , ($?)
20 , aggregateMaybeTable
19 , aggregateMaybeTable
21 , nameMaybeTable
20 , nameMaybeTable
@@ -23,34 +22,35 @@ module Rel8.Table.Maybe
23where
22where
24
23
25-- base
24-- base
26−import Data.Functor ( ($>) )
25+import Control.Category ( id )
27−import Data.Functor.Identity ( Identity( Identity ) )
28import Data.Kind ( Type )
26import Data.Kind ( Type )
29−import Data.Maybe ( fromMaybe, isJust )
27+import Data.Maybe ( isJust )
28+import Data.Type.Equality ( apply )
30−import Prelude hiding ( null, undefined )
29+import Prelude hiding ( id, null, undefined )
31
30
32-- comonad
31-- comonad
33import Control.Comonad ( extract )
32import Control.Comonad ( extract )
34
33
35-- rel8
34-- rel8
36−import Rel8.Aggregate ( Aggregate )
35+import Rel8.Aggregate ( Col( A ), Aggregate )
37−import Rel8.Expr ( Expr )
36+import Rel8.Expr ( Col( E ), Expr )
38import Rel8.Expr.Aggregate ( groupByExpr )
37import Rel8.Expr.Aggregate ( groupByExpr )
39import Rel8.Expr.Bool ( boolExpr )
38import Rel8.Expr.Bool ( boolExpr )
40import Rel8.Expr.Null ( isNull, isNonNull, null, nullify )
39import Rel8.Expr.Null ( isNull, isNonNull, null, nullify )
41import Rel8.Kind.Context ( Reifiable )
40import Rel8.Kind.Context ( Reifiable )
41+import Rel8.Schema.Context.Abstract ( Abstract )
42import Rel8.Schema.Dict ( Dict( Dict ) )
42import Rel8.Schema.Dict ( Dict( Dict ) )
43import qualified Rel8.Schema.Kind as K
43import qualified Rel8.Schema.Kind as K
44import Rel8.Schema.HTable.Identity ( HIdentity(..) )
44import Rel8.Schema.HTable.Identity ( HIdentity(..) )
45import Rel8.Schema.HTable.Label ( hlabel, hunlabel )
45import Rel8.Schema.HTable.Label ( hlabel, hunlabel )
46import Rel8.Schema.HTable.Maybe ( HMaybeTable(..) )
46import Rel8.Schema.HTable.Maybe ( HMaybeTable(..) )
47−import Rel8.Schema.Name ( Name )
47+import Rel8.Schema.Name ( Col( N ), Name )
48import Rel8.Schema.Null ( Nullity( Null, NotNull ), Sql, nullable )
48import Rel8.Schema.Null ( Nullity( Null, NotNull ), Sql, nullable )
49import qualified Rel8.Schema.Null as N
49import qualified Rel8.Schema.Null as N
50+import Rel8.Schema.Spec ( Spec( Spec ) )
50import Rel8.Table
51import Rel8.Table
51 ( Table, Columns, Context, fromColumns, toColumns
52 ( Table, Columns, Context, fromColumns, toColumns
52− , FromExprs, fromResult, toResult
53+ , coherence, congruence, reify, unreify
53− , Transpose
54 )
54 )
55import Rel8.Table.Alternative
55import Rel8.Table.Alternative
56 ( AltTable, (<|>:)
56 ( AltTable, (<|>:)
@@ -59,12 +59,12 @@ import Rel8.Table.Alternative
59import Rel8.Table.Bool ( bool )
59import Rel8.Table.Bool ( bool )
60import Rel8.Table.Eq ( EqTable, eqTable )
60import Rel8.Table.Eq ( EqTable, eqTable )
61import Rel8.Table.Ord ( OrdTable, ordTable )
61import Rel8.Table.Ord ( OrdTable, ordTable )
62−import Rel8.Table.Projection ( Projectable, project )
63import Rel8.Table.Nullify ( Nullify, aggregateNullify, guard )
62import Rel8.Table.Nullify ( Nullify, aggregateNullify, guard )
64−import Rel8.Table.Serialize ( ToExprs )
63+import Rel8.Table.Recontextualize ( Recontextualize )
64+import Rel8.Table.Serialize ( FromExprs, ToExprs, fromResult, toResult )
65import Rel8.Table.Undefined ( undefined )
65import Rel8.Table.Undefined ( undefined )
66import Rel8.Type ( DBType )
66import Rel8.Type ( DBType )
67−import Rel8.Type.Tag ( MaybeTag( IsJust ) )
67+import Rel8.Type.Tag ( MaybeTag )
68
68
69-- semigroupoids
69-- semigroupoids
70import Data.Functor.Apply ( Apply, (<.>) )
70import Data.Functor.Apply ( Apply, (<.>) )
@@ -81,18 +81,15 @@ import Data.Functor.Bind ( Bind, (>>-) )
81-- a "nullTag" - to track whether or not the outer join produced any rows.
81-- a "nullTag" - to track whether or not the outer join produced any rows.
82type MaybeTable :: K.Context -> Type -> Type
82type MaybeTable :: K.Context -> Type -> Type
83data MaybeTable context a = MaybeTable
83data MaybeTable context a = MaybeTable
84− { tag :: context (Maybe MaybeTag)
84+ { tag :: Col context ('Spec (Maybe MaybeTag))
85 , just :: Nullify context a
85 , just :: Nullify context a
86 }
86 }
87 deriving stock Functor
87 deriving stock Functor
88
88
89
89
90−instance Projectable (MaybeTable context) where
91− project f (MaybeTable tag a) = MaybeTable tag (project f a)
92−
93−
94instance context ~ Expr => Apply (MaybeTable context) where
90instance context ~ Expr => Apply (MaybeTable context) where
95− MaybeTable tag f <.> MaybeTable tag' a = MaybeTable (tag <> tag') (f <.> a)
91+ MaybeTable (E tag) f <.> MaybeTable (E tag') a =
92+ MaybeTable (E (tag <> tag')) (f <.> a)
96
93
97
94
98-- | Has the same behavior as the @Applicative@ instance for @Maybe@. See also:
95-- | Has the same behavior as the @Applicative@ instance for @Maybe@. See also:
@@ -103,8 +100,8 @@ instance context ~ Expr => Applicative (MaybeTable context) where
103
100
104
101
105instance context ~ Expr => Bind (MaybeTable context) where
102instance context ~ Expr => Bind (MaybeTable context) where
106− MaybeTable tag a >>- f = case f (extract a) of
103+ MaybeTable (E tag) a >>- f = case f (extract a) of
107− MaybeTable tag' b -> MaybeTable (tag <> tag') b
104+ MaybeTable (E tag') b -> MaybeTable (E (tag <> tag')) b
108
105
109
106
110-- | Has the same behavior as the @Monad@ instance for @Maybe@.
107-- | Has the same behavior as the @Monad@ instance for @Maybe@.
@@ -132,13 +129,14 @@ instance (context ~ Expr, Table Expr a, Semigroup a) =>
132 mempty = nothingTable
129 mempty = nothingTable
133
130
134
131
132+instance
133+ ( Table context a
135−instance (Table context a, Reifiable context, context ~ context') =>
134+ , Reifiable context, Abstract context, context ~ context'
135+ )
136− Table context' (MaybeTable context a)
136+ => Table context' (MaybeTable context a)
137 where
137 where
138 type Columns (MaybeTable context a) = HMaybeTable (Columns a)
138 type Columns (MaybeTable context a) = HMaybeTable (Columns a)
139 type Context (MaybeTable context a) = Context a
139 type Context (MaybeTable context a) = Context a
140− type FromExprs (MaybeTable context a) = Maybe (FromExprs a)
141− type Transpose to (MaybeTable context a) = MaybeTable to (Transpose to a)
142
140
143 toColumns MaybeTable {tag, just} = HMaybeTable
141 toColumns MaybeTable {tag, just} = HMaybeTable
144 { htag = hlabel $ HIdentity tag
142 { htag = hlabel $ HIdentity tag
@@ -150,44 +148,52 @@ instance (Table context a, Reifiable context, context ~ context') =>
150 , just = fromColumns $ hunlabel hjust
148 , just = fromColumns $ hunlabel hjust
151 }
149 }
152
150
153− toResult ma = HMaybeTable
151+ reify proof (MaybeTable tag a) = MaybeTable tag (reify proof a)
154− { htag = hlabel (HIdentity (Identity (IsJust <$ ma)))
152+ unreify proof (MaybeTable tag a) = MaybeTable tag (unreify proof a)
155− , hjust = hlabel (toResult @_ @(Nullify context a) ma)
153+ coherence = coherence @context @a
156− }
154+ congruence proof abstract = id `apply` congruence @context @a proof abstract
155+
157
156
158− fromResult HMaybeTable {htag, hjust} = case hunlabel htag of
157+instance
159− HIdentity (Identity tag) -> tag $>
158+ ( Recontextualize from to a b
160− fromMaybe err (fromResult @_ @(Nullify context a) (hunlabel hjust))
159+ , Reifiable from, Abstract from, from ~ from'
161− where
160+ , Reifiable to, Abstract to, to ~ to'
162− err = error "Maybe.fromColumns: mismatch between tag and data"
161+ )
162+ => Recontextualize from to (MaybeTable from' a) (MaybeTable to' b)
163
163
164
164
165instance (EqTable a, context ~ Expr) => EqTable (MaybeTable context a) where
165instance (EqTable a, context ~ Expr) => EqTable (MaybeTable context a) where
166 eqTable = HMaybeTable
166 eqTable = HMaybeTable
167− { htag = hlabel (HIdentity Dict)
167+ { htag = hlabel (HType Dict)
168 , hjust = hlabel (eqTable @(Nullify context a))
168 , hjust = hlabel (eqTable @(Nullify context a))
169 }
169 }
170
170
171
171
172instance (OrdTable a, context ~ Expr) => OrdTable (MaybeTable context a) where
172instance (OrdTable a, context ~ Expr) => OrdTable (MaybeTable context a) where
173 ordTable = HMaybeTable
173 ordTable = HMaybeTable
174− { htag = hlabel (HIdentity Dict)
174+ { htag = hlabel (HType Dict)
175 , hjust = hlabel (ordTable @(Nullify context a))
175 , hjust = hlabel (ordTable @(Nullify context a))
176 }
176 }
177
177
178
178
179+type instance FromExprs (MaybeTable _context a) = Maybe (FromExprs a)
180+
181+
179instance (ToExprs exprs a, context ~ Expr) =>
182instance (ToExprs exprs a, context ~ Expr) =>
180 ToExprs (MaybeTable context exprs) (Maybe a)
183 ToExprs (MaybeTable context exprs) (Maybe a)
184+ where
185+ fromResult = fmap (fromResult @exprs) . fromColumns
186+ toResult = toColumns . fmap (toResult @exprs)
181
187
182
188
183-- | Check if a @MaybeTable@ is absent of any row. Like 'Data.Maybe.isNothing'.
189-- | Check if a @MaybeTable@ is absent of any row. Like 'Data.Maybe.isNothing'.
184isNothingTable :: MaybeTable Expr a -> Expr Bool
190isNothingTable :: MaybeTable Expr a -> Expr Bool
185−isNothingTable (MaybeTable tag _) = isNull tag
191+isNothingTable (MaybeTable (E tag) _) = isNull tag
186
192
187
193
188-- | Check if a @MaybeTable@ contains a row. Like 'Data.Maybe.isJust'.
194-- | Check if a @MaybeTable@ contains a row. Like 'Data.Maybe.isJust'.
189isJustTable :: MaybeTable Expr a -> Expr Bool
195isJustTable :: MaybeTable Expr a -> Expr Bool
190−isJustTable (MaybeTable tag _) = isNonNull tag
196+isJustTable (MaybeTable (E tag) _) = isNonNull tag
191
197
192
198
193-- | Perform case analysis on a 'MaybeTable'. Like 'maybe'.
199-- | Perform case analysis on a 'MaybeTable'. Like 'maybe'.
@@ -198,18 +204,13 @@ maybeTable b f ma@(MaybeTable _ a) = bool (f (extract a)) b (isNothingTable ma)
198
204
199-- | The null table. Like 'Nothing'.
205-- | The null table. Like 'Nothing'.
200nothingTable :: Table Expr a => MaybeTable Expr a
206nothingTable :: Table Expr a => MaybeTable Expr a
201−nothingTable = MaybeTable null (pure undefined)
207+nothingTable = MaybeTable (E null) (pure undefined)
202
208
203
209
204-- | Lift any table into 'MaybeTable'. Like 'Just'. Note you can also use
210-- | Lift any table into 'MaybeTable'. Like 'Just'. Note you can also use
205-- 'pure'.
211-- 'pure'.
206justTable :: a -> MaybeTable Expr a
212justTable :: a -> MaybeTable Expr a
207−justTable = MaybeTable mempty . pure
213+justTable = MaybeTable (E mempty) . pure
208−
209−
210−-- | 'Data.Maybe.fromMaybe' for 'MaybeTable's.
211−fromMaybeTable :: Table Expr a => a -> MaybeTable Expr a -> a
212−fromMaybeTable fallback = maybeTable fallback id
213
214
214
215
215-- | Project a single expression out of a 'MaybeTable'. You can think of this
216-- | Project a single expression out of a 'MaybeTable'. You can think of this
@@ -229,8 +230,8 @@ aggregateMaybeTable :: ()
229 => (exprs -> aggregates)
230 => (exprs -> aggregates)
230 -> MaybeTable Expr exprs
231 -> MaybeTable Expr exprs
231 -> MaybeTable Aggregate aggregates
232 -> MaybeTable Aggregate aggregates
232−aggregateMaybeTable f (MaybeTable tag a) =
233+aggregateMaybeTable f (MaybeTable (E tag) a) =
233− MaybeTable (groupByExpr tag) (aggregateNullify f a)
234+ MaybeTable (A (groupByExpr tag)) (aggregateNullify f a)
234
235
235
236
236-- | Construct a 'MaybeTable' in the 'Name' context. This can be useful if you
237-- | Construct a 'MaybeTable' in the 'Name' context. This can be useful if you
@@ -243,4 +244,4 @@ nameMaybeTable
243 -> a
244 -> a
244 -- ^ Names of the columns in @a@.
245 -- ^ Names of the columns in @a@.
245 -> MaybeTable Name a
246 -> MaybeTable Name a
246−nameMaybeTable tag = MaybeTable tag . pure
247+nameMaybeTable tag = MaybeTable (N tag) . pure
src/Rel8/Table/Name.hs+20−11
@@ -1,17 +1,14 @@
1−{-# language DataKinds #-}
2{-# language FlexibleContexts #-}
1{-# language FlexibleContexts #-}
3−{-# language FlexibleInstances #-}
4−{-# language MultiParamTypeClasses #-}
5{-# language NamedFieldPuns #-}
2{-# language NamedFieldPuns #-}
6{-# language ScopedTypeVariables #-}
3{-# language ScopedTypeVariables #-}
7{-# language TypeApplications #-}
4{-# language TypeApplications #-}
8{-# language TypeFamilies #-}
5{-# language TypeFamilies #-}
9−{-# language UndecidableInstances #-}
10{-# language ViewPatterns #-}
6{-# language ViewPatterns #-}
11
7
12module Rel8.Table.Name
8module Rel8.Table.Name
13 ( namesFromLabels
9 ( namesFromLabels
14 , namesFromLabelsWith
10 , namesFromLabelsWith
11+ , showExprs
15 , showLabels
12 , showLabels
16 , showNames
13 , showNames
17 )
14 )
@@ -24,11 +21,16 @@ import Data.List.NonEmpty ( NonEmpty, intersperse, nonEmpty )
24import Data.Maybe ( fromMaybe )
21import Data.Maybe ( fromMaybe )
25import Prelude
22import Prelude
26
23
24+-- opaleye
25+import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
26+
27-- rel8
27-- rel8
28+import Rel8.Expr ( Expr, Col( E ) )
29+import Rel8.Expr.Opaleye ( toPrimExpr )
28import Rel8.Schema.HTable ( htabulate, htabulateA, hfield, hspecs )
30import Rel8.Schema.HTable ( htabulate, htabulateA, hfield, hspecs )
29−import Rel8.Schema.Name ( Name( Name ) )
31+import Rel8.Schema.Name ( Name( Name ), Col( N ) )
30−import Rel8.Schema.Spec ( Spec(..) )
32+import Rel8.Schema.Spec ( SSpec(..) )
31−import Rel8.Table ( Table(..) )
33+import Rel8.Table ( Table, Columns, Context, fromColumns, toColumns )
32
34
33
35
34-- | Construct a table in the 'Name' context containing the names of all
36-- | Construct a table in the 'Name' context containing the names of all
@@ -60,19 +62,26 @@ namesFromLabelsWith :: Table Name a
60 => (NonEmpty String -> String) -> a
62 => (NonEmpty String -> String) -> a
61namesFromLabelsWith f = fromColumns $ htabulate $ \field ->
63namesFromLabelsWith f = fromColumns $ htabulate $ \field ->
62 case hfield hspecs field of
64 case hfield hspecs field of
63− Spec {labels} -> Name (f (renderLabels labels))
65+ SSpec {labels} -> N (Name (f (renderLabels labels)))
66+
67+
68+showExprs :: Table Expr a => a -> [(String, Opaleye.PrimExpr)]
69+showExprs as = case (namesFromLabels, toColumns as) of
70+ (names, exprs) -> getConst $ htabulateA $ \field ->
71+ case (hfield names field, hfield exprs field) of
72+ (N (Name name), E expr) -> Const [(name, toPrimExpr expr)]
64
73
65
74
66showLabels :: forall a. Table (Context a) a => a -> [NonEmpty String]
75showLabels :: forall a. Table (Context a) a => a -> [NonEmpty String]
67showLabels _ = getConst $
76showLabels _ = getConst $
68 htabulateA @(Columns a) $ \field -> case hfield hspecs field of
77 htabulateA @(Columns a) $ \field -> case hfield hspecs field of
69− Spec {labels} -> Const (pure (renderLabels labels))
78+ SSpec {labels} -> Const [renderLabels labels]
70
79
71
80
72−showNames :: forall a. Table Name a => a -> NonEmpty String
81+showNames :: forall a. Table Name a => a -> [String]
73showNames (toColumns -> names) = getConst $
82showNames (toColumns -> names) = getConst $
74 htabulateA @(Columns a) $ \field -> case hfield names field of
83 htabulateA @(Columns a) $ \field -> case hfield names field of
75− Name name -> Const (pure name)
84+ N (Name name) -> Const [name]
76
85
77
86
78renderLabels :: [String] -> NonEmpty String
87renderLabels :: [String] -> NonEmpty String
src/Rel8/Table/NonEmpty.hs+52−42
@@ -11,71 +11,81 @@
11
11
12module Rel8.Table.NonEmpty
12module Rel8.Table.NonEmpty
13 ( NonEmptyTable(..)
13 ( NonEmptyTable(..)
14− , ($+)
15− , nonEmptyTable
16− , nameNonEmptyTable
14+ , nonEmptyTable, nameNonEmptyTable
17 )
15 )
18where
16where
19
17
20-- base
18-- base
19+import Control.Category ( id )
21import Data.Functor.Identity ( Identity( Identity ) )
20import Data.Functor.Identity ( Identity( Identity ) )
22import Data.Kind ( Type )
21import Data.Kind ( Type )
23import Data.List.NonEmpty ( NonEmpty )
22import Data.List.NonEmpty ( NonEmpty )
23+import Data.Type.Equality ( (:~:)( Refl ), apply )
24import Prelude hiding ( id )
24import Prelude hiding ( id )
25
25
26-- rel8
26-- rel8
27−import Rel8.Expr ( Expr )
27+import Rel8.Expr ( Expr, Col( E, unE ) )
28import Rel8.Expr.Array ( sappend1, snonEmptyOf )
28import Rel8.Expr.Array ( sappend1, snonEmptyOf )
29+import Rel8.Schema.Context.Abstract ( Abstract, exclusivity, virtual )
29import Rel8.Schema.Dict ( Dict( Dict ) )
30import Rel8.Schema.Dict ( Dict( Dict ) )
30import Rel8.Schema.HTable.NonEmpty ( HNonEmptyTable )
31import Rel8.Schema.HTable.NonEmpty ( HNonEmptyTable )
31−import Rel8.Schema.HTable.Vectorize
32+import Rel8.Schema.HTable.Vectorize ( happend, hvectorize )
32− ( hvectorize, hunvectorize
33− , happend
34− , hproject, hcolumn
35− )
36import qualified Rel8.Schema.Kind as K
33import qualified Rel8.Schema.Kind as K
37−import Rel8.Schema.Name ( Name( Name ) )
34+import Rel8.Schema.Name ( Col( N ), Name( Name ) )
38import Rel8.Schema.Null ( Nullity( Null, NotNull ) )
35import Rel8.Schema.Null ( Nullity( Null, NotNull ) )
39−import Rel8.Schema.Result ( vectorizer, unvectorizer )
36+import Rel8.Schema.Reify ( hreify, hunreify )
40−import Rel8.Schema.Spec ( Spec(..) )
37+import Rel8.Schema.Spec ( SSpec(..) )
41import Rel8.Table
38import Rel8.Table
42 ( Table, Context, Columns, fromColumns, toColumns
39 ( Table, Context, Columns, fromColumns, toColumns
43− , FromExprs, fromResult, toResult
40+ , reify, unreify, coherence, congruence
44− , Transpose
45 )
41 )
46import Rel8.Table.Alternative ( AltTable, (<|>:) )
42import Rel8.Table.Alternative ( AltTable, (<|>:) )
47import Rel8.Table.Eq ( EqTable, eqTable )
43import Rel8.Table.Eq ( EqTable, eqTable )
48import Rel8.Table.Ord ( OrdTable, ordTable )
44import Rel8.Table.Ord ( OrdTable, ordTable )
49−import Rel8.Table.Projection
45+import Rel8.Table.Recontextualize ( Recontextualize )
50− ( Projectable, Projecting, Projection, project, apply
51− )
52−import Rel8.Table.Serialize ( ToExprs )
46+import Rel8.Table.Serialize ( FromExprs, ToExprs, fromResult, toResult )
53
47
54
48
55-- | A @NonEmptyTable@ value contains one or more instances of @a@. You
49-- | A @NonEmptyTable@ value contains one or more instances of @a@. You
56-- construct @NonEmptyTable@s with 'Rel8.some' or 'nonEmptyAgg'.
50-- construct @NonEmptyTable@s with 'Rel8.some' or 'nonEmptyAgg'.
57type NonEmptyTable :: K.Context -> Type -> Type
51type NonEmptyTable :: K.Context -> Type -> Type
58newtype NonEmptyTable context a =
52newtype NonEmptyTable context a =
59− NonEmptyTable (HNonEmptyTable (Columns a) (Context a))
53+ NonEmptyTable (HNonEmptyTable (Columns a) (Col (Context a)))
60−
61−
62−instance Projectable (NonEmptyTable context) where
63− project f (NonEmptyTable a) = NonEmptyTable (hproject (apply f) a)
64
54
65
55
66−instance (Table context a, context ~ context') =>
56+instance (Table context a, Abstract context, context ~ context') =>
67 Table context' (NonEmptyTable context a)
57 Table context' (NonEmptyTable context a)
68 where
58 where
69 type Columns (NonEmptyTable context a) = HNonEmptyTable (Columns a)
59 type Columns (NonEmptyTable context a) = HNonEmptyTable (Columns a)
70 type Context (NonEmptyTable context a) = Context a
60 type Context (NonEmptyTable context a) = Context a
71− type FromExprs (NonEmptyTable context a) = NonEmpty (FromExprs a)
72− type Transpose to (NonEmptyTable context a) =
73− NonEmptyTable to (Transpose to a)
74
61
75 fromColumns = NonEmptyTable
62 fromColumns = NonEmptyTable
76 toColumns (NonEmptyTable a) = a
63 toColumns (NonEmptyTable a) = a
77− fromResult = fmap (fromResult @_ @a) . hunvectorize unvectorizer
64+
78− toResult = hvectorize vectorizer . fmap (toResult @_ @a)
65+ reify proof@Refl (NonEmptyTable a) =
66+ case coherence @context @a proof abstract of
67+ Refl -> case congruence @context @a proof abstract of
68+ Refl -> NonEmptyTable (hreify a)
69+ where
70+ abstract = exclusivity virtual
71+
72+ unreify proof@Refl (NonEmptyTable a) =
73+ case coherence @context @a proof abstract of
74+ Refl -> case congruence @context @a proof abstract of
75+ Refl -> NonEmptyTable (hunreify a)
76+ where
77+ abstract = exclusivity virtual
78+
79+ coherence = coherence @context @a
80+ congruence proof abstract = id `apply` congruence @context @a proof abstract
81+
82+
83+instance
84+ ( Recontextualize from to a b
85+ , Abstract from, from ~ from'
86+ , Abstract to, to ~ to'
87+ )
88+ => Recontextualize from to (NonEmptyTable from' a) (NonEmptyTable to' b)
79
89
80
90
81instance (EqTable a, context ~ Expr) =>
91instance (EqTable a, context ~ Expr) =>
@@ -83,7 +93,7 @@ instance (EqTable a, context ~ Expr) =>
83 where
93 where
84 eqTable =
94 eqTable =
85 hvectorize
95 hvectorize
86− (\Spec {nullity} (Identity Dict) -> case nullity of
96+ (\SSpec {nullity} (Identity Dict) -> case nullity of
87 Null -> Dict
97 Null -> Dict
88 NotNull -> Dict)
98 NotNull -> Dict)
89 (Identity (eqTable @a))
99 (Identity (eqTable @a))
@@ -94,38 +104,38 @@ instance (OrdTable a, context ~ Expr) =>
94 where
104 where
95 ordTable =
105 ordTable =
96 hvectorize
106 hvectorize
97− (\Spec {nullity} (Identity Dict) -> case nullity of
107+ (\SSpec {nullity} (Identity Dict) -> case nullity of
98 Null -> Dict
108 Null -> Dict
99 NotNull -> Dict)
109 NotNull -> Dict)
100 (Identity (ordTable @a))
110 (Identity (ordTable @a))
101
111
102
112
113+type instance FromExprs (NonEmptyTable _context a) = NonEmpty (FromExprs a)
114+
115+
103instance (ToExprs exprs a, context ~ Expr) =>
116instance (ToExprs exprs a, context ~ Expr) =>
104 ToExprs (NonEmptyTable context exprs) (NonEmpty a)
117 ToExprs (NonEmptyTable context exprs) (NonEmpty a)
118+ where
119+ fromResult = fmap (fromResult @exprs) . fromColumns
120+ toResult = toColumns . fmap (toResult @exprs)
105
121
106
122
107instance context ~ Expr => AltTable (NonEmptyTable context) where
123instance context ~ Expr => AltTable (NonEmptyTable context) where
108 (<|>:) = (<>)
124 (<|>:) = (<>)
109
125
110
126
127+instance (Table Expr a, context ~ Expr) =>
111−instance (Table Expr a, context ~ Expr) => Semigroup (NonEmptyTable context a)
128+ Semigroup (NonEmptyTable context a)
112 where
129 where
113 NonEmptyTable as <> NonEmptyTable bs = NonEmptyTable $
130 NonEmptyTable as <> NonEmptyTable bs = NonEmptyTable $
114− happend (const sappend1) as bs
131+ happend (\_ _ (E a) (E b) -> E (sappend1 a b)) as bs
115−
116−
117−-- | Project a single expression out of a 'NonEmptyTable'.
118−($+) :: Projecting a (Expr b)
119− => Projection a (Expr b) -> NonEmptyTable Expr a -> Expr (NonEmpty b)
120−f $+ NonEmptyTable a = hcolumn $ hproject (apply f) a
121−infixl 4 $+
122
132
123
133
124-- | Construct a @NonEmptyTable@ from a non-empty list of expressions.
134-- | Construct a @NonEmptyTable@ from a non-empty list of expressions.
125nonEmptyTable :: Table Expr a => NonEmpty a -> NonEmptyTable Expr a
135nonEmptyTable :: Table Expr a => NonEmpty a -> NonEmptyTable Expr a
126nonEmptyTable =
136nonEmptyTable =
127 NonEmptyTable .
137 NonEmptyTable .
128− hvectorize (\Spec {info} -> snonEmptyOf info) .
138+ hvectorize (\SSpec {info} -> E . snonEmptyOf info . fmap unE) .
129 fmap toColumns
139 fmap toColumns
130
140
131
141
@@ -138,6 +148,6 @@ nameNonEmptyTable
138 -> NonEmptyTable Name a
148 -> NonEmptyTable Name a
139nameNonEmptyTable =
149nameNonEmptyTable =
140 NonEmptyTable .
150 NonEmptyTable .
141− hvectorize (\_ (Identity (Name a)) -> Name a) .
151+ hvectorize (\_ (Identity (N (Name a))) -> N (Name a)) .
142 pure .
152 pure .
143 toColumns
153 toColumns
src/Rel8/Table/Null.hsdeleted−147
@@ -1,147 +0,0 @@
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 #-}
10−
11−module Rel8.Table.Null
12− ( NullTable(..)
13− , nullableTable, nullTable, nullifyTable, unsafeUnnullifyTable
14− , isNullTable, isNonNullTable
15− , nameNullTable
16− , toMaybeTable, toNullTable
17− )
18−where
19−
20−-- base
21−import Data.Kind ( Type )
22−import Prelude hiding ( null, undefined )
23−
24−-- comonad
25−import Control.Comonad ( extract )
26−
27−-- rel8
28−import Rel8.Expr ( Expr )
29−import Rel8.Expr.Bool ( not_ )
30−import Rel8.Kind.Context ( Reifiable )
31−import qualified Rel8.Schema.Kind as K
32−import Rel8.Schema.Name ( Name )
33−import Rel8.Table
34− ( Table, Columns, Context, fromColumns, toColumns
35− , FromExprs, fromResult, toResult
36− , Transpose
37− )
38−import Rel8.Table.Alternative
39− ( AltTable, (<|>:)
40− , AlternativeTable, emptyTable
41− )
42−import Rel8.Table.Bool ( bool )
43−import Rel8.Table.Eq ( EqTable, eqTable )
44−import Rel8.Table.Maybe ( MaybeTable, justTable, maybeTable, nothingTable )
45−import Rel8.Table.Nullify ( Nullify, isNull )
46−import Rel8.Table.Ord ( OrdTable, ordTable )
47−import Rel8.Table.Projection ( Projectable, project )
48−import Rel8.Table.Serialize ( ToExprs )
49−import Rel8.Table.Undefined ( undefined )
50−
51−
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.
58−type NullTable :: K.Context -> Type -> Type
59−newtype NullTable context a = NullTable (Nullify context a)
60−
61−
62−instance Projectable (NullTable context) where
63− project f (NullTable a) = NullTable (project f a)
64−
65−
66−instance context ~ Expr => AltTable (NullTable context) where
67− ma <|>: mb = bool ma mb (isNullTable ma)
68−
69−
70−instance context ~ Expr => AlternativeTable (NullTable context) where
71− emptyTable = nullTable
72−
73−
74−instance (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)
81−
82− toColumns (NullTable a) = toColumns a
83− fromColumns = NullTable . fromColumns
84−
85− toResult = toResult @_ @(Nullify context a)
86− fromResult = fromResult @_ @(Nullify context a)
87−
88−
89−instance (EqTable a, context ~ Expr) => EqTable (NullTable context a) where
90− eqTable = eqTable @(Nullify context a)
91−
92−
93−instance (OrdTable a, context ~ Expr) => OrdTable (NullTable context a) where
94− ordTable = ordTable @(Nullify context a)
95−
96−
97−instance (ToExprs exprs a, context ~ Expr) =>
98− ToExprs (NullTable context exprs) (Maybe a)
99−
100−
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.
103−isNullTable :: Table Expr a => NullTable Expr a -> Expr Bool
104−isNullTable (NullTable a) = isNull a
105−
106−
107−-- | The inverse of 'isNullTable'.
108−isNonNullTable :: Table Expr a => NullTable Expr a -> Expr Bool
109−isNonNullTable = not_ . isNullTable
110−
111−
112−-- | Like 'Rel8.nullable'.
113−nullableTable :: (Table Expr a, Table Expr b)
114− => b -> (a -> b) -> NullTable Expr a -> b
115−nullableTable b f ma@(NullTable a) = bool (f (extract a)) b (isNullTable ma)
116−
117−
118−-- | The null table. Like 'Rel8.null'.
119−nullTable :: Table Expr a => NullTable Expr a
120−nullTable = NullTable (pure undefined)
121−
122−
123−-- | Lift any table into 'NullTable'. Like 'Rel8.nullify'.
124−nullifyTable :: a -> NullTable Expr a
125−nullifyTable = NullTable . pure
126−
127−
128−unsafeUnnullifyTable :: NullTable Expr a -> a
129−unsafeUnnullifyTable (NullTable a) = extract a
130−
131−
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'.
135−nameNullTable :: a -> NullTable Name a
136−nameNullTable = NullTable . pure
137−
138−
139−-- | Convert a 'NullTable' to a 'MaybeTable'.
140−toMaybeTable :: Table Expr a => NullTable Expr a -> MaybeTable Expr a
141−toMaybeTable = nullableTable nothingTable justTable
142−
143−
144−-- | Convert a 'MaybeTable' to a 'NullTable'. Note that if the underlying @a@
145−-- has no non-nullable fields, this is a lossy conversion.
146−toNullTable :: Table Expr a => MaybeTable Expr a -> NullTable Expr a
147−toNullTable = maybeTable nullTable nullifyTable
src/Rel8/Table/Nullify.hs+50−57
@@ -1,9 +1,7 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2−{-# language FlexibleContexts #-}
3{-# language FlexibleInstances #-}
2{-# language FlexibleInstances #-}
4{-# language LambdaCase #-}
3{-# language LambdaCase #-}
5{-# language MultiParamTypeClasses #-}
4{-# language MultiParamTypeClasses #-}
6−{-# language NamedFieldPuns #-}
7{-# language ScopedTypeVariables #-}
5{-# language ScopedTypeVariables #-}
8{-# language StandaloneKindSignatures #-}
6{-# language StandaloneKindSignatures #-}
9{-# language TypeApplications #-}
7{-# language TypeApplications #-}
@@ -14,16 +12,16 @@ module Rel8.Table.Nullify
14 ( Nullify
12 ( Nullify
15 , aggregateNullify
13 , aggregateNullify
16 , guard
14 , guard
17− , isNull
18 )
15 )
19where
16where
20
17
21-- base
18-- base
22import Control.Applicative ( liftA2 )
19import Control.Applicative ( liftA2 )
23−import Data.Functor.Const ( Const( Const ), getConst )
20+import Control.Category ( id )
24import Data.Functor.Identity ( runIdentity )
21import Data.Functor.Identity ( runIdentity )
25import Data.Kind ( Type )
22import Data.Kind ( Type )
23+import Data.Type.Equality ( (:~:)( Refl ), apply )
26−import Prelude
24+import Prelude hiding ( id )
27
25
28-- comonad
26-- comonad
29import Control.Comonad ( Comonad, duplicate, extract, ComonadApply, (<@>) )
27import Control.Comonad ( Comonad, duplicate, extract, ComonadApply, (<@>) )
@@ -31,12 +29,12 @@ import Control.Comonad ( Comonad, duplicate, extract, ComonadApply, (<@>) )
31-- rel8
29-- rel8
32import Rel8.Aggregate ( Aggregate )
30import Rel8.Aggregate ( Aggregate )
33import Rel8.Expr ( Expr )
31import Rel8.Expr ( Expr )
34−import Rel8.Expr.Bool ( (||.), false )
35−import qualified Rel8.Expr.Null as Expr
36import Rel8.Kind.Context ( Reifiable, contextSing )
32import Rel8.Kind.Context ( Reifiable, contextSing )
33+import Rel8.Schema.Context ( Col )
34+import Rel8.Schema.Context.Abstract ( Abstract, exclusivity, virtual )
37import Rel8.Schema.Context.Nullify
35import Rel8.Schema.Context.Nullify
38 ( Nullifiability( NAggregate, NExpr )
36 ( Nullifiability( NAggregate, NExpr )
39− , NonNullifiability
37+ , NonNullifiability( NNReify )
40 , Nullifiable, nullifiability
38 , Nullifiable, nullifiability
41 , nullifiableOrNot, absurd
39 , nullifiableOrNot, absurd
42 , guarder
40 , guarder
@@ -45,23 +43,17 @@ import Rel8.Schema.Context.Nullify
45 )
43 )
46import Rel8.Schema.Dict ( Dict( Dict ) )
44import Rel8.Schema.Dict ( Dict( Dict ) )
47import Rel8.Schema.HTable ( HTable )
45import Rel8.Schema.HTable ( HTable )
48−import Rel8.Schema.HTable.Nullify
46+import Rel8.Schema.HTable.Nullify ( HNullify, hnullify, hunnullify, hguard )
49− ( HNullify, hnulls, hnullify, hunnullify
50− , hguard
51− , hproject
52− )
53import qualified Rel8.Schema.Kind as K
47import qualified Rel8.Schema.Kind as K
54−import Rel8.Schema.Null ( Nullity( NotNull, Null ) )
48+import Rel8.Schema.Reify ( hreify, hunreify )
55−import qualified Rel8.Schema.Result as R
49+import Rel8.Schema.Spec ( Spec( Spec ) )
56import Rel8.Table
50import Rel8.Table
57 ( Table, Columns, Context, toColumns, fromColumns
51 ( Table, Columns, Context, toColumns, fromColumns
58− , FromExprs, fromResult, toResult
52+ , reify, unreify, coherence, congruence
59− , Transpose
60 )
53 )
61−import Rel8.Schema.Spec ( Spec( Spec, nullity ) )
62import Rel8.Table.Eq ( EqTable, eqTable )
54import Rel8.Table.Eq ( EqTable, eqTable )
63import Rel8.Table.Ord ( OrdTable, ordTable )
55import Rel8.Table.Ord ( OrdTable, ordTable )
64−import Rel8.Table.Projection ( Projectable, apply, project )
56+import Rel8.Table.Recontextualize ( Recontextualize )
65
57
66-- semigroupoids
58-- semigroupoids
67import Data.Functor.Apply ( Apply, (<.>), liftF2 )
59import Data.Functor.Apply ( Apply, (<.>), liftF2 )
@@ -72,13 +64,7 @@ import Data.Functor.Extend ( Extend, duplicated )
72type Nullify :: K.Context -> Type -> Type
64type Nullify :: K.Context -> Type -> Type
73data Nullify context a
65data Nullify context a
74 = Table (Nullifiability context) a
66 = Table (Nullifiability context) a
75− | Fields (NonNullifiability context) (HNullify (Columns a) (Context a))
67+ | Fields (NonNullifiability context) (HNullify (Columns a) (Col (Context a)))
76−
77−
78−instance Projectable (Nullify context) where
79− project f = \case
80− Table nullifiable a -> Table nullifiable (fromColumns (apply f (toColumns a)))
81− Fields nonNullifiable a -> Fields nonNullifiable (hproject (apply f) a)
82
68
83
69
84instance Nullifiable context => Functor (Nullify context) where
70instance Nullifiable context => Functor (Nullify context) where
@@ -138,13 +124,14 @@ instance Nullifiable context => ComonadApply (Nullify context) where
138 (<@>) = (<.>)
124 (<@>) = (<.>)
139
125
140
126
127+instance
128+ ( Table context a
141−instance (Table context a, Reifiable context, context ~ context') =>
129+ , Reifiable context, Abstract context, context ~ context'
130+ )
142− Table context' (Nullify context a)
131+ => Table context' (Nullify context a)
143 where
132 where
144 type Columns (Nullify context a) = HNullify (Columns a)
133 type Columns (Nullify context a) = HNullify (Columns a)
145 type Context (Nullify context a) = Context a
134 type Context (Nullify context a) = Context a
146− type FromExprs (Nullify context a) = Maybe (FromExprs a)
147− type Transpose to (Nullify context a) = Nullify to (Transpose to a)
148
135
149 fromColumns = case nullifiableOrNot contextSing of
136 fromColumns = case nullifiableOrNot contextSing of
150 Left notNullifiable -> Fields notNullifiable
137 Left notNullifiable -> Fields notNullifiable
@@ -158,11 +145,36 @@ instance (Table context a, Reifiable context, context ~ context') =>
158 Table nullifiable a -> hnullify (nullifier nullifiable) (toColumns a)
145 Table nullifiable a -> hnullify (nullifier nullifiable) (toColumns a)
159 Fields _ a -> a
146 Fields _ a -> a
160
147
161− fromResult = fmap (fromResult @_ @a) . hunnullify R.unnullifier
148+ reify proof@Refl = \case
162−
149+ Table nullifiable a -> Table nullifiable (reify proof a)
163− toResult =
150+ Fields notNullifiable a -> case notNullifiable of
164− maybe (hnulls (const R.null)) (hnullify R.nullifier) .
151+ NNReify (_ :: NonNullifiability ctx) ->
165− fmap (toResult @_ @a)
152+ case coherence @context @a proof abstract of
153+ Refl -> case congruence @context @a proof abstract of
154+ Refl -> Fields notNullifiable (hreify a)
155+ where
156+ abstract = exclusivity (virtual @ctx)
157+
158+ unreify proof@Refl = \case
159+ Table nullifiable a -> Table nullifiable (unreify proof a)
160+ Fields notNullifiable a -> case notNullifiable of
161+ NNReify (_ :: NonNullifiability ctx) ->
162+ case coherence @context @a proof abstract of
163+ Refl -> case congruence @context @a proof abstract of
164+ Refl -> Fields notNullifiable (hunreify a)
165+ where
166+ abstract = exclusivity (virtual @ctx)
167+
168+ coherence = coherence @context @a
169+ congruence proof abstract = id `apply` congruence @context @a proof abstract
170+
171+
172+instance
173+ ( Recontextualize from to a b
174+ , Reifiable from, Abstract from, from ~ from'
175+ , Reifiable to, Abstract to, to ~ to'
176+ )
177+ => Recontextualize from' to' (Nullify from a) (Nullify to b)
166
178
167
179
168instance (EqTable a, context ~ Expr) => EqTable (Nullify context a) where
180instance (EqTable a, context ~ Expr) => EqTable (Nullify context a) where
@@ -183,29 +195,10 @@ aggregateNullify f = \case
183
195
184
196
185guard :: (Reifiable context, HTable t)
197guard :: (Reifiable context, HTable t)
186− => context tag
198+ => Col context ('Spec tag)
187 -> (tag -> Bool)
199 -> (tag -> Bool)
188 -> (Expr tag -> Expr Bool)
200 -> (Expr tag -> Expr Bool)
189− -> HNullify t context
201+ -> HNullify t (Col context)
190− -> HNullify t context
202+ -> HNullify t (Col context)
191guard tag isNonNull isNonNullExpr =
203guard tag isNonNull isNonNullExpr =
192 hguard (guarder contextSing tag isNonNull isNonNullExpr)
204 hguard (guarder contextSing tag isNonNull isNonNullExpr)
193−
194−
195−isNull :: forall a. Table Expr a => Nullify Expr a -> Expr Bool
196−isNull =
197− maybe false getAny .
198− getConst .
199− hunnullify (\Spec {nullity} a -> Const $ case nullity of
200− NotNull -> Just $ Any $ Expr.isNull a
201− Null -> Nothing) .
202− toColumns
203−
204−
205−newtype Any = Any
206− { getAny :: Expr Bool
207− }
208−
209−
210−instance Semigroup Any where
211− Any a <> Any b = Any (a ||. b)
src/Rel8/Table/Opaleye.hs+64−78
@@ -1,150 +1,136 @@
1{-# language BlockArguments #-}
1{-# language BlockArguments #-}
2−{-# language DataKinds #-}
3{-# language DisambiguateRecordFields #-}
2{-# language DisambiguateRecordFields #-}
4{-# language FlexibleContexts #-}
3{-# language FlexibleContexts #-}
4+{-# language LambdaCase #-}
5{-# language NamedFieldPuns #-}
5{-# language NamedFieldPuns #-}
6−{-# language RankNTypes #-}
7{-# language TypeFamilies #-}
6{-# language TypeFamilies #-}
8{-# language ViewPatterns #-}
7{-# language ViewPatterns #-}
9
8
10−{-# options_ghc -Wno-deprecations #-}
11−
12module Rel8.Table.Opaleye
9module Rel8.Table.Opaleye
13 ( aggregator
10 ( aggregator
14− , attributes
15 , binaryspec
11 , binaryspec
16 , distinctspec
12 , distinctspec
17− , exprs
18− , exprsWithNames
19 , table
13 , table
20 , tableFields
14 , tableFields
21 , unpackspec
15 , unpackspec
22 , valuesspec
16 , valuesspec
23− , view
24 , castTable
17 , castTable
25 )
18 )
26where
19where
27
20
28-- base
21-- base
29−import Data.Functor.Const ( Const( Const ), getConst )
22+import Prelude hiding ( undefined )
30−import Data.List.NonEmpty ( NonEmpty )
31−import Prelude
32
23
33-- opaleye
24-- opaleye
34−import qualified Opaleye.Adaptors as Opaleye
35−import qualified Opaleye.Field as Opaleye ( Field_ )
36import qualified Opaleye.Internal.Aggregate as Opaleye
25import qualified Opaleye.Internal.Aggregate as Opaleye
26+import qualified Opaleye.Internal.Binary as Opaleye
27+import qualified Opaleye.Internal.Distinct as Opaleye
37import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
28import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
29+import qualified Opaleye.Internal.PackMap as Opaleye
30+import qualified Opaleye.Internal.Unpackspec as Opaleye
38import qualified Opaleye.Internal.Values as Opaleye
31import qualified Opaleye.Internal.Values as Opaleye
39−import qualified Opaleye.Table as Opaleye
32+import qualified Opaleye.Internal.Table as Opaleye
40
33
41-- profunctors
34-- profunctors
42import Data.Profunctor ( dimap, lmap )
35import Data.Profunctor ( dimap, lmap )
43
36
44-- rel8
37-- rel8
45−import Rel8.Aggregate ( Aggregate( Aggregate ), Aggregates )
38+import Rel8.Aggregate ( Col( A ), Aggregate( Aggregate ), Aggregates )
46−import Rel8.Expr ( Expr )
39+import Rel8.Expr ( Expr, Col(..) )
47import Rel8.Expr.Opaleye
40import Rel8.Expr.Opaleye
48 ( fromPrimExpr, toPrimExpr
41 ( fromPrimExpr, toPrimExpr
42+ , traversePrimExpr
43+ , fromColumn, toColumn
49− , scastExpr, traverseFieldP
44+ , scastExpr
50 )
45 )
51−import Rel8.Schema.HTable ( htabulateA, hfield, hspecs, htabulate,
46+import Rel8.Schema.HTable ( htabulateA, hfield, htraverse, hspecs, htabulate )
52− htraverseP, htraversePWithField )
53−import Rel8.Schema.Name ( Name( Name ), Selects, ppColumn )
47+import Rel8.Schema.Name ( Col( N ), Name( Name ), Selects )
54−import Rel8.Schema.Spec ( Spec(..) )
48+import Rel8.Schema.Spec ( SSpec(..) )
55−import Rel8.Schema.Table ( TableSchema(..), ppTable )
49+import Rel8.Schema.Table ( TableSchema(..) )
56import Rel8.Table ( Table, fromColumns, toColumns )
50import Rel8.Table ( Table, fromColumns, toColumns )
57−import Rel8.Type.Information ( typeName )
51+import Rel8.Table.Undefined ( undefined )
58
52
59-- semigroupoids
53-- semigroupoids
60import Data.Functor.Apply ( WrappedApplicative(..) )
54import Data.Functor.Apply ( WrappedApplicative(..) )
61−import Data.Profunctor.Product ( ProductProfunctor )
62
55
63
56
64aggregator :: Aggregates aggregates exprs => Opaleye.Aggregator aggregates exprs
57aggregator :: Aggregates aggregates exprs => Opaleye.Aggregator aggregates exprs
65−aggregator = dimap toColumns fromColumns $
58+aggregator = Opaleye.Aggregator $ Opaleye.PackMap $ \f aggregates ->
66− htraverseP $
59+ fmap fromColumns $ unwrapApplicative $ htabulateA $ \field ->
67− lmap (\(Aggregate a) -> (a, ())) Opaleye.aggregatorApply
68−
69−
70−attributes :: Selects names exprs => TableSchema names -> exprs
71−attributes schema@TableSchema {columns} = fromColumns $ htabulate $ \field ->
72− case hfield (toColumns columns) field of
60+ WrapApplicative $ case hfield (toColumns aggregates) field of
73− Name column -> fromPrimExpr $ Opaleye.ConstExpr $
61+ A (Aggregate (Opaleye.Aggregator (Opaleye.PackMap inner))) ->
74− Opaleye.OtherLit $
62+ E <$> inner f ()
75− show (ppTable schema) <> "." <> show (ppColumn column)
76−
77−
78−fromOpaleyespec :: (ProductProfunctor p, Table Expr a)
79− => p (Opaleye.Field_ n x) (Opaleye.Field_ n x)
80− -> p a a
81−fromOpaleyespec x =
82− dimap toColumns fromColumns (htraverseP (traverseFieldP x))
83
63
84
64
85binaryspec :: Table Expr a => Opaleye.Binaryspec a a
65binaryspec :: Table Expr a => Opaleye.Binaryspec a a
86−binaryspec = fromOpaleyespec Opaleye.binaryspecField
66+binaryspec = Opaleye.Binaryspec $ Opaleye.PackMap $ \f (as, bs) ->
67+ fmap fromColumns $ unwrapApplicative $ htabulateA $ \field ->
68+ WrapApplicative $
69+ case (hfield (toColumns as) field, hfield (toColumns bs) field) of
70+ (E a, E b) -> E . fromPrimExpr <$> f (toPrimExpr a, toPrimExpr b)
87
71
88
72
89distinctspec :: Table Expr a => Opaleye.Distinctspec a a
73distinctspec :: Table Expr a => Opaleye.Distinctspec a a
90−distinctspec = fromOpaleyespec Opaleye.distinctspecField
74+distinctspec =
91−
75+ Opaleye.Distinctspec $ Opaleye.Aggregator $ Opaleye.PackMap $ \f ->
92−
76+ fmap fromColumns .
93−exprs :: Table Expr a => a -> NonEmpty Opaleye.PrimExpr
77+ unwrapApplicative .
94−exprs (toColumns -> as) = getConst $ htabulateA $ \field ->
78+ htraverse
95− case hfield as field of
79+ (\(E a) ->
96− expr -> Const (pure (toPrimExpr expr))
80+ WrapApplicative $ E . fromPrimExpr <$> f (Nothing, toPrimExpr a)) .
97−
81+ toColumns
98−
99−exprsWithNames :: Selects names exprs
100− => names -> exprs -> NonEmpty (String, Opaleye.PrimExpr)
101−exprsWithNames names as = getConst $ htabulateA $ \field ->
102− case (hfield (toColumns names) field, hfield (toColumns as) field) of
103− (Name name, expr) -> Const (pure (name, toPrimExpr expr))
104
82
105
83
106−table :: Selects names exprs => TableSchema names -> Opaleye.Table exprs exprs
84+table ::Selects names exprs => TableSchema names -> Opaleye.Table exprs exprs
107table (TableSchema name schema columns) =
85table (TableSchema name schema columns) =
108 case schema of
86 case schema of
109− Nothing -> Opaleye.table name (tableFields columns)
87+ Nothing -> Opaleye.Table name (tableFields columns)
110− Just schemaName -> Opaleye.tableWithSchema schemaName name (tableFields columns)
88+ Just schemaName -> Opaleye.TableWithSchema schemaName name (tableFields columns)
111
89
112
90
113−tableFields :: Selects names exprs
91+tableFields ::Selects names exprs
114 => names -> Opaleye.TableFields exprs exprs
92 => names -> Opaleye.TableFields exprs exprs
115tableFields (toColumns -> names) = dimap toColumns fromColumns $
93tableFields (toColumns -> names) = dimap toColumns fromColumns $
116 unwrapApplicative $ htabulateA $ \field -> WrapApplicative $
94 unwrapApplicative $ htabulateA $ \field -> WrapApplicative $
117 case hfield names field of
95 case hfield names field of
118 name -> lmap (`hfield` field) (go name)
96 name -> lmap (`hfield` field) (go name)
119 where
97 where
120− go :: Name a -> Opaleye.TableFields (Expr a) (Expr a)
98+ go :: Col Name spec -> Opaleye.TableFields (Col Expr spec) (Col Expr spec)
121− go (Name name) =
99+ go (N (Name name)) =
122− traverseFieldP $
100+ lmap (\(E a) -> toColumn $ toPrimExpr a) $
101+ E . fromPrimExpr . fromColumn <$>
123− Opaleye.requiredTableField name
102+ Opaleye.requiredTableField name
124
103
125
104
126unpackspec :: Table Expr a => Opaleye.Unpackspec a a
105unpackspec :: Table Expr a => Opaleye.Unpackspec a a
127−unpackspec = fromOpaleyespec Opaleye.unpackspecField
106+unpackspec = Opaleye.Unpackspec $ Opaleye.PackMap $ \f ->
107+ fmap fromColumns .
108+ unwrapApplicative .
109+ htraverse (\(E a) -> WrapApplicative $ E <$> traversePrimExpr f a) .
110+ toColumns
128{-# INLINABLE unpackspec #-}
111{-# INLINABLE unpackspec #-}
129
112
130
113
131−valuesspec :: Table Expr a => Opaleye.Valuesspec a a
114+valuesspec :: Table Expr a => Opaleye.ValuesspecSafe a a
132−valuesspec = dimap toColumns fromColumns $
115+valuesspec = Opaleye.ValuesspecSafe (toPackMap undefined) unpackspec
133− htraversePWithField (traverseFieldP . Opaleye.valuesspecFieldType . typeName)
134− where typeName = Rel8.Type.Information.typeName . info . hfield hspecs
135
116
136
117
137−view :: Selects names exprs => names -> exprs
118+toPackMap :: Table Expr a
119+ => a -> Opaleye.PackMap Opaleye.PrimExpr Opaleye.PrimExpr () a
120+toPackMap as = Opaleye.PackMap $ \f () ->
138−view columns = fromColumns $ htabulate $ \field ->
121+ fmap fromColumns $
122+ unwrapApplicative .
123+ htraverse (\(E a) -> WrapApplicative $ E <$> traversePrimExpr f a) $
139− case hfield (toColumns columns) field of
124+ toColumns as
140− Name column -> fromPrimExpr $ Opaleye.BaseTableAttrExpr column
141
125
142
126
143-- | Transform a table by adding 'CAST' to all columns. This is most useful for
127-- | Transform a table by adding 'CAST' to all columns. This is most useful for
144-- finalising a SELECT or RETURNING statement, guaranteed that the output
128-- finalising a SELECT or RETURNING statement, guaranteed that the output
145-- matches what is encoded in each columns TypeInformation.
129-- matches what is encoded in each columns TypeInformation.
146castTable :: Table Expr a => a -> a
130castTable :: Table Expr a => a -> a
147−castTable (toColumns -> as) = fromColumns $ htabulate \field ->
131+castTable (toColumns -> as) = fromColumns $ htabulate \i ->
148− case hfield hspecs field of
132+ case hfield hspecs i of
133+ SSpec{info} ->
149− Spec {info} -> case hfield as field of
134+ case hfield as i of
135+ E expr ->
150− expr -> scastExpr info expr
136+ E (scastExpr info expr)
src/Rel8/Table/Ord.hs+45−16
@@ -10,6 +10,7 @@
10{-# language TypeFamilies #-}
10{-# language TypeFamilies #-}
11{-# language TypeOperators #-}
11{-# language TypeOperators #-}
12{-# language UndecidableInstances #-}
12{-# language UndecidableInstances #-}
13+{-# language UndecidableSuperClasses #-}
13{-# language ViewPatterns #-}
14{-# language ViewPatterns #-}
14
15
15module Rel8.Table.Ord
16module Rel8.Table.Ord
@@ -24,20 +25,29 @@ import GHC.Generics ( Rep )
24import Prelude hiding ( seq )
25import Prelude hiding ( seq )
25
26
26-- rel8
27-- rel8
27−import Rel8.Expr ( Expr )
28+import Rel8.Expr ( Expr, Col( E ) )
28import Rel8.Expr.Bool ( (||.), (&&.), false, true )
29import Rel8.Expr.Bool ( (||.), (&&.), false, true )
29import Rel8.Expr.Eq ( (==.) )
30import Rel8.Expr.Eq ( (==.) )
30import Rel8.Expr.Ord ( (<.), (>.) )
31import Rel8.Expr.Ord ( (<.), (>.) )
31import Rel8.FCF ( Eval, Exp )
32import Rel8.FCF ( Eval, Exp )
32import Rel8.Generic.Record ( Record )
33import Rel8.Generic.Record ( Record )
33−import Rel8.Generic.Table.Record ( GTable, GColumns, gtable )
34+import Rel8.Generic.Table
35+ ( GGTable, GGColumns, ggtable
36+ , GAlgebra
37+ )
38+import Rel8.Kind.Algebra ( KnownAlgebra )
34import Rel8.Schema.Dict ( Dict( Dict ) )
39import Rel8.Schema.Dict ( Dict( Dict ) )
35−import Rel8.Schema.HTable ( htabulateA, hfield )
40+import Rel8.Schema.HTable
41+ ( HTable, HConstrainTable
42+ , htabulateA, hfield, hdicts
43+ )
36−import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )
44+import Rel8.Schema.HTable.Identity ( HIdentity( HType ) )
37import Rel8.Schema.Null (Sql)
45import Rel8.Schema.Null (Sql)
46+import Rel8.Schema.Spec.Constrain ( ConstrainSpec )
38import Rel8.Table ( Columns, toColumns, TColumns )
47import Rel8.Table ( Columns, toColumns, TColumns )
39import Rel8.Table.Bool ( bool )
48import Rel8.Table.Bool ( bool )
40import Rel8.Table.Eq ( EqTable )
49import Rel8.Table.Eq ( EqTable )
50+import Rel8.Type.Eq ( DBEq )
41import Rel8.Type.Ord ( DBOrd )
51import Rel8.Type.Ord ( DBOrd )
42
52
43
53
@@ -46,14 +56,22 @@ import Rel8.Type.Ord ( DBOrd )
46-- columns in a 'Table' have an instance of 'DBOrd'".
56-- columns in a 'Table' have an instance of 'DBOrd'".
47type OrdTable :: Type -> Constraint
57type OrdTable :: Type -> Constraint
48class EqTable a => OrdTable a where
58class EqTable a => OrdTable a where
49− ordTable :: Columns a (Dict (Sql DBOrd))
59+ ordTable :: Columns a (Dict (ConstrainSpec (Sql DBOrd)))
50
60
51 default ordTable ::
61 default ordTable ::
62+ ( KnownAlgebra (GAlgebra (Rep (Record a)))
52− ( GTable TOrdTable TColumns (Rep (Record a))
63+ , Eval (GGTable (GAlgebra (Rep (Record a))) TOrdTable TColumns (Dict (ConstrainSpec (Sql DBOrd))) (Rep (Record a)))
53− , Columns a ~ GColumns TColumns (Rep (Record a))
64+ , Columns a ~ Eval (GGColumns (GAlgebra (Rep (Record a))) TColumns (Rep (Record a)))
54 )
65 )
55− => Columns a (Dict (Sql DBOrd))
66+ => Columns a (Dict (ConstrainSpec (Sql DBOrd)))
56− ordTable = gtable @TOrdTable @TColumns @(Rep (Record a)) table
67+ ordTable =
68+ ggtable
69+ @(GAlgebra (Rep (Record a)))
70+ @TOrdTable
71+ @TColumns
72+ @(Rep (Record a))
73+ table
74+ (\_ Dict -> Dict)
57 where
75 where
58 table (_ :: proxy x) = ordTable @x
76 table (_ :: proxy x) = ordTable @x
59
77
@@ -62,8 +80,19 @@ data TOrdTable :: Type -> Exp Constraint
62type instance Eval (TOrdTable a) = OrdTable a
80type instance Eval (TOrdTable a) = OrdTable a
63
81
64
82
83+instance
84+ ( HTable t
85+ , f ~ Col Expr
86+ , HConstrainTable t (ConstrainSpec (Sql DBEq))
87+ , HConstrainTable t (ConstrainSpec (Sql DBOrd))
88+ )
89+ => OrdTable (t f)
90+ where
91+ ordTable = hdicts @(Columns (t f)) @(ConstrainSpec (Sql DBOrd))
92+
93+
65instance Sql DBOrd a => OrdTable (Expr a) where
94instance Sql DBOrd a => OrdTable (Expr a) where
66− ordTable = HIdentity Dict
95+ ordTable = HType Dict
67
96
68
97
69instance (OrdTable a, OrdTable b) => OrdTable (a, b)
98instance (OrdTable a, OrdTable b) => OrdTable (a, b)
@@ -98,7 +127,7 @@ instance
98(toColumns -> as) <: (toColumns -> bs) =
127(toColumns -> as) <: (toColumns -> bs) =
99 foldr @[] go false $ getConst $ htabulateA $ \field ->
128 foldr @[] go false $ getConst $ htabulateA $ \field ->
100 case (hfield as field, hfield bs field) of
129 case (hfield as field, hfield bs field) of
101− (a, b) -> case hfield (ordTable @a) field of
130+ (E a, E b) -> case hfield (ordTable @a) field of
102 Dict -> Const [(a <. b, a ==. b)]
131 Dict -> Const [(a <. b, a ==. b)]
103 where
132 where
104 go (lt, eq) a = lt ||. (eq &&. a)
133 go (lt, eq) a = lt ||. (eq &&. a)
@@ -111,7 +140,7 @@ infix 4 <:
111(toColumns -> as) <=: (toColumns -> bs) =
140(toColumns -> as) <=: (toColumns -> bs) =
112 foldr @[] go true $ getConst $ htabulateA $ \field ->
141 foldr @[] go true $ getConst $ htabulateA $ \field ->
113 case (hfield as field, hfield bs field) of
142 case (hfield as field, hfield bs field) of
114− (a, b) -> case hfield (ordTable @a) field of
143+ (E a, E b) -> case hfield (ordTable @a) field of
115 Dict -> Const [(a <. b, a ==. b)]
144 Dict -> Const [(a <. b, a ==. b)]
116 where
145 where
117 go (lt, eq) a = lt ||. (eq &&. a)
146 go (lt, eq) a = lt ||. (eq &&. a)
@@ -124,7 +153,7 @@ infix 4 <=:
124(toColumns -> as) >: (toColumns -> bs) =
153(toColumns -> as) >: (toColumns -> bs) =
125 foldr @[] go false $ getConst $ htabulateA $ \field ->
154 foldr @[] go false $ getConst $ htabulateA $ \field ->
126 case (hfield as field, hfield bs field) of
155 case (hfield as field, hfield bs field) of
127− (a, b) -> case hfield (ordTable @a) field of
156+ (E a, E b) -> case hfield (ordTable @a) field of
128 Dict -> Const [(a >. b, a ==. b)]
157 Dict -> Const [(a >. b, a ==. b)]
129 where
158 where
130 go (gt, eq) a = gt ||. (eq &&. a)
159 go (gt, eq) a = gt ||. (eq &&. a)
@@ -137,7 +166,7 @@ infix 4 >:
137(toColumns -> as) >=: (toColumns -> bs) =
166(toColumns -> as) >=: (toColumns -> bs) =
138 foldr @[] go true $ getConst $ htabulateA $ \field ->
167 foldr @[] go true $ getConst $ htabulateA $ \field ->
139 case (hfield as field, hfield bs field) of
168 case (hfield as field, hfield bs field) of
140− (a, b) -> case hfield (ordTable @a) field of
169+ (E a, E b) -> case hfield (ordTable @a) field of
141 Dict -> Const [(a >. b, a ==. b)]
170 Dict -> Const [(a >. b, a ==. b)]
142 where
171 where
143 go (gt, eq) a = gt ||. (eq &&. a)
172 go (gt, eq) a = gt ||. (eq &&. a)
@@ -146,9 +175,9 @@ infix 4 >=:
146
175
147-- | Given two 'Table's, return the table that sorts before the other.
176-- | Given two 'Table's, return the table that sorts before the other.
148least :: OrdTable a => a -> a -> a
177least :: OrdTable a => a -> a -> a
149−least a b = bool b a (a <: b)
178+least a b = bool a b (a <: b)
150
179
151
180
152-- | Given two 'Table's, return the table that sorts after the other.
181-- | Given two 'Table's, return the table that sorts after the other.
153greatest :: OrdTable a => a -> a -> a
182greatest :: OrdTable a => a -> a -> a
154−greatest a b = bool b a (a >: b)
183+greatest a b = bool a b (a >: b)
src/Rel8/Table/Order.hs+6−5
@@ -16,12 +16,13 @@ import Data.Functor.Contravariant ( (>$<), contramap )
16import Prelude
16import Prelude
17
17
18-- rel8
18-- rel8
19+import Rel8.Expr ( unE )
19import Rel8.Expr.Order ( asc, desc, nullsFirst, nullsLast )
20import Rel8.Expr.Order ( asc, desc, nullsFirst, nullsLast )
20import Rel8.Order ( Order )
21import Rel8.Order ( Order )
21import Rel8.Schema.Dict ( Dict( Dict ) )
22import Rel8.Schema.Dict ( Dict( Dict ) )
22import Rel8.Schema.HTable (htabulateA, hfield, hspecs)
23import Rel8.Schema.HTable (htabulateA, hfield, hspecs)
23import Rel8.Schema.Null ( Nullity( Null, NotNull ) )
24import Rel8.Schema.Null ( Nullity( Null, NotNull ) )
24−import Rel8.Schema.Spec ( Spec( Spec, nullity ) )
25+import Rel8.Schema.Spec ( SSpec( SSpec, nullity ) )
25import Rel8.Table ( Columns, toColumns )
26import Rel8.Table ( Columns, toColumns )
26import Rel8.Table.Ord ( OrdTable, ordTable )
27import Rel8.Table.Ord ( OrdTable, ordTable )
27
28
@@ -31,8 +32,8 @@ import Rel8.Table.Ord ( OrdTable, ordTable )
31ascTable :: forall a. OrdTable a => Order a
32ascTable :: forall a. OrdTable a => Order a
32ascTable = contramap toColumns $ getConst $
33ascTable = contramap toColumns $ getConst $
33 htabulateA @(Columns a) $ \field -> case hfield hspecs field of
34 htabulateA @(Columns a) $ \field -> case hfield hspecs field of
34− Spec {nullity} -> case hfield (ordTable @a) field of
35+ SSpec {nullity} -> case hfield (ordTable @a) field of
35− Dict -> Const $ (`hfield` field) >$<
36+ Dict -> Const $ unE . (`hfield` field) >$<
36 case nullity of
37 case nullity of
37 Null -> nullsFirst asc
38 Null -> nullsFirst asc
38 NotNull -> asc
39 NotNull -> asc
@@ -43,8 +44,8 @@ ascTable = contramap toColumns $ getConst $
43descTable :: forall a. OrdTable a => Order a
44descTable :: forall a. OrdTable a => Order a
44descTable = contramap toColumns $ getConst $
45descTable = contramap toColumns $ getConst $
45 htabulateA @(Columns a) $ \field -> case hfield hspecs field of
46 htabulateA @(Columns a) $ \field -> case hfield hspecs field of
46− Spec {nullity} -> case hfield (ordTable @a) field of
47+ SSpec {nullity} -> case hfield (ordTable @a) field of
47− Dict -> Const $ (`hfield` field) >$<
48+ Dict -> Const $ unE . (`hfield` field) >$<
48 case nullity of
49 case nullity of
49 Null -> nullsLast desc
50 Null -> nullsLast desc
50 NotNull -> desc
51 NotNull -> desc
src/Rel8/Table/Projection.hsdeleted−73
@@ -1,73 +0,0 @@
1−{-# language FlexibleContexts #-}
2−{-# language FlexibleInstances #-}
3−{-# language MonoLocalBinds #-}
4−{-# language MultiParamTypeClasses #-}
5−{-# language StandaloneKindSignatures #-}
6−{-# language UndecidableInstances #-}
7−
8−module Rel8.Table.Projection
9− ( Projection
10− , Projectable( project )
11− , Biprojectable( biproject )
12− , Projecting
13− , apply
14− )
15−where
16−
17−-- base
18−import Data.Kind ( Constraint, Type )
19−import Prelude
20−
21−-- rel8
22−import Rel8.Schema.Field ( Field( Field ), fields )
23−import Rel8.Schema.HTable ( hfield, htabulate )
24−import Rel8.Table ( Columns, Context, Transpose, toColumns )
25−import Rel8.Table.Transpose ( Transposes )
26−
27−
28−-- | The constraint @'Projecting' a b@ ensures that @'Projection' a b@ is a
29−-- usable 'Projection'.
30−type Projecting :: Type -> Type -> Constraint
31−class
32− ( Transposes (Context a) (Field a) a (Transpose (Field a) a)
33− , Transposes (Context a) (Field a) b (Transpose (Field a) b)
34− )
35− => Projecting a b
36−instance
37− ( Transposes (Context a) (Field a) a (Transpose (Field a) a)
38− , Transposes (Context a) (Field a) b (Transpose (Field a) b)
39− )
40− => Projecting a b
41−
42−
43−-- | A @'Projection' a b@s is a special type of function @a -> b@ whereby the
44−-- resulting @b@ is guaranteed to be composed only from columns contained in
45−-- @a@.
46−type Projection :: Type -> Type -> Type
47−type Projection a b = Transpose (Field a) a -> Transpose (Field a) b
48−
49−
50−-- | @'Projectable' f@ means that @f@ is a kind of functor on 'Rel8.Table's
51−-- that allows the mapping of a 'Projection' over its underlying columns.
52−type Projectable :: (Type -> Type) -> Constraint
53−class Projectable f where
54− -- | Map a 'Projection' over @f@.
55− project :: Projecting a b
56− => Projection a b -> f a -> f b
57−
58−
59−-- | @'Biprojectable' p@ means that @p@ is a kind of bifunctor on
60−-- 'Rel8.Table's that allows the mapping of a pair of 'Projection's over its
61−-- underlying columns.
62−type Biprojectable :: (Type -> Type -> Type) -> Constraint
63−class Biprojectable p where
64− -- | Map a pair of 'Projection's over @p@.
65− biproject :: (Projecting a b, Projecting c d)
66− => Projection a b -> Projection c d -> p a c -> p b d
67−
68−
69−apply :: Projecting a b
70− => Projection a b -> Columns a context -> Columns b context
71−apply f a = case toColumns (f fields) of
72− bs -> htabulate $ \field -> case hfield bs field of
73− Field field' -> hfield a field'
src/Rel8/Table/Recontextualize.hsnew file+143
@@ -0,0 +1,143 @@
1+{-# language DataKinds #-}
2+{-# language FlexibleInstances #-}
3+{-# language FunctionalDependencies #-}
4+{-# language StandaloneKindSignatures #-}
5+{-# language TypeFamilies #-}
6+{-# language UndecidableInstances #-}
7+{-# language UndecidableSuperClasses #-}
8+
9+module Rel8.Table.Recontextualize
10+ ( Recontextualize
11+ )
12+where
13+
14+-- base
15+import Data.Functor.Identity ( Identity )
16+import Data.Kind ( Constraint, Type )
17+import Data.List.NonEmpty ( NonEmpty)
18+import Prelude
19+
20+-- rel8
21+import Rel8.Schema.Context ( Col )
22+import Rel8.Schema.HTable ( HTable )
23+import qualified Rel8.Schema.Kind as K
24+import Rel8.Schema.Null ( Sql )
25+import Rel8.Schema.Result ( Result )
26+import Rel8.Schema.Spec ( KnownSpec )
27+import Rel8.Table ( Table, Congruent )
28+import Rel8.Type ( DBType )
29+
30+-- these
31+import Data.These ( These)
32+
33+
34+-- | @Recontextualize from to a b@ is evidence that the types @a@ and @b@ are
35+-- related, and that @b@ is the same type as @a@, but after changing the
36+-- context from the initial context @from@, to the new context @to@.
37+type Recontextualize :: K.Context -> K.Context -> Type -> Type -> Constraint
38+class
39+ ( Table from a
40+ , Table to b
41+ , Congruent a b
42+ , Recontextualize from from a a
43+ , Recontextualize to to b b
44+ , Recontextualize to from b a
45+ ) => Recontextualize from to a b
46+ | a -> from
47+ , b -> to
48+ , a to -> b
49+ , b from -> a
50+
51+
52+instance Sql DBType a => Recontextualize Result Result (Identity a) (Identity a)
53+
54+
55+instance KnownSpec spec => Recontextualize from to (Col from spec) (Col to spec)
56+
57+
58+instance HTable t => Recontextualize from to (t (Col from)) (t (Col to))
59+
60+
61+instance
62+ ( Recontextualize from to a1 b1
63+ , Recontextualize from to a2 b2
64+ , from ~ Result, to ~ Result
65+ )
66+ => Recontextualize from to (Either a1 a2) (Either b1 b2)
67+
68+
69+instance (Recontextualize from to a b, from ~ Result, to ~ Result) =>
70+ Recontextualize from to [a] [b]
71+
72+
73+instance (Recontextualize from to a b, from ~ Result, to ~ Result) =>
74+ Recontextualize from to (Maybe a) (Maybe b)
75+
76+
77+instance (Recontextualize from to a b, from ~ Result, to ~ Result) =>
78+ Recontextualize from to (NonEmpty a) (NonEmpty b)
79+
80+
81+instance
82+ ( Recontextualize from to a1 b1
83+ , Recontextualize from to a2 b2
84+ , from ~ Result, to ~ Result
85+ )
86+ => Recontextualize from to (These a1 a2) (These b1 b2)
87+
88+
89+instance
90+ ( Recontextualize from to a1 b1
91+ , Recontextualize from to a2 b2
92+ )
93+ => Recontextualize from to (a1, a2) (b1, b2)
94+
95+
96+instance
97+ ( Recontextualize from to a1 b1
98+ , Recontextualize from to a2 b2
99+ , Recontextualize from to a3 b3
100+ )
101+ => Recontextualize from to (a1, a2, a3) (b1, b2, b3)
102+
103+
104+instance
105+ ( Recontextualize from to a1 b1
106+ , Recontextualize from to a2 b2
107+ , Recontextualize from to a3 b3
108+ , Recontextualize from to a4 b4
109+ )
110+ => Recontextualize from to (a1, a2, a3, a4) (b1, b2, b3, b4)
111+
112+
113+instance
114+ ( Recontextualize from to a1 b1
115+ , Recontextualize from to a2 b2
116+ , Recontextualize from to a3 b3
117+ , Recontextualize from to a4 b4
118+ , Recontextualize from to a5 b5
119+ )
120+ => Recontextualize from to (a1, a2, a3, a4, a5) (b1, b2, b3, b4, b5)
121+
122+
123+instance
124+ ( Recontextualize from to a1 b1
125+ , Recontextualize from to a2 b2
126+ , Recontextualize from to a3 b3
127+ , Recontextualize from to a4 b4
128+ , Recontextualize from to a5 b5
129+ , Recontextualize from to a6 b6
130+ )
131+ => Recontextualize from to (a1, a2, a3, a4, a5, a6) (b1, b2, b3, b4, b5, b6)
132+
133+
134+instance
135+ ( Recontextualize from to a1 b1
136+ , Recontextualize from to a2 b2
137+ , Recontextualize from to a3 b3
138+ , Recontextualize from to a4 b4
139+ , Recontextualize from to a5 b5
140+ , Recontextualize from to a6 b6
141+ , Recontextualize from to a7 b7
142+ )
143+ => Recontextualize from to (a1, a2, a3, a4, a5, a6, a7) (b1, b2, b3, b4, b5, b6, b7)
src/Rel8/Table/Rel8able.hs+85−28
@@ -1,6 +1,6 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2{-# language FlexibleInstances #-}
2{-# language FlexibleInstances #-}
3−{-# language MultiParamTypeClasses #-}
3+{-# language FunctionalDependencies #-}
4{-# language ScopedTypeVariables #-}
4{-# language ScopedTypeVariables #-}
5{-# language StandaloneKindSignatures #-}
5{-# language StandaloneKindSignatures #-}
6{-# language TypeApplications #-}
6{-# language TypeApplications #-}
@@ -15,78 +15,135 @@ module Rel8.Table.Rel8able
15where
15where
16
16
17-- base
17-- base
18+import Data.Kind ( Constraint, Type )
19+import Data.Type.Equality ( (:~:)( Refl ) )
18−import Prelude ()
20+import Prelude
19
21
20-- rel8
22-- rel8
21import Rel8.Expr ( Expr )
23import Rel8.Expr ( Expr )
22import qualified Rel8.Kind.Algebra as K
24import qualified Rel8.Kind.Algebra as K
23−import Rel8.Kind.Context ( Reifiable, contextSing )
25+import Rel8.Kind.Context
26+ ( SContext( SReify )
27+ , Reifiable, contextSing
28+ , sReifiable
29+ )
24import Rel8.Generic.Rel8able
30import Rel8.Generic.Rel8able
25 ( Rel8able, Algebra
31 ( Rel8able, Algebra
26 , GColumns, gfromColumns, gtoColumns
32 , GColumns, gfromColumns, gtoColumns
27− , GFromExprs, gfromResult, gtoResult
33+ , greify, gunreify
28 )
34 )
35+import Rel8.Schema.Context ( Col )
36+import Rel8.Schema.Dict ( Dict( Dict ) )
29import qualified Rel8.Schema.Kind as K
37import qualified Rel8.Schema.Kind as K
30import Rel8.Schema.HTable ( HConstrainTable, hdicts )
38import Rel8.Schema.HTable ( HConstrainTable, hdicts )
31import Rel8.Schema.Null ( Sql )
39import Rel8.Schema.Null ( Sql )
40+import Rel8.Schema.Reify ( hreify, hunreify, UnwrapReify )
32import Rel8.Schema.Result ( Result )
41import Rel8.Schema.Result ( Result )
33import Rel8.Table
42import Rel8.Table
34− ( Table, Columns, Context, fromColumns, toColumns
43+ ( Table, Columns, Context, Congruent, fromColumns, toColumns
35− , FromExprs, fromResult, toResult
44+ , Unreify, reify, unreify, coherence, congruence
36− , Transpose
37 )
45 )
38−import Rel8.Table.ADT ( ADT )
46+import Rel8.Schema.Spec.Constrain ( ConstrainSpec )
47+import Rel8.Table.ADT ( ADT( ADT ), ADTable, fromADT, toADT )
39import Rel8.Table.Eq ( EqTable, eqTable )
48import Rel8.Table.Eq ( EqTable, eqTable )
49+import Rel8.Table.HKD ( HKD )
40import Rel8.Table.Ord ( OrdTable, ordTable )
50import Rel8.Table.Ord ( OrdTable, ordTable )
41−import Rel8.Table.Serialize ( ToExprs )
51+import Rel8.Table.Recontextualize ( Recontextualize )
52+import Rel8.Table.Serialize ( FromExprs, ToExprs, fromResult, toResult )
42import Rel8.Type.Eq ( DBEq )
53import Rel8.Type.Eq ( DBEq )
43import Rel8.Type.Ord ( DBOrd )
54import Rel8.Type.Ord ( DBOrd )
44
55
45
56
46−instance (Rel8able t, Reifiable context, context ~ context') =>
57+instance (Rel8able t, Reifiable context) =>
47− Table context' (t context)
58+ Table context (t context)
48 where
59 where
49 type Columns (t context) = GColumns t
60 type Columns (t context) = GColumns t
50 type Context (t context) = context
61 type Context (t context) = context
51− type FromExprs (t context) = GFromExprs t
62+ type Unreify (t context) = t (UnwrapReify context)
52− type Transpose to (t context) = t to
63+
64+ fromColumns = gunreify . gfromColumns . hreify
65+ toColumns = hunreify . gtoColumns . greify
66+
67+ reify Refl = case contextSing @context of
68+ SReify context -> case sReifiable context of
69+ Dict -> greify
70+
71+ unreify Refl = case contextSing @context of
72+ SReify context -> case sReifiable context of
73+ Dict -> gunreify
74+
75+ coherence Refl _ = Refl
76+ congruence Refl _ = Refl
53
77
54− fromColumns = gfromColumns contextSing
78+
55− toColumns = gtoColumns contextSing
79+instance
56− fromResult = gfromResult @t
80+ ( Rel8able t
57− toResult = gtoResult @t
81+ , Reifiable from
82+ , Reifiable to
83+ , Congruent (t from) (t to)
84+ )
85+ => Recontextualize from to (t from) (t to)
58
86
59
87
60instance
88instance
61 ( context ~ Expr
89 ( context ~ Expr
62 , Rel8able t
90 , Rel8able t
63− , HConstrainTable (Columns (t context)) (Sql DBEq)
91+ , HConstrainTable (Columns (t context)) (ConstrainSpec (Sql DBEq))
64 )
92 )
65 => EqTable (t context)
93 => EqTable (t context)
66 where
94 where
67− eqTable = hdicts @(Columns (t context)) @(Sql DBEq)
95+ eqTable = hdicts @(Columns (t context)) @(ConstrainSpec (Sql DBEq))
68
96
69
97
70instance
98instance
71 ( context ~ Expr
99 ( context ~ Expr
72 , Rel8able t
100 , Rel8able t
73− , HConstrainTable (Columns (t context)) (Sql DBEq)
101+ , HConstrainTable (Columns (t context)) (ConstrainSpec (Sql DBEq))
74− , HConstrainTable (Columns (t context)) (Sql DBOrd)
102+ , HConstrainTable (Columns (t context)) (ConstrainSpec (Sql DBOrd))
75 )
103 )
76 => OrdTable (t context)
104 => OrdTable (t context)
77 where
105 where
78− ordTable = hdicts @(Columns (t context)) @(Sql DBOrd)
106+ ordTable = hdicts @(Columns (t context)) @(ConstrainSpec (Sql DBOrd))
107+
108+
109+type instance FromExprs (t Expr) = FromExprs' t
79
110
80
111
81instance
112instance
82− ( Rel8able t', t' ~ Choose (Algebra t) t
83− , x ~ t' Expr
113+ ( x ~ t' Expr
84 , result ~ Result
114 , result ~ Result
115+ , ToExprs' (Algebra t) t' t
85 )
116 )
86 => ToExprs x (t result)
117 => ToExprs x (t result)
118+ where
119+ fromResult = fromResult' @(Algebra t) @t'
120+ toResult = toResult' @(Algebra t) @t'
121+
122+
123+type FromExprs' :: K.Rel8able -> Type
124+type family FromExprs' t where
125+ FromExprs' (ADT t) = t Result
126+ FromExprs' (HKD a) = a
127+ FromExprs' t = t Result
128+
129+
130+type ToExprs' :: K.Algebra -> K.Rel8able -> K.Rel8able -> Constraint
131+class (algebra ~ Algebra t, Rel8able t') =>
132+ ToExprs' algebra t' t | algebra t -> t'
133+ where
134+ fromResult' :: GColumns t' (Col Result) -> t Result
135+ toResult' :: t Result -> GColumns t' (Col Result)
136+
87
137
138+instance (Algebra t ~ 'K.Product, Rel8able t, t ~ t') =>
139+ ToExprs' 'K.Product t' t
140+ where
141+ fromResult' = fromColumns
142+ toResult' = toColumns
88
143
89−type Choose :: K.Algebra -> K.Rel8able -> K.Rel8able
144+
90−type family Choose algebra t where
145+instance (Algebra t ~ 'K.Sum, ADTable t, t' ~ ADT t) =>
91− Choose 'K.Sum t = ADT t
146+ ToExprs' 'K.Sum t' t
92− Choose 'K.Product t = t
147+ where
148+ fromResult' = fromADT . ADT
149+ toResult' = (\(ADT a) -> a) . toADT
src/Rel8/Table/Serialize.hs+122−22
@@ -1,4 +1,7 @@
1{-# language AllowAmbiguousTypes #-}
1{-# language AllowAmbiguousTypes #-}
2+{-# language DataKinds #-}
3+{-# language DefaultSignatures #-}
4+{-# language DisambiguateRecordFields #-}
2{-# language FlexibleContexts #-}
5{-# language FlexibleContexts #-}
3{-# language FlexibleInstances #-}
6{-# language FlexibleInstances #-}
4{-# language FunctionalDependencies #-}
7{-# language FunctionalDependencies #-}
@@ -7,31 +10,41 @@
7{-# language StandaloneKindSignatures #-}
10{-# language StandaloneKindSignatures #-}
8{-# language TypeApplications #-}
11{-# language TypeApplications #-}
9{-# language TypeFamilies #-}
12{-# language TypeFamilies #-}
13+{-# language TypeOperators #-}
10{-# language UndecidableInstances #-}
14{-# language UndecidableInstances #-}
11
15
12module Rel8.Table.Serialize
16module Rel8.Table.Serialize
13− ( Serializable, lit, litHTable, parse
17+ ( Serializable, lit, parse
14− , ToExprs
18+ , ToExprs(..), FromExprs
19+ , TToExprs
15 )
20 )
16where
21where
17
22
18-- base
23-- base
19−import Data.Functor.Identity ( Identity( Identity ) )
20import Data.Kind ( Constraint, Type )
24import Data.Kind ( Constraint, Type )
21import Data.List.NonEmpty ( NonEmpty )
25import Data.List.NonEmpty ( NonEmpty )
26+import GHC.Generics ( Generic, Rep, from, to )
22import Prelude
27import Prelude
23
28
24-- hasql
29-- hasql
25import qualified Hasql.Decoders as Hasql
30import qualified Hasql.Decoders as Hasql
26
31
27-- rel8
32-- rel8
28−import Rel8.Expr ( Expr )
33+import Rel8.Expr ( Expr, Col( E ) )
29import Rel8.Expr.Serialize ( slitExpr, sparseValue )
34import Rel8.Expr.Serialize ( slitExpr, sparseValue )
35+import Rel8.FCF ( Eval, Exp )
36+import Rel8.Generic.Record ( Record(..) )
37+import Rel8.Generic.Table
38+ ( GGToExprs, GGColumns, ggfromResult, ggtoResult
39+ , GAlgebra
40+ )
41+import Rel8.Kind.Algebra ( KnownAlgebra )
30import Rel8.Schema.HTable ( HTable, htabulate, htabulateA, hfield, hspecs )
42import Rel8.Schema.HTable ( HTable, htabulate, htabulateA, hfield, hspecs )
43+import Rel8.Schema.HTable.Identity ( HIdentity( HType ) )
31import Rel8.Schema.Null ( NotNull, Sql )
44import Rel8.Schema.Null ( NotNull, Sql )
32−import Rel8.Schema.Result ( Result )
45+import Rel8.Schema.Result ( Col( R ), Result )
33−import Rel8.Schema.Spec ( Spec(..) )
46+import Rel8.Schema.Spec ( SSpec(..), KnownSpec )
34−import Rel8.Table ( Table, fromColumns, FromExprs, fromResult, toResult )
47+import Rel8.Table ( Table, Columns, fromColumns, toColumns, TColumns )
35import Rel8.Type ( DBType )
48import Rel8.Type ( DBType )
36
49
37-- semigroupoids
50-- semigroupoids
@@ -40,21 +53,71 @@ import Data.Functor.Apply ( WrappedApplicative(..) )
40
53
41-- | @ToExprs exprs a@ is evidence that the types @exprs@ and @a@ describe
54-- | @ToExprs exprs a@ is evidence that the types @exprs@ and @a@ describe
42-- essentially the same type, but @exprs@ is in the 'Expr' context, and @a@ is
55-- essentially the same type, but @exprs@ is in the 'Expr' context, and @a@ is
43−-- a normal Haskell type.
56+-- in the 'Result' context.
44type ToExprs :: Type -> Type -> Constraint
57type ToExprs :: Type -> Type -> Constraint
45−class Table Expr exprs => ToExprs exprs a
58+class Table Expr exprs => ToExprs exprs a where
46−
59+ fromResult :: Columns exprs (Col Result) -> a
47−
60+ toResult :: a -> Columns exprs (Col Result)
61+
62+ default fromResult ::
63+ ( Generic (Record a)
64+ , KnownAlgebra (GAlgebra (Rep (Record exprs)))
65+ , Eval (GGToExprs (GAlgebra (Rep (Record exprs))) TToExprs TColumns (Rep (Record exprs)) (Rep (Record a)))
66+ , Columns exprs ~ Eval (GGColumns (GAlgebra (Rep (Record exprs))) TColumns (Rep (Record exprs)))
67+ )
68+ => Columns exprs (Col Result) -> a
69+ fromResult =
70+ unrecord .
71+ to .
72+ ggfromResult
73+ @(GAlgebra (Rep (Record exprs)))
74+ @TToExprs
75+ @TColumns
76+ @(Rep (Record exprs))
77+ (\(_ :: proxy expr) -> fromResult @expr)
78+
79+ default toResult ::
80+ ( Generic (Record a)
81+ , KnownAlgebra (GAlgebra (Rep (Record exprs)))
82+ , Eval (GGToExprs (GAlgebra (Rep (Record exprs))) TToExprs TColumns (Rep (Record exprs)) (Rep (Record a)))
83+ , Columns exprs ~ Eval (GGColumns (GAlgebra (Rep (Record exprs))) TColumns (Rep (Record exprs)))
84+ )
85+ => a -> Columns exprs (Col Result)
86+ toResult =
87+ ggtoResult
88+ @(GAlgebra (Rep (Record exprs)))
89+ @TToExprs
90+ @TColumns
91+ @(Rep (Record exprs))
92+ (\(_ :: proxy expr) -> toResult @expr) .
93+ from .
94+ Record
95+
96+
97+data TToExprs :: Type -> Type -> Exp Constraint
98+type instance Eval (TToExprs exprs a) = ToExprs exprs a
99+
100+
48−instance {-# OVERLAPPABLE #-} (Sql DBType a, x ~ Expr a) => ToExprs x a
101+instance {-# OVERLAPPABLE #-} (Sql DBType a, x ~ Expr a) => ToExprs x a where
49−
102+ fromResult (HType (R a)) = a
50−
103+ toResult = HType . R
104+
105+
51−instance (Sql DBType a, x ~ [a]) => ToExprs (Expr x) [a]
106+instance (Sql DBType a, x ~ [a]) => ToExprs (Expr x) [a] where
107+ fromResult (HType (R a)) = a
108+ toResult = HType . R
52
109
53
110
54instance (Sql DBType a, NotNull a, x ~ Maybe a) => ToExprs (Expr x) (Maybe a)
111instance (Sql DBType a, NotNull a, x ~ Maybe a) => ToExprs (Expr x) (Maybe a)
112+ where
113+ fromResult (HType (R a)) = a
114+ toResult = HType . R
55
115
56
116
57instance (Sql DBType a, NotNull a, x ~ NonEmpty a) => ToExprs (Expr x) (NonEmpty a)
117instance (Sql DBType a, NotNull a, x ~ NonEmpty a) => ToExprs (Expr x) (NonEmpty a)
118+ where
119+ fromResult (HType (R a)) = a
120+ toResult = HType . R
58
121
59
122
60instance (ToExprs exprs1 a, ToExprs exprs2 b, x ~ (exprs1, exprs2)) =>
123instance (ToExprs exprs1 a, ToExprs exprs2 b, x ~ (exprs1, exprs2)) =>
@@ -116,6 +179,43 @@ instance
116 => ToExprs x (a, b, c, d, e, f, g)
179 => ToExprs x (a, b, c, d, e, f, g)
117
180
118
181
182+instance (HTable t, result ~ Col Result, x ~ t (Col Expr)) =>
183+ ToExprs x (t result)
184+ where
185+ fromResult = id
186+ toResult = id
187+
188+
189+instance (KnownSpec spec, x ~ Col Expr spec) =>
190+ ToExprs x (Col Result spec)
191+ where
192+ fromResult = fromColumns
193+ toResult = toColumns
194+
195+
196+-- | The @FromExprs@ type function maps a type in the @Expr@ context to the
197+-- corresponding type in the @Result@ context.
198+type FromExprs :: Type -> Type
199+type family FromExprs a
200+type instance FromExprs (Expr a) = a
201+type instance FromExprs (Col Expr spec) = Col Result spec
202+type instance FromExprs (a, b) = (FromExprs a, FromExprs b)
203+type instance FromExprs (a, b, c) = (FromExprs a, FromExprs b, FromExprs c)
204+type instance FromExprs (a, b, c, d) =
205+ (FromExprs a, FromExprs b, FromExprs c, FromExprs d)
206+type instance FromExprs (a, b, c, d, e) =
207+ (FromExprs a, FromExprs b, FromExprs c, FromExprs d, FromExprs e)
208+type instance FromExprs (a, b, c, d, e, f) =
209+ ( FromExprs a, FromExprs b, FromExprs c, FromExprs d, FromExprs e
210+ , FromExprs f
211+ )
212+type instance FromExprs (a, b, c, d, e, f, g) =
213+ ( FromExprs a, FromExprs b, FromExprs c, FromExprs d, FromExprs e
214+ , FromExprs f, FromExprs g
215+ )
216+type instance FromExprs (t (Col Expr)) = t (Col Result)
217+
218+
119-- | @Serializable@ witnesses the one-to-one correspondence between the type
219-- | @Serializable@ witnesses the one-to-one correspondence between the type
120-- @sql@, which contains SQL expressions, and the type @haskell@, which
220-- @sql@, which contains SQL expressions, and the type @haskell@, which
121-- contains the Haskell decoding of rows containing @sql@ SQL expressions.
221-- contains the Haskell decoding of rows containing @sql@ SQL expressions.
@@ -128,21 +228,21 @@ instance {-# OVERLAPPING #-} Sql DBType a => Serializable (Expr a) a
128-- | Use @lit@ to turn literal Haskell values into expressions. @lit@ is
228-- | Use @lit@ to turn literal Haskell values into expressions. @lit@ is
129-- capable of lifting single @Expr@s to full tables.
229-- capable of lifting single @Expr@s to full tables.
130lit :: forall exprs a. Serializable exprs a => a -> exprs
230lit :: forall exprs a. Serializable exprs a => a -> exprs
131−lit = fromColumns . litHTable . toResult @_ @exprs
231+lit = fromColumns . litHTable . toResult @exprs
132
232
133
233
134parse :: forall exprs a. Serializable exprs a => Hasql.Row a
234parse :: forall exprs a. Serializable exprs a => Hasql.Row a
135−parse = fromResult @_ @exprs <$> parseHTable
235+parse = fromResult @exprs <$> parseHTable
136
236
137
237
138−litHTable :: HTable t => t Result -> t Expr
238+litHTable :: HTable t => t (Col Result) -> t (Col Expr)
139litHTable as = htabulate $ \field ->
239litHTable as = htabulate $ \field ->
140 case hfield hspecs field of
240 case hfield hspecs field of
141− Spec {nullity, info} -> case hfield as field of
241+ SSpec {nullity, info} -> case hfield as field of
142− Identity value -> slitExpr nullity info value
242+ R value -> E (slitExpr nullity info value)
143
243
144
244
145−parseHTable :: HTable t => Hasql.Row (t Result)
245+parseHTable :: HTable t => Hasql.Row (t (Col Result))
146parseHTable = unwrapApplicative $ htabulateA $ \field ->
246parseHTable = unwrapApplicative $ htabulateA $ \field ->
147 WrapApplicative $ case hfield hspecs field of
247 WrapApplicative $ case hfield hspecs field of
148− Spec {nullity, info} -> Identity <$> sparseValue nullity info
248+ SSpec {nullity, info} -> R <$> sparseValue nullity info
src/Rel8/Table/These.hs+49−71
@@ -20,36 +20,36 @@ module Rel8.Table.These
20 , isThisTable, isThatTable, isThoseTable
20 , isThisTable, isThatTable, isThoseTable
21 , hasHereTable, hasThereTable
21 , hasHereTable, hasThereTable
22 , justHereTable, justThereTable
22 , justHereTable, justThereTable
23− , alignMaybeTable
24 , aggregateTheseTable
23 , aggregateTheseTable
25 , nameTheseTable
24 , nameTheseTable
26 )
25 )
27where
26where
28
27
29-- base
28-- base
29+import Control.Category ( id )
30import Data.Bifunctor ( Bifunctor, bimap )
30import Data.Bifunctor ( Bifunctor, bimap )
31import Data.Kind ( Type )
31import Data.Kind ( Type )
32import Data.Maybe ( isJust )
32import Data.Maybe ( isJust )
33+import Data.Type.Equality ( apply )
33−import Prelude hiding ( null, undefined )
34+import Prelude hiding ( id, undefined )
34
35
35-- rel8
36-- rel8
36import Rel8.Aggregate ( Aggregate )
37import Rel8.Aggregate ( Aggregate )
37import Rel8.Expr ( Expr )
38import Rel8.Expr ( Expr )
38−import Rel8.Expr.Bool ( (&&.), (||.), boolExpr, not_ )
39+import Rel8.Expr.Bool ( (&&.), not_ )
39−import Rel8.Expr.Null ( null, isNonNull )
40+import Rel8.Expr.Null ( isNonNull )
40import Rel8.Kind.Context ( Reifiable )
41import Rel8.Kind.Context ( Reifiable )
42+import Rel8.Schema.Context.Abstract ( Abstract )
41import Rel8.Schema.Context.Nullify ( Nullifiable )
43import Rel8.Schema.Context.Nullify ( Nullifiable )
42import Rel8.Schema.Dict ( Dict( Dict ) )
44import Rel8.Schema.Dict ( Dict( Dict ) )
43−import Rel8.Schema.HTable.Label ( hlabel, hrelabel, hunlabel )
45+import Rel8.Schema.HTable.Label ( hlabel, hunlabel )
44import Rel8.Schema.HTable.Identity ( HIdentity(..) )
46import Rel8.Schema.HTable.Identity ( HIdentity(..) )
45−import Rel8.Schema.HTable.Maybe ( HMaybeTable(..) )
46import Rel8.Schema.HTable.These ( HTheseTable(..) )
47import Rel8.Schema.HTable.These ( HTheseTable(..) )
47import qualified Rel8.Schema.Kind as K
48import qualified Rel8.Schema.Kind as K
48import Rel8.Schema.Name ( Name )
49import Rel8.Schema.Name ( Name )
49import Rel8.Table
50import Rel8.Table
50 ( Table, Columns, Context, fromColumns, toColumns
51 ( Table, Columns, Context, fromColumns, toColumns
51− , FromExprs, fromResult, toResult
52+ , coherence, congruence, reify, unreify
52− , Transpose
53 )
53 )
54import Rel8.Table.Eq ( EqTable, eqTable )
54import Rel8.Table.Eq ( EqTable, eqTable )
55import Rel8.Table.Maybe
55import Rel8.Table.Maybe
@@ -61,8 +61,8 @@ import Rel8.Table.Maybe
61 )
61 )
62import Rel8.Table.Nullify ( Nullify, guard )
62import Rel8.Table.Nullify ( Nullify, guard )
63import Rel8.Table.Ord ( OrdTable, ordTable )
63import Rel8.Table.Ord ( OrdTable, ordTable )
64−import Rel8.Table.Projection ( Biprojectable, Projectable, biproject, project )
64+import Rel8.Table.Recontextualize ( Recontextualize )
65−import Rel8.Table.Serialize ( ToExprs )
65+import Rel8.Table.Serialize ( FromExprs, ToExprs, fromResult, toResult )
66import Rel8.Table.Undefined ( undefined )
66import Rel8.Table.Undefined ( undefined )
67import Rel8.Type.Tag ( MaybeTag )
67import Rel8.Type.Tag ( MaybeTag )
68
68
@@ -71,8 +71,7 @@ import Data.Functor.Apply ( Apply, (<.>) )
71import Data.Functor.Bind ( Bind, (>>-) )
71import Data.Functor.Bind ( Bind, (>>-) )
72
72
73-- these
73-- these
74−import Data.These ( These( This, That, These ) )
74+import Data.These ( These )
75−import Data.These.Combinators ( justHere, justThere )
76
75
77
76
78-- | @TheseTable a b@ is a Rel8 table that contains either the table @a@, the
77-- | @TheseTable a b@ is a Rel8 table that contains either the table @a@, the
@@ -90,18 +89,10 @@ data TheseTable context a b = TheseTable
90 deriving stock Functor
89 deriving stock Functor
91
90
92
91
93−instance Biprojectable (TheseTable context) where
94− biproject f g (TheseTable a b) = TheseTable (project f a) (project g b)
95−
96−
97instance Nullifiable context => Bifunctor (TheseTable context) where
92instance Nullifiable context => Bifunctor (TheseTable context) where
98 bimap f g (TheseTable a b) = TheseTable (fmap f a) (fmap g b)
93 bimap f g (TheseTable a b) = TheseTable (fmap f a) (fmap g b)
99
94
100
95
101−instance Projectable (TheseTable context a) where
102− project f (TheseTable a b) = TheseTable a (project f b)
103−
104−
105instance (context ~ Expr, Table Expr a, Semigroup a) =>
96instance (context ~ Expr, Table Expr a, Semigroup a) =>
106 Apply (TheseTable context a)
97 Apply (TheseTable context a)
107 where
98 where
@@ -148,16 +139,12 @@ instance (context ~ Expr, Table Expr a, Table Expr b, Semigroup a, Semigroup b)
148
139
149instance
140instance
150 ( Table context a, Table context b
141 ( Table context a, Table context b
151− , Reifiable context, context ~ context'
142+ , Reifiable context, Abstract context, context ~ context'
152 )
143 )
153 => Table context' (TheseTable context a b)
144 => Table context' (TheseTable context a b)
154 where
145 where
155 type Columns (TheseTable context a b) = HTheseTable (Columns a) (Columns b)
146 type Columns (TheseTable context a b) = HTheseTable (Columns a) (Columns b)
156 type Context (TheseTable context a b) = Context a
147 type Context (TheseTable context a b) = Context a
157− type FromExprs (TheseTable context a b) =
158− These (FromExprs a) (FromExprs b)
159− type Transpose to (TheseTable context a b) =
160− TheseTable to (Transpose to a) (Transpose to b)
161
148
162 toColumns TheseTable {here, there} = HTheseTable
149 toColumns TheseTable {here, there} = HTheseTable
163 { hhereTag = hlabel $ HIdentity $ tag here
150 { hhereTag = hlabel $ HIdentity $ tag here
@@ -179,48 +166,38 @@ instance
179 }
166 }
180 }
167 }
181
168
182− toResult tables = HTheseTable
169+ reify proof TheseTable {here, there} = TheseTable
183− { hhereTag = hrelabel hhereTag
170+ { here = reify proof here
184− , hhere = hrelabel hhere
171+ , there = reify proof there
185− , hthereTag = hrelabel hthereTag
186− , hthere = hrelabel hthere
187 }
172 }
188− where
173+ unreify proof TheseTable {here, there} = TheseTable
189− HMaybeTable
174+ { here = unreify proof here
190− { htag = hhereTag
175+ , there = unreify proof there
191− , hjust = hhere
176+ }
192− } = toResult @_ @(MaybeTable context a) (justHere tables)
177+
193− HMaybeTable
178+ coherence = coherence @context @a
194− { htag = hthereTag
179+ congruence proof abstract =
195− , hjust = hthere
180+ id `apply`
196− } = toResult @_ @(MaybeTable context b) (justThere tables)
181+ congruence @context @a proof abstract `apply`
197−
182+ congruence @context @b proof abstract
198− fromResult HTheseTable {hhereTag, hhere, hthereTag, hthere} =
183+
199− case (here, there) of
184+
200− (Just a, Nothing) -> This a
185+instance
201− (Nothing, Just b) -> That b
186+ ( Reifiable from, Abstract from, from ~ from'
202− (Just a, Just b) -> These a b
187+ , Reifiable to, Abstract to, to ~ to'
203− _ -> error "These.fromColumns: mismatch between tags and data"
188+ , Recontextualize from to a1 b1
204− where
189+ , Recontextualize from to a2 b2
205− here = fromResult @_ @(MaybeTable context a) mhere
190+ )
206− there = fromResult @_ @(MaybeTable context b) mthere
191+ => Recontextualize from to (TheseTable from' a1 a2) (TheseTable to' b1 b2)
207− mhere = HMaybeTable
208− { htag = hrelabel hhereTag
209− , hjust = hrelabel hhere
210− }
211− mthere = HMaybeTable
212− { htag = hrelabel hthereTag
213− , hjust = hrelabel hthere
214− }
215
192
216
193
217instance (EqTable a, EqTable b, context ~ Expr) =>
194instance (EqTable a, EqTable b, context ~ Expr) =>
218 EqTable (TheseTable context a b)
195 EqTable (TheseTable context a b)
219 where
196 where
220 eqTable = HTheseTable
197 eqTable = HTheseTable
221− { hhereTag = hlabel (HIdentity Dict)
198+ { hhereTag = hlabel (HType Dict)
222 , hhere = hlabel (eqTable @(Nullify context a))
199 , hhere = hlabel (eqTable @(Nullify context a))
223− , hthereTag = hlabel (HIdentity Dict)
200+ , hthereTag = hlabel (HType Dict)
224 , hthere = hlabel (eqTable @(Nullify context b))
201 , hthere = hlabel (eqTable @(Nullify context b))
225 }
202 }
226
203
@@ -229,15 +206,26 @@ instance (OrdTable a, OrdTable b, context ~ Expr) =>
229 OrdTable (TheseTable context a b)
206 OrdTable (TheseTable context a b)
230 where
207 where
231 ordTable = HTheseTable
208 ordTable = HTheseTable
232− { hhereTag = hlabel (HIdentity Dict)
209+ { hhereTag = hlabel (HType Dict)
233 , hhere = hlabel (ordTable @(Nullify context a))
210 , hhere = hlabel (ordTable @(Nullify context a))
234− , hthereTag = hlabel (HIdentity Dict)
211+ , hthereTag = hlabel (HType Dict)
235 , hthere = hlabel (ordTable @(Nullify context b))
212 , hthere = hlabel (ordTable @(Nullify context b))
236 }
213 }
237
214
238
215
216+type instance FromExprs (TheseTable _context a b) =
217+ These (FromExprs a) (FromExprs b)
218+
219+
239instance (ToExprs exprs1 a, ToExprs exprs2 b, x ~ TheseTable Expr exprs1 exprs2) =>
220instance (ToExprs exprs1 a, ToExprs exprs2 b, x ~ TheseTable Expr exprs1 exprs2) =>
240 ToExprs x (These a b)
221 ToExprs x (These a b)
222+ where
223+ fromResult =
224+ bimap (fromResult @exprs1) (fromResult @exprs2) .
225+ fromColumns
226+ toResult =
227+ toColumns .
228+ bimap (toResult @exprs1) (toResult @exprs2)
241
229
242
230
243-- | Test if a 'TheseTable' was constructed with 'thisTable'.
231-- | Test if a 'TheseTable' was constructed with 'thisTable'.
@@ -289,16 +277,6 @@ justThereTable :: TheseTable context a b -> MaybeTable context b
289justThereTable = there
277justThereTable = there
290
278
291
279
292−-- | Construct a @TheseTable@ from two 'MaybeTable's.
293−alignMaybeTable :: ()
294− => MaybeTable Expr a
295− -> MaybeTable Expr b
296− -> MaybeTable Expr (TheseTable Expr a b)
297−alignMaybeTable a b = MaybeTable tag (pure (TheseTable a b))
298− where
299− tag = boolExpr null mempty (isJustTable a ||. isJustTable b)
300−
301−
302-- | Construct a @TheseTable@. Corresponds to 'This'.
280-- | Construct a @TheseTable@. Corresponds to 'This'.
303thisTable :: Table Expr b => a -> TheseTable Expr a b
281thisTable :: Table Expr b => a -> TheseTable Expr a b
304thisTable a = TheseTable (justTable a) nothingTable
282thisTable a = TheseTable (justTable a) nothingTable
src/Rel8/Table/Transpose.hsdeleted−46
@@ -1,46 +0,0 @@
1−{-# language DataKinds #-}
2−{-# language FlexibleInstances #-}
3−{-# language FunctionalDependencies #-}
4−{-# language StandaloneKindSignatures #-}
5−{-# language TypeFamilies #-}
6−{-# language UndecidableInstances #-}
7−
8−module Rel8.Table.Transpose
9− ( Transposes
10− )
11−where
12−
13−-- base
14−import Data.Kind ( Constraint, Type )
15−import Prelude ()
16−
17−-- rel8
18−import qualified Rel8.Schema.Kind as K
19−import Rel8.Table ( Table, Transpose, Congruent )
20−
21−
22−-- | @'Transposes' from to a b@ means that @a@ and @b@ are 'Table's, in the
23−-- @from@ and @to@ contexts respectively, which share the same underlying
24−-- structure. In other words, @b@ is a version of @a@ transposed from the
25−-- @from@ context to the @to@ context (and vice versa).
26−type Transposes :: K.Context -> K.Context -> Type -> Type -> Constraint
27−class
28− ( Table from a
29− , Table to b
30− , Congruent a b
31− , b ~ Transpose to a
32− , a ~ Transpose from b
33− )
34− => Transposes from to a b
35− | a -> from
36− , b -> to
37− , a to -> b
38− , b from -> a
39−instance
40− ( Table from a
41− , Table to b
42− , Congruent a b
43− , b ~ Transpose to a
44− , a ~ Transpose from b
45− )
46− => Transposes from to a b
src/Rel8/Table/Undefined.hs+5−5
@@ -11,16 +11,16 @@ where
11import Prelude hiding ( undefined )
11import Prelude hiding ( undefined )
12
12
13-- rel8
13-- rel8
14−import Rel8.Expr ( Expr )
14+import Rel8.Expr ( Expr, Col( E ) )
15import Rel8.Expr.Null ( snull, unsafeUnnullify )
15import Rel8.Expr.Null ( snull, unsafeUnnullify )
16import Rel8.Schema.HTable ( htabulate, hfield, hspecs )
16import Rel8.Schema.HTable ( htabulate, hfield, hspecs )
17import Rel8.Schema.Null ( Nullity( Null, NotNull ) )
17import Rel8.Schema.Null ( Nullity( Null, NotNull ) )
18−import Rel8.Schema.Spec ( Spec(..) )
18+import Rel8.Schema.Spec ( SSpec(..) )
19import Rel8.Table ( Table, fromColumns )
19import Rel8.Table ( Table, fromColumns )
20
20
21
21
22undefined :: Table Expr a => a
22undefined :: Table Expr a => a
23undefined = fromColumns $ htabulate $ \field -> case hfield hspecs field of
23undefined = fromColumns $ htabulate $ \field -> case hfield hspecs field of
24− Spec {nullity, info} -> case nullity of
24+ SSpec {nullity, info} -> case nullity of
25− Null -> snull info
25+ Null -> E (snull info)
26− NotNull -> unsafeUnnullify (snull info)
26+ NotNull -> E (unsafeUnnullify (snull info))
src/Rel8/Table/Window.hsdeleted−43
@@ -1,43 +0,0 @@
1−{-# language MonoLocalBinds #-}
2−
3−module Rel8.Table.Window
4− ( cumulative
5− , cumulative_
6− , currentRow
7− )
8−where
9−
10−-- base
11−import Prelude
12−
13−-- opaleye
14−import qualified Opaleye.Window as Opaleye
15−
16−-- rel8
17−import Rel8.Aggregate ( Aggregates )
18−import qualified Rel8.Expr.Window as Expr
19−import Rel8.Schema.HTable ( hfield, htabulateA )
20−import Rel8.Table ( fromColumns, toColumns )
21−import Rel8.Window ( Window( Window ) )
22−
23−
24−-- | 'cumulative' allows the use of aggregation functions in 'Window'
25−-- expressions. In particular, @'cumulative' 'Rel8.sum'@
26−-- (when combined with 'Rel8.Window.orderPartitionBy') gives a running total,
27−-- also known as a \"cumulative sum\", hence the name @cumulative@.
28−cumulative :: Aggregates aggregates exprs => (a -> aggregates) -> Window a exprs
29−cumulative f =
30− fmap fromColumns $
31− htabulateA $ \field ->
32− Expr.cumulative ((`hfield` field) . toColumns . f)
33−
34−
35−-- | A version of 'cumulative' for use with nullary aggregators like
36−-- 'Rel8.Expr.Aggregate.countStar'.
37−cumulative_ :: Aggregates aggregates exprs => aggregates -> Window a exprs
38−cumulative_ = cumulative . const
39−
40−
41−-- | Return every column of the current row of a window query.
42−currentRow :: Window a a
43−currentRow = Window $ Opaleye.over (Opaleye.noWindowFunction id) mempty mempty
src/Rel8/Tabulate.hsdeleted−640
@@ -1,640 +0,0 @@
1−{-# language FlexibleContexts #-}
2−{-# language MonoLocalBinds #-}
3−{-# language ScopedTypeVariables #-}
4−{-# language StandaloneKindSignatures #-}
5−{-# language TypeApplications #-}
6−{-# language TupleSections #-}
7−{-# language UndecidableInstances #-}
8−
9−-- | "Rel8.Tabulate" provides an alternative API ('Tabulation') for writing
10−-- queries that complements the main "Rel8" API ('Query').
11−
12−module Rel8.Tabulate
13− (
14− Tabulation
15−
16− -- * Interfacing with 'Query's
17− , fromQuery
18− , toQuery
19− , liftQuery
20− , through
21− , lookup
22−
23− -- * Aggregation and Ordering
24− , aggregate
25− , distinct
26− , order
27−
28− -- ** Magic 'Tabulation's
29− -- $magic
30− , count
31− , optional
32− , many
33− , some
34− , exists
35− , present
36− , absent
37−
38− -- * Natural joins
39− , align
40− , alignWith
41− , leftAlign
42− , leftAlignWith
43− , rightAlign
44− , rightAlignWith
45− , zip
46− , zipWith
47− , similarity
48− , difference
49− )
50−where
51−
52−-- base
53−import Control.Applicative ( (<|>), empty, liftA2 )
54−import Control.Monad ( liftM2 )
55−import Data.Bifunctor ( Bifunctor, bimap, first, second )
56−import Data.Foldable ( traverse_ )
57−import Data.Function ( on )
58−import Data.Functor.Contravariant ( Contravariant, (>$<), contramap )
59−import Data.Int ( Int64 )
60−import Data.Kind ( Type )
61−import Data.Maybe ( fromJust, fromMaybe )
62−import Prelude hiding ( lookup, zip, zipWith )
63−
64−-- bifunctors
65−import Data.Bifunctor.Clown ( Clown( Clown ), runClown )
66−
67−-- comonad
68−import Control.Comonad ( extract )
69−
70−-- opaleye
71−import qualified Opaleye.Aggregate as Opaleye
72−import qualified Opaleye.Order as Opaleye ( orderBy, distinctOnExplicit )
73−
74−-- profunctors
75−import Data.Profunctor ( dimap, lmap )
76−
77−-- product-profunctors
78−import Data.Profunctor.Product
79− ( ProductProfunctor, (***!)
80− , SumProfunctor, (+++!)
81− )
82−import qualified Data.Profunctor.Product as PP
83−
84−-- rel8
85−import Rel8.Aggregate ( Aggregates )
86−import Rel8.Expr ( Expr )
87−import Rel8.Expr.Aggregate ( countStar )
88−import Rel8.Expr.Bool ( true )
89−import Rel8.Order ( Order( Order ) )
90−import Rel8.Query ( Query )
91−import qualified Rel8.Query.Exists as Q ( exists, present, absent )
92−import Rel8.Query.Filter ( where_ )
93−import Rel8.Query.List ( catNonEmptyTable )
94−import qualified Rel8.Query.Maybe as Q ( optional )
95−import Rel8.Query.Opaleye ( mapOpaleye, unsafePeekQuery )
96−import Rel8.Query.Rebind ( rebind )
97−import Rel8.Query.These ( alignBy )
98−import Rel8.Table ( Table, fromColumns, toColumns )
99−import Rel8.Table.Aggregate ( hgroupBy, listAgg, nonEmptyAgg )
100−import Rel8.Table.Alternative
101− ( AltTable, (<|>:)
102− , AlternativeTable, emptyTable
103− )
104−import Rel8.Table.Cols ( fromCols, toCols )
105−import Rel8.Table.Eq ( EqTable, (==:), eqTable )
106−import Rel8.Table.List ( ListTable( ListTable ) )
107−import Rel8.Table.Maybe ( MaybeTable( MaybeTable ), maybeTable )
108−import Rel8.Table.NonEmpty ( NonEmptyTable( NonEmptyTable ) )
109−import Rel8.Table.Opaleye ( aggregator, unpackspec )
110−import Rel8.Table.Ord ( OrdTable )
111−import Rel8.Table.Order ( ascTable )
112−import Rel8.Table.Projection
113− ( Biprojectable, biproject
114− , Projectable, project
115− , apply
116− )
117−import Rel8.Table.These ( TheseTable( TheseTable ), theseTable )
118−
119−-- semigroupoids
120−import Data.Functor.Apply ( Apply, liftF2 )
121−import Data.Functor.Bind ( Bind, (>>-) )
122−
123−
124−type Key :: Type -> Type
125−type Key = Maybe
126−
127−
128−cat :: Table Expr k => Key k -> Query k
129−cat = maybe emptyTable pure
130−
131−
132−key :: (ProductProfunctor p, SumProfunctor p)
133− => p a b -> p (Key a) (Key b)
134−key a = dimap from to (PP.empty +++! a)
135− where
136− from = maybe (Left ()) Right
137− to = either (const Nothing) Just
138−
139−
140−keyed :: (ProductProfunctor p, SumProfunctor p)
141− => p k l -> p a b -> p (Key k, a) (Key l, b)
142−keyed k a = key k ***! a
143−
144−
145−type Predicate :: Type -> Type
146−newtype Predicate a = Predicate (Maybe (a -> Expr Bool))
147−
148−
149−instance Contravariant Predicate where
150− contramap f (Predicate a) = Predicate (lmap f <$> a)
151−
152−
153−instance Semigroup (Predicate k) where
154− Predicate ma <> Predicate mb = Predicate $ ma <|> mb
155−
156−
157−instance Monoid (Predicate k) where
158− mempty = Predicate Nothing
159−
160−
161−match :: EqTable k => Key k -> Predicate k
162−match = Predicate . fmap (==:)
163−
164−
165−ensure :: Predicate k -> Key k -> Query ()
166−ensure (Predicate mp) = traverse_ (\k -> traverse_ (\p -> where_ (p k)) mp)
167−
168−
169−-- | A @'Tabulation' k a@ is like a @'Query' a@, except that each row also
170−-- has a key @k@ in addition to the value @a@. 'Tabulation's can be composed
171−-- monadically just like 'Query's, but the resulting join is more like a
172−-- @NATURAL JOIN@ (based on the common key column(s) @k@) than the
173−-- @CROSS JOIN@ given by 'Query'.
174−--
175−-- Another way to think of @'Tabulation' k a@ is as analogous to @Map k a@ in
176−-- the same way @'Query' a@ is analogous to @[a]@. However, there's nothing
177−-- stopping a 'Tabulation' from containing multiple rows with the same key, so
178−-- technically @Map k (NonEmpty a)@ is more accurate.
179−--
180−-- 'Tabulation's can be created from 'Query's with 'fromQuery' and 'liftQuery'
181−-- and converted back to 'Query's with 'lookup' and 'toQuery' (though note the
182−-- caveats that come with the latter).
183−type Tabulation :: Type -> Type -> Type
184−newtype Tabulation k a = Tabulation (Predicate k -> Query (Key k, a))
185−
186−
187−instance Biprojectable Tabulation where
188− biproject f g =
189− bimap
190− (fromColumns . apply f . toColumns)
191− (fromColumns . apply g . toColumns)
192−
193−
194−instance Bifunctor Tabulation where
195− bimap f g (Tabulation a) = Tabulation $ \p ->
196− bimap (fmap f) g <$> a (f >$< p)
197−
198−
199−instance Functor (Tabulation k) where
200− fmap = second
201−
202−
203−instance Projectable (Tabulation k) where
204− project f = fmap (fromColumns . apply f . toColumns)
205−
206−
207−-- | If @'Tabulation' k a@ is @Map k (NonEmpty a)@, then @(<.>)@ is
208−-- @intersectionWith (liftA2 (<*>))@
209−instance EqTable k => Apply (Tabulation k) where
210− liftF2 = liftA2
211−
212−
213−-- | @pure = 'liftQuery' . pure@
214−instance EqTable k => Applicative (Tabulation k) where
215− pure = liftQuery . pure
216− liftA2 = liftM2
217−
218−
219−instance EqTable k => Bind (Tabulation k) where
220− Tabulation as >>- f = Tabulation $ \p -> do
221− (k, a) <- as p
222− case f a of
223− Tabulation bs -> do
224− let p' = match k
225− (k', b) <- bs (p' <> p)
226− ensure p' k'
227− pure (k' <|> k, b)
228−
229−
230−instance EqTable k => Monad (Tabulation k) where
231− (>>=) = (>>-)
232−
233−
234−-- | If @'Tabulation' k a@ is @Map k (NonEmpty a)@, then @(<|>:)@ is
235−-- @unionWith (<>)@.
236−instance EqTable k => AltTable (Tabulation k) where
237− tas <|>: tbs = do
238− eas <- peek tas
239− ebs <- peek tbs
240− case (eas, ebs) of
241− (Left as, Left bs) -> liftQuery $ as <|>: bs
242− (Right as, Right bs) -> fromQuery $ as <|>: bs
243− _ -> catNonEmptyTable `through` ((<>) `on` some) tas tbs
244−
245−
246−instance EqTable k => AlternativeTable (Tabulation k) where
247− emptyTable = Tabulation $ const $ fmap (empty,) emptyTable
248−
249−
250−-- | If @'Tabulation' k a@ is @Map k (NonEmpty a)@, then @(<>)@ is
251−-- @unionWith (liftA2 (<>))@.
252−instance (EqTable k, Table Expr a, Semigroup a) => Semigroup (Tabulation k a)
253− where
254− (<>) = alignWith (theseTable id id (<>))
255−
256−
257−instance (EqTable k, Table Expr a, Semigroup a) => Monoid (Tabulation k a)
258− where
259− mempty = emptyTable
260−
261−
262−-- | Any 'Query' of key-value pairs @(k, a)@ can be a @'Tabulation' k a@.
263−fromQuery :: Query (k, a) -> Tabulation k a
264−fromQuery = Tabulation . const . fmap (first pure)
265−
266−
267−-- | Convert a @'Tabulation' k a@ back into a 'Query' of key-value pairs.
268−--
269−-- Note that the result of a 'toQuery' is undefined (will always return zero
270−-- rows) on 'Tabulation's constructed with 'liftQuery' or 'pure'. So while
271−-- @toQuery . fromQuery@ is always @id@, @fromQuery . toQuery@ is not.
272−--
273−-- A safer, more predictable alternative to 'toQuery' is to use 'lookup' with
274−-- an explicit set of keys:
275−--
276−-- @
277−-- do
278−-- k <- keys
279−-- a <- lookup k tabulation
280−-- pure (k, a)
281−-- @
282−--
283−-- Having said that, in practice, most legitimate uses of 'Tabulation' will
284−-- have a well-defined 'toQuery'. It would be possible in theory to encode
285−-- the necessary invariants at the type level using an indexed monad, but we
286−-- would lose the ability to use @do@-notation, which is the main benefit
287−-- of having 'Tabulation' as a monad in the first place.
288−--
289−-- In particular, @'toQuery' t@ is well-defined for any 'Tabulation' @t@
290−-- defined as @t = fromQuery _@. @'toQuery' t@ is also well-defined for any
291−-- 'Tabulation' @t@ defined as @t = t' >>= _@ or @t = t' *> _@ where
292−-- @'toQuery' t'@ is well-defined. There are other valid permutations too.
293−-- Generally, anything that uses 'fromQuery' at some point, unless wrapped in
294−-- a top-level 'present' or 'absent', will have a well-defined 'toQuery'.
295−toQuery :: Table Expr k => Tabulation k a -> Query (k, a)
296−toQuery (Tabulation f) = do
297− (mk, a) <- f mempty
298− k <- cat mk
299− pure (k, a)
300−
301−
302−-- | A @'Query' a@ can be treated as a @'Tabulation' k a@ where the given @a@
303−-- values exist at every possible key @k@.
304−liftQuery :: Query a -> Tabulation k a
305−liftQuery = Tabulation . const . fmap (empty,)
306−
307−
308−-- | Run a Kleisli arrow in the the 'Query' monad \"through\" a 'Tabulation'.
309−-- Useful for 'Rel8.filter'ing a 'Tabulation'.
310−--
311−-- @
312−-- 'Rel8.filter' ((>=. 30) . userAge) `'through'` usersById
313−-- @
314−through :: (a -> Query b) -> Tabulation k a -> Tabulation k b
315−through f (Tabulation as) = Tabulation $ \p -> do
316− (k, a) <- as p
317− b <- f a
318− pure (k, b)
319−infixr 1 `through`
320−
321−
322−-- | @'lookup' k t@ returns the value(s) at the key @k@ in the tabulation @t@.
323−lookup :: EqTable k => k -> Tabulation k a -> Query a
324−lookup k (Tabulation f) = do
325− (k', a) <- f p
326− ensure p k'
327− pure a
328− where
329− p = match (pure k)
330−
331−
332−-- | 'aggregate' aggregates the values within each key of a
333−-- 'Tabulation'. There is an implicit @GROUP BY@ on all the key columns.
334−aggregate :: forall k aggregates exprs.
335− ( EqTable k
336− , Aggregates aggregates exprs
337− )
338− => Tabulation k aggregates -> Tabulation k exprs
339−aggregate (Tabulation f) = Tabulation $
340− mapOpaleye (Opaleye.aggregate (keyed haggregator aggregator)) .
341− fmap (first (fmap (hgroupBy (eqTable @k) . toColumns))) .
342− f
343− where
344− haggregator = dimap fromColumns fromCols aggregator
345−
346−
347−-- | 'distinct' ensures a 'Tabulation' has at most one value for
348−-- each key, i.e., it drops duplicates. In general it keeps only the
349−-- \"first\" value it encounters for each key, but note that \"first\" is
350−-- undefined unless you first call 'order'.
351−distinct :: EqTable k => Tabulation k a -> Tabulation k a
352−distinct (Tabulation f) = Tabulation $
353− mapOpaleye (Opaleye.distinctOnExplicit (key unpackspec) fst) . f
354−
355−
356−-- | 'order' orders the /values/ of a 'Tabulation' within their
357−-- respective keys. This specifies a defined order for 'distinct'.
358−-- It also defines the order of the lists produced by 'many' and
359−-- 'some'.
360−order :: OrdTable k => Order a -> Tabulation k a -> Tabulation k a
361−order ordering (Tabulation f) =
362− Tabulation $ mapOpaleye (Opaleye.orderBy ordering') . f
363− where
364− Order ordering' = runClown (keyed (Clown ascTable) (Clown ordering))
365−
366−
367−-- $magic
368−--
369−-- Some of the following combinators produce \"magic\" 'Tabulation's. Let's
370−-- use 'count' as an example to demonstrate this concept. Consider
371−-- the following:
372−--
373−-- @
374−-- count $ fromQuery $ values
375−-- [ (lit 'a', lit True)
376−-- , (lit 'a', lit False)
377−-- , (lit 'b', lit True)
378−-- ]
379−-- @
380−--
381−-- You might expect this to be equivalent to the following 'Tabulation':
382−--
383−-- @
384−-- fromQuery $ values
385−-- [ (lit 'a', 2)
386−-- , (lit 'b', 1)
387−-- ]
388−-- @
389−--
390−-- However, it isn't quite. While the resulting 'Tabulation' does effectively
391−-- contain the above entries, it also behaves as though it contained the value
392−-- @0@ at every other possible key.
393−--
394−-- This means you can do:
395−--
396−-- @
397−-- do
398−-- user <- usersById
399−-- orderCount <- count ordersByUserId
400−-- @
401−--
402−-- To see how many orders a user has (getting @0@ if they have no orders).
403−
404−
405−-- | 'count' returns a count of how many entries are in the given
406−-- 'Tabulation' at each key.
407−--
408−-- The resulting 'Tabulation' is \"magic\" in that the value @0@ exists at
409−-- every possible key that wasn't in the given 'Tabulation'.
410−count :: EqTable k => Tabulation k a -> Tabulation k (Expr Int64)
411−count =
412− fmap (maybeTable 0 id) .
413− optional .
414− aggregate .
415− fmap (const countStar)
416−
417−
418−-- | 'optional' produces a \"magic\" 'Tabulation' whereby each
419−-- entry in the given 'Tabulation' is wrapped in 'Rel8.justTable', and every
420−-- other possible key contains a single 'Rel8.nothingTable'.
421−--
422−-- This is used to implement 'leftAlignWith'.
423−optional :: Tabulation k a -> Tabulation k (MaybeTable Expr a)
424−optional (Tabulation f) = Tabulation $ \p -> case p of
425− Predicate Nothing -> fmap pure <$> f p
426− _ -> fmap (\m -> (empty, snd <$> m)) $ Q.optional $ do
427− (k, a) <- f p
428− ensure p k
429− pure (k, a)
430−
431−
432−-- | 'many' aggregates each entry with a particular key into a
433−-- single entry with all of the values contained in a 'ListTable'.
434−--
435−-- 'order' can be used to give this 'ListTable' a defined order.
436−--
437−-- The resulting 'Tabulation' is \"magic\" in that the value
438−-- @'Rel8.listTable []'@ exists at every possible key that wasn't in the given
439−-- 'Tabulation'.
440−many :: (EqTable k, Table Expr a)
441− => Tabulation k a -> Tabulation k (ListTable Expr a)
442−many =
443− fmap (maybeTable mempty (\(ListTable a) -> ListTable a)) .
444− optional .
445− aggregate .
446− fmap (listAgg . toCols)
447−
448−
449−-- | 'some' aggregates each entry with a particular key into a
450−-- single entry with all of the values contained in a 'NonEmptyTable'.
451−--
452−-- 'order' can be used to give this 'NonEmptyTable' a defined order.
453−some :: (EqTable k, Table Expr a)
454− => Tabulation k a -> Tabulation k (NonEmptyTable Expr a)
455−some =
456− fmap (\(NonEmptyTable a) -> NonEmptyTable a) .
457− aggregate .
458− fmap (nonEmptyAgg . toCols)
459−
460−
461−-- | 'exists' produces a \"magic\" 'Tabulation' which contains the
462−-- value 'Rel8.true' at each key in the given 'Tabulation', and the value
463−-- 'Rel8.false' at every other possible key.
464−exists :: Tabulation k a -> Tabulation k (Expr Bool)
465−exists (Tabulation f) = Tabulation $ \p -> case p of
466− Predicate Nothing -> (true <$) <$> f p
467− _ -> fmap (empty,) $ Q.exists $ do
468− (k, _) <- f p
469− ensure p k
470−
471−
472−-- | 'present' produces a 'Tabulation' where a single @()@ row
473−-- exists for every key that was present in the given 'Tabulation'.
474−--
475−-- This is used to implement 'similarity'.
476−present :: Tabulation k a -> Tabulation k ()
477−present (Tabulation f) = Tabulation $ \p -> do
478− Q.present $ do
479− (k, _) <- f p
480− ensure p k
481− pure (empty, ())
482−
483−
484−-- | 'absent' produces a 'Tabulation' where a single @()@ row exists
485−-- at every possible key that absent from the given 'Tabulation'.
486−--
487−-- This is used to implement 'difference'.
488−absent :: Tabulation k a -> Tabulation k ()
489−absent (Tabulation f) = Tabulation $ \p -> do
490− Q.absent $ do
491− (k, _) <- f p
492− ensure p k
493− pure (empty, ())
494−
495−
496−-- | Performs a @NATURAL FULL OUTER JOIN@ based on the common key columns.
497−--
498−-- Analogous to 'Data.Semialign.align'.
499−align :: EqTable k
500− => Tabulation k a -> Tabulation k b -> Tabulation k (TheseTable Expr a b)
501−align = alignWith id
502−
503−
504−-- | Performs a @NATURAL FULL OUTER JOIN@ based on the common key columns.
505−--
506−-- Analogous to 'Data.Semialign.alignWith'.
507−alignWith :: EqTable k
508− => (TheseTable Expr a b -> c)
509− -> Tabulation k a -> Tabulation k b -> Tabulation k c
510−alignWith f (Tabulation as) (Tabulation bs) = Tabulation $ \p -> do
511− tkab <- liftF2 (alignBy condition) as bs p
512− k <- traverse (rebind "key") $ recover $ bimap fst fst tkab
513− let
514− tab = bimap snd snd tkab
515− pure (k, f tab)
516− where
517− condition (k, _) (k', _) = fromMaybe true (liftA2 (==:) k k')
518− recover (TheseTable mma@(MaybeTable _ ma) mmb@(MaybeTable _ mb)) =
519− case extract ma of
520− Nothing -> extract mb
521− Just a -> case extract mb of
522− Nothing -> extract ma
523− Just b -> case a <$ mma <|>: b <$ mmb of
524− MaybeTable _ c -> pure (extract c)
525−
526−
527−-- | Performs a @NATURAL LEFT OUTER JOIN@ based on the common key columns.
528−--
529−-- Analogous to 'Data.Semialign.rpadZip'.
530−--
531−-- Note that you can achieve the same effect with 'optional' and the
532−-- 'Applicative' instance for 'Tabulation', i.e., this is just
533−-- @\left right -> liftA2 (,) left (optional right). You can also
534−-- use @do@-notation.
535−leftAlign :: EqTable k
536− => Tabulation k a -> Tabulation k b -> Tabulation k (a, MaybeTable Expr b)
537−leftAlign = leftAlignWith (,)
538−
539−
540−-- | Performs a @NATURAL LEFT OUTER JOIN@ based on the common key columns.
541−--
542−-- Analogous to 'Data.Semialign.rpadZipWith'.
543−--
544−-- Note that you can achieve the same effect with 'optional' and the
545−-- 'Applicative' instance for 'Tabulation', i.e., this is just
546−-- @\f left right -> liftA2 f left (optional right). You can also
547−-- use @do@-notation.
548−leftAlignWith :: EqTable k
549− => (a -> MaybeTable Expr b -> c)
550− -> Tabulation k a -> Tabulation k b -> Tabulation k c
551−leftAlignWith f left right = liftA2 f left (optional right)
552−
553−
554−-- | Performs a @NATURAL RIGHT OUTER JOIN@ based on the common key columns.
555−--
556−-- Analogous to 'Data.Semialign.lpadZip'.
557−--
558−-- Note that you can achieve the same effect with 'optional' and the
559−-- 'Applicative' instance for 'Tabulation', i.e., this is just
560−-- @\left right -> liftA2 (flip (,)) right (optional left). You can
561−-- also use @do@-notation.
562−rightAlign :: EqTable k
563− => Tabulation k a -> Tabulation k b -> Tabulation k (MaybeTable Expr a, b)
564−rightAlign = rightAlignWith (,)
565−
566−
567−-- | Performs a @NATURAL RIGHT OUTER JOIN@ based on the common key columns.
568−--
569−-- Analogous to 'Data.Semialign.lpadZipWith'.
570−--
571−-- Note that you can achieve the same effect with 'optional' and the
572−-- 'Applicative' instance for 'Tabulation', i.e., this is just
573−-- @\f left right -> liftA2 (flip f) right (optional left). You can
574−-- also use @do@-notation.
575−rightAlignWith :: EqTable k
576− => (MaybeTable Expr a -> b -> c)
577− -> Tabulation k a -> Tabulation k b -> Tabulation k c
578−rightAlignWith f left right = liftA2 (flip f) right (optional left)
579−
580−
581−-- | Performs a @NATURAL INNER JOIN@ based on the common key columns.
582−--
583−-- Analagous to 'Data.Semialign.zip'.
584−--
585−-- Note that you can achieve the same effect with the 'Applicative' instance
586−-- of 'Tabulation', i.e., this is just @'liftA2 (,)'@. You can also use
587−-- @do@-notation.
588−zip :: EqTable k
589− => Tabulation k a -> Tabulation k b -> Tabulation k (a, b)
590−zip = zipWith (,)
591−
592−
593−-- | Performs a @NATURAL INNER JOIN@ based on the common key columns.
594−--
595−-- Analagous to 'Data.Semialign.zipWith'.
596−--
597−-- Note that you can achieve the same effect with the 'Applicative' instance
598−-- of 'Tabulation', i.e., this is just @'liftA2'@. You can also use
599−-- @do@-notation.
600−zipWith :: EqTable k
601− => (a -> b -> c) -> Tabulation k a -> Tabulation k b -> Tabulation k c
602−zipWith = liftA2
603−
604−
605−-- | Performs a [@NATURAL SEMI JOIN@](https://en.wikipedia.org/wiki/Relational_algebra#Semijoin_%28%E2%8B%89%29%28%E2%8B%8A%29)
606−-- based on the common key columns.
607−--
608−-- The result is a subset of the left tabulation where only entries which have
609−-- a corresponding entry in the right tabulation are kept.
610−--
611−-- Note that you can achieve a similar effect with 'present' and the
612−-- 'Applicative' instance of 'Tabulation', i.e., this is just
613−-- @\left right -> left <* present right@. You can also use
614−-- @do@-notation.
615−similarity :: EqTable k => Tabulation k a -> Tabulation k b -> Tabulation k a
616−similarity a b = a <* present b
617−
618−
619−-- | Performs a [@NATURAL ANTI JOIN@](https://en.wikipedia.org/wiki/Relational_algebra#Antijoin_%28%E2%96%B7%29)
620−-- based on the common key columns.
621−--
622−-- The result is a subset of the left tabulation where only entries which do
623−-- not have a corresponding entry in the right tabulation are kept.
624−--
625−-- Note that you can achieve a similar effect with 'absent' and the
626−-- 'Applicative' instance of 'Tabulation', i.e., this is just
627−-- @\left right -> left <* absent right@. You can also use
628−-- @do@-notation.
629−difference :: EqTable k => Tabulation k a -> Tabulation k b -> Tabulation k a
630−difference a b = a <* absent b
631−
632−
633−-- | 'Tabulation's can be produced with either 'fromQuery' or 'liftQuery', and
634−-- in some cases we might want to treat these differently. 'peek' uses
635−-- 'unsafePeekQuery' to determine which type of 'Tabulation' we have.
636−peek :: Tabulation k a -> Tabulation k (Either (Query a) (Query (k, a)))
637−peek (Tabulation f) = Tabulation $ \p ->
638− pure $ (empty,) $ case unsafePeekQuery (f p) of
639− (Nothing, _) -> Left $ fmap snd (f p)
640− (Just _, _) -> Right $ fmap (first fromJust) (f p)
src/Rel8/Type.hs+8−9
@@ -1,4 +1,3 @@
1−{-# language FlexibleContexts #-}
2{-# language FlexibleInstances #-}
1{-# language FlexibleInstances #-}
3{-# language MonoLocalBinds #-}
2{-# language MonoLocalBinds #-}
4{-# language MultiWayIf #-}
3{-# language MultiWayIf #-}
@@ -128,10 +127,10 @@ instance DBType Int64 where
128instance DBType Float where
127instance DBType Float where
129 typeInformation = TypeInformation
128 typeInformation = TypeInformation
130 { encode = \x -> Opaleye.ConstExpr
129 { encode = \x -> Opaleye.ConstExpr
131− if | x == (1 / 0) -> Opaleye.OtherLit "'Infinity'"
130+ if | x == (1 /0) -> Opaleye.OtherLit "'Infinity'"
132− | isNaN x -> Opaleye.OtherLit "'NaN'"
131+ | isNaN x -> Opaleye.OtherLit "'NaN'"
133− | x == (-1 / 0) -> Opaleye.OtherLit "'-Infinity'"
132+ | x == (-1/0) -> Opaleye.OtherLit "'-Infinity'"
134− | otherwise -> Opaleye.NumericLit $ realToFrac x
133+ | otherwise -> Opaleye.NumericLit $ realToFrac x
135 , decode = Hasql.float4
134 , decode = Hasql.float4
136 , typeName = "float4"
135 , typeName = "float4"
137 }
136 }
@@ -141,10 +140,10 @@ instance DBType Float where
141instance DBType Double where
140instance DBType Double where
142 typeInformation = TypeInformation
141 typeInformation = TypeInformation
143 { encode = \x -> Opaleye.ConstExpr
142 { encode = \x -> Opaleye.ConstExpr
144− if | x == (1 / 0) -> Opaleye.OtherLit "'Infinity'"
143+ if | x == (1 /0) -> Opaleye.OtherLit "'Infinity'"
145− | isNaN x -> Opaleye.OtherLit "'NaN'"
144+ | isNaN x -> Opaleye.OtherLit "'NaN'"
146− | x == (-1 / 0) -> Opaleye.OtherLit "'-Infinity'"
145+ | x == (-1/0) -> Opaleye.OtherLit "'-Infinity'"
147− | otherwise -> Opaleye.NumericLit $ realToFrac x
146+ | otherwise -> Opaleye.NumericLit $ realToFrac x
148 , decode = Hasql.float8
147 , decode = Hasql.float8
149 , typeName = "float8"
148 , typeName = "float8"
150 }
149 }
src/Rel8/Type/Composite.hs+19−20
@@ -20,7 +20,6 @@ where
20
20
21-- base
21-- base
22import Data.Functor.Const ( Const( Const ), getConst )
22import Data.Functor.Const ( Const( Const ), getConst )
23−import Data.Functor.Identity ( Identity( Identity ) )
24import Data.Kind ( Constraint, Type )
23import Data.Kind ( Constraint, Type )
25import Prelude
24import Prelude
26
25
@@ -31,19 +30,19 @@ import qualified Hasql.Decoders as Hasql
31import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
30import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
32
31
33-- rel8
32-- rel8
34−import Rel8.Expr ( Expr )
33+import Rel8.Expr ( Col( E ), Expr )
35import Rel8.Expr.Opaleye ( castExpr, fromPrimExpr, toPrimExpr )
34import Rel8.Expr.Opaleye ( castExpr, fromPrimExpr, toPrimExpr )
36−import Rel8.Schema.HTable ( HTable, hfield, hspecs, htabulate, htabulateA )
35+import Rel8.Schema.HTable ( hfield, hspecs, htabulate, htabulateA )
37−import Rel8.Schema.Name ( Name( Name ) )
36+import Rel8.Schema.Name ( Col( N ), Name( Name ) )
38import Rel8.Schema.Null ( Nullity( Null, NotNull ) )
37import Rel8.Schema.Null ( Nullity( Null, NotNull ) )
39−import Rel8.Schema.Result ( Result )
38+import Rel8.Schema.Result ( Col( R ), Result )
40−import Rel8.Schema.Spec ( Spec( Spec, nullity, info ) )
39+import Rel8.Schema.Spec ( SSpec( SSpec, nullity, info ) )
41−import Rel8.Table ( fromColumns, toColumns, fromResult, toResult )
40+import Rel8.Table ( Table, fromColumns, toColumns )
42import Rel8.Table.Eq ( EqTable )
41import Rel8.Table.Eq ( EqTable )
43−import Rel8.Table.HKD ( HKD, HKDable )
42+import Rel8.Table.HKD ( HKD, HKDable, fromHKD, toHKD )
44import Rel8.Table.Ord ( OrdTable )
43import Rel8.Table.Ord ( OrdTable )
45import Rel8.Table.Rel8able ()
44import Rel8.Table.Rel8able ()
46−import Rel8.Table.Serialize ( litHTable )
45+import Rel8.Table.Serialize ( lit )
47import Rel8.Type ( DBType, typeInformation )
46import Rel8.Type ( DBType, typeInformation )
48import Rel8.Type.Eq ( DBEq )
47import Rel8.Type.Eq ( DBEq )
49import Rel8.Type.Information ( TypeInformation(..) )
48import Rel8.Type.Information ( TypeInformation(..) )
@@ -68,8 +67,8 @@ newtype Composite a = Composite
68
67
69instance DBComposite a => DBType (Composite a) where
68instance DBComposite a => DBType (Composite a) where
70 typeInformation = TypeInformation
69 typeInformation = TypeInformation
71− { decode = Hasql.composite (Composite . fromResult @_ @(HKD a Expr) <$> decoder)
70+ { decode = Hasql.composite (Composite . fromHKD <$> decoder)
72− , encode = encoder . litHTable . toResult @_ @(HKD a Expr) . unComposite
71+ , encode = encoder . lit . toColumns . toHKD . unComposite
73 , typeName = compositeTypeName @a
72 , typeName = compositeTypeName @a
74 }
73 }
75
74
@@ -104,7 +103,7 @@ class (DBType a, HKDable a) => DBComposite a where
104-- single column expression, by combining them into a PostgreSQL composite
103-- single column expression, by combining them into a PostgreSQL composite
105-- type.
104-- type.
106compose :: DBComposite a => HKD a Expr -> Expr a
105compose :: DBComposite a => HKD a Expr -> Expr a
107−compose = castExpr . fromPrimExpr . encoder . toColumns
106+compose = castExpr . fromPrimExpr . encoder
108
107
109
108
110-- | Expand a composite type into a 'HKD'.
109-- | Expand a composite type into a 'HKD'.
@@ -113,23 +112,23 @@ compose = castExpr . fromPrimExpr . encoder . toColumns
113decompose :: forall a. DBComposite a => Expr a -> HKD a Expr
112decompose :: forall a. DBComposite a => Expr a -> HKD a Expr
114decompose (toPrimExpr -> a) = fromColumns $ htabulate \field ->
113decompose (toPrimExpr -> a) = fromColumns $ htabulate \field ->
115 case hfield names field of
114 case hfield names field of
116− Name name -> case hfield hspecs field of
115+ N (Name name) -> case hfield hspecs field of
117− Spec {} -> fromPrimExpr $ Opaleye.CompositeExpr a name
116+ SSpec {} -> E $ fromPrimExpr $ Opaleye.CompositeExpr a name
118 where
117 where
119 names = toColumns (compositeFields @a)
118 names = toColumns (compositeFields @a)
120
119
121
120
122−decoder :: HTable t => Hasql.Composite (t Result)
121+decoder :: Table Result a => Hasql.Composite a
123−decoder = unwrapApplicative $ htabulateA \field ->
122+decoder = fmap fromColumns $ unwrapApplicative $ htabulateA \field ->
124 case hfield hspecs field of
123 case hfield hspecs field of
125− Spec {nullity, info} -> WrapApplicative $ Identity <$>
124+ SSpec {nullity, info} -> WrapApplicative $ R <$>
126 case nullity of
125 case nullity of
127 Null -> Hasql.field $ Hasql.nullable $ decode info
126 Null -> Hasql.field $ Hasql.nullable $ decode info
128 NotNull -> Hasql.field $ Hasql.nonNullable $ decode info
127 NotNull -> Hasql.field $ Hasql.nonNullable $ decode info
129
128
130
129
131−encoder :: HTable t => t Expr -> Opaleye.PrimExpr
130+encoder :: Table Expr a => a -> Opaleye.PrimExpr
132−encoder a = Opaleye.FunExpr "ROW" exprs
131+encoder (toColumns -> a) = Opaleye.FunExpr "ROW" exprs
133 where
132 where
134 exprs = getConst $ htabulateA \field -> case hfield a field of
133 exprs = getConst $ htabulateA \field -> case hfield a field of
135− expr -> Const [toPrimExpr expr]
134+ E (toPrimExpr -> expr) -> Const [expr]
src/Rel8/Type/Enum.hs−1
@@ -106,7 +106,6 @@ class (DBType a, Enumable a) => DBEnum a where
106
106
107-- | Types that are sum types, where each constructor is unary (that is, has no
107-- | Types that are sum types, where each constructor is unary (that is, has no
108-- fields).
108-- fields).
109−type Enumable :: Type -> Constraint
110class (Generic a, GEnumable (Rep a)) => Enumable a
109class (Generic a, GEnumable (Rep a)) => Enumable a
111instance (Generic a, GEnumable (Rep a)) => Enumable a
110instance (Generic a, GEnumable (Rep a)) => Enumable a
112
111
src/Rel8/Type/JSONBEncoded.hs−4
@@ -1,5 +1,3 @@
1−{-# language StandaloneKindSignatures #-}
2−
3module Rel8.Type.JSONBEncoded ( JSONBEncoded(..) ) where
1module Rel8.Type.JSONBEncoded ( JSONBEncoded(..) ) where
4
2
5-- aeson
3-- aeson
@@ -8,7 +6,6 @@ import Data.Aeson.Types ( parseEither )
8
6
9-- base
7-- base
10import Data.Bifunctor ( first )
8import Data.Bifunctor ( first )
11−import Data.Kind ( Type )
12import Prelude
9import Prelude
13
10
14-- hasql
11-- hasql
@@ -23,7 +20,6 @@ import Data.Text ( pack )
23
20
24
21
25-- | Like 'Rel8.JSONEncoded', but works for @jsonb@ columns.
22-- | Like 'Rel8.JSONEncoded', but works for @jsonb@ columns.
26−type JSONBEncoded :: Type -> Type
27newtype JSONBEncoded a = JSONBEncoded { fromJSONBEncoded :: a }
23newtype JSONBEncoded a = JSONBEncoded { fromJSONBEncoded :: a }
28
24
29
25
src/Rel8/Type/JSONEncoded.hs−4
@@ -1,5 +1,3 @@
1−{-# language StandaloneKindSignatures #-}
2−
3module Rel8.Type.JSONEncoded ( JSONEncoded(..) ) where
1module Rel8.Type.JSONEncoded ( JSONEncoded(..) ) where
4
2
5-- aeson
3-- aeson
@@ -7,7 +5,6 @@ import Data.Aeson ( FromJSON, ToJSON, parseJSON, toJSON )
7import Data.Aeson.Types ( parseEither )
5import Data.Aeson.Types ( parseEither )
8
6
9-- base
7-- base
10−import Data.Kind ( Type )
11import Prelude
8import Prelude
12
9
13-- rel8
10-- rel8
@@ -18,7 +15,6 @@ import Rel8.Type.Information ( parseTypeInformation )
18-- | A deriving-via helper type for column types that store a Haskell value
15-- | A deriving-via helper type for column types that store a Haskell value
19-- using a JSON encoding described by @aeson@'s 'ToJSON' and 'FromJSON' type
16-- using a JSON encoding described by @aeson@'s 'ToJSON' and 'FromJSON' type
20-- classes.
17-- classes.
21−type JSONEncoded :: Type -> Type
22newtype JSONEncoded a = JSONEncoded { fromJSONEncoded :: a }
18newtype JSONEncoded a = JSONEncoded { fromJSONEncoded :: a }
23
19
24
20
src/Rel8/Type/Num.hs+1−4
@@ -18,7 +18,6 @@ import Prelude
18
18
19-- rel8
19-- rel8
20import Rel8.Type ( DBType )
20import Rel8.Type ( DBType )
21−import Rel8.Type.Ord ( DBOrd )
22
21
23-- scientific
22-- scientific
24import Data.Scientific ( Scientific )
23import Data.Scientific ( Scientific )
@@ -40,14 +39,13 @@ instance DBNum Scientific
40-- expressions. This is a Rel8 concept, and allows us to provide
39-- expressions. This is a Rel8 concept, and allows us to provide
41-- 'fromIntegral'.
40-- 'fromIntegral'.
42type DBIntegral :: Type -> Constraint
41type DBIntegral :: Type -> Constraint
43−class (DBNum a, DBOrd a) => DBIntegral a
42+class DBNum a => DBIntegral a
44instance DBIntegral Int16
43instance DBIntegral Int16
45instance DBIntegral Int32
44instance DBIntegral Int32
46instance DBIntegral Int64
45instance DBIntegral Int64
47
46
48
47
49-- | The class of database types that support the @/@ operator.
48-- | The class of database types that support the @/@ operator.
50−type DBFractional :: Type -> Constraint
51class DBNum a => DBFractional a
49class DBNum a => DBFractional a
52instance DBFractional Float
50instance DBFractional Float
53instance DBFractional Double
51instance DBFractional Double
@@ -55,7 +53,6 @@ instance DBFractional Scientific
55
53
56
54
57-- | The class of database types that support the @/@ operator.
55-- | The class of database types that support the @/@ operator.
58−type DBFloating :: Type -> Constraint
59class DBFractional a => DBFloating a
56class DBFractional a => DBFloating a
60instance DBFloating Float
57instance DBFloating Float
61instance DBFloating Double
58instance DBFloating Double
src/Rel8/Type/Ord.hs+2
@@ -75,6 +75,7 @@ instance Sql DBOrd a => DBOrd (NonEmpty a)
75-- | The class of database types that support the @max@ aggregation function.
75-- | The class of database types that support the @max@ aggregation function.
76type DBMax :: Type -> Constraint
76type DBMax :: Type -> Constraint
77class DBOrd a => DBMax a
77class DBOrd a => DBMax a
78+instance DBMax Bool
78instance DBMax Char
79instance DBMax Char
79instance DBMax Int16
80instance DBMax Int16
80instance DBMax Int32
81instance DBMax Int32
@@ -100,6 +101,7 @@ instance Sql DBMax a => DBMax (NonEmpty a)
100-- | The class of database types that support the @min@ aggregation function.
101-- | The class of database types that support the @min@ aggregation function.
101type DBMin :: Type -> Constraint
102type DBMin :: Type -> Constraint
102class DBOrd a => DBMin a
103class DBOrd a => DBMin a
104+instance DBMin Bool
103instance DBMin Char
105instance DBMin Char
104instance DBMin Int16
106instance DBMin Int16
105instance DBMin Int32
107instance DBMin Int32
src/Rel8/Type/ReadShow.hs−3
@@ -1,12 +1,10 @@
1{-# language ScopedTypeVariables #-}
1{-# language ScopedTypeVariables #-}
2−{-# language StandaloneKindSignatures #-}
3{-# language TypeApplications #-}
2{-# language TypeApplications #-}
4{-# language ViewPatterns #-}
3{-# language ViewPatterns #-}
5
4
6module Rel8.Type.ReadShow ( ReadShow(..) ) where
5module Rel8.Type.ReadShow ( ReadShow(..) ) where
7
6
8-- base
7-- base
9−import Data.Kind ( Type )
10import Data.Proxy ( Proxy( Proxy ) )
8import Data.Proxy ( Proxy( Proxy ) )
11import Data.Typeable ( Typeable, typeRep )
9import Data.Typeable ( Typeable, typeRep )
12import Prelude
10import Prelude
@@ -22,7 +20,6 @@ import qualified Data.Text as Text
22
20
23-- | A deriving-via helper type for column types that store a Haskell value
21-- | A deriving-via helper type for column types that store a Haskell value
24-- using a Haskell's 'Read' and 'Show' type classes.
22-- using a Haskell's 'Read' and 'Show' type classes.
25−type ReadShow :: Type -> Type
26newtype ReadShow a = ReadShow { fromReadShow :: a }
23newtype ReadShow a = ReadShow { fromReadShow :: a }
27
24
28
25
src/Rel8/Type/Tag.hs+1−2
@@ -21,7 +21,7 @@ import Prelude
21import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
21import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
22
22
23-- rel8
23-- rel8
24−import Rel8.Expr ( Expr )
24+import {-# SOURCE #-} Rel8.Expr ( Expr )
25import Rel8.Expr.Eq ( (==.) )
25import Rel8.Expr.Eq ( (==.) )
26import Rel8.Expr.Opaleye ( zipPrimExprsWith )
26import Rel8.Expr.Opaleye ( zipPrimExprsWith )
27import Rel8.Expr.Serialize ( litExpr )
27import Rel8.Expr.Serialize ( litExpr )
@@ -90,7 +90,6 @@ instance DBMonoid MaybeTag where
90 memptyExpr = litExpr mempty
90 memptyExpr = litExpr mempty
91
91
92
92
93−type Tag :: Type
94newtype Tag = Tag Text
93newtype Tag = Tag Text
95 deriving newtype
94 deriving newtype
96 ( Eq, Ord, Read, Show
95 ( Eq, Ord, Read, Show
src/Rel8/Window.hsdeleted−97
@@ -1,97 +0,0 @@
1−{-# language DerivingVia #-}
2−{-# language FlexibleContexts #-}
3−{-# language GeneralizedNewtypeDeriving #-}
4−{-# language ScopedTypeVariables #-}
5−{-# language StandaloneKindSignatures #-}
6−{-# language TypeApplications #-}
7−
8−module Rel8.Window
9− ( Window(..)
10− , Partition
11− , over
12− , partitionBy
13− , orderPartitionBy
14− )
15−where
16−
17−-- base
18−import Data.Functor.Const ( Const( Const ), getConst )
19−import Data.Functor.Contravariant ( Contravariant, contramap )
20−import Data.Kind ( Type )
21−import Prelude
22−
23−-- opaleye
24−import qualified Opaleye.Internal.Window as Opaleye
25−import qualified Opaleye.Internal.PackMap as Opaleye
26−
27−-- profunctors
28−import Data.Profunctor ( Profunctor )
29−
30−-- product-profunctors
31−import Data.Profunctor.Product ( ProductProfunctor, (****), purePP )
32−
33−-- rel8
34−import Rel8.Expr.Opaleye ( toColumn, toPrimExpr )
35−import Rel8.Order( Order( Order ) )
36−import Rel8.Schema.HTable ( hfield, htabulateA )
37−import Rel8.Table ( Columns, toColumns )
38−import Rel8.Table.Eq ( EqTable )
39−
40−-- semigroupoids
41−import Data.Functor.Apply ( Apply, WrappedApplicative(..) )
42−
43−
44−-- | 'Window' is an applicative functor that represents expressions that
45−-- contain
46−-- [window functions](https://www.postgresql.org/docs/current/tutorial-window.html).
47−-- 'Rel8.Query.Window.window' can be used to
48−-- evaluate these expressions over a particular query.
49−type Window :: Type -> Type -> Type
50−newtype Window a b = Window (Opaleye.Windows a b)
51− deriving newtype (Profunctor)
52− deriving newtype (Functor, Applicative)
53− deriving (Apply) via (WrappedApplicative (Window a))
54−
55−
56−instance ProductProfunctor Window where
57− purePP = pure
58− (****) = (<*>)
59−
60−
61−-- | In PostgreSQL, window functions must specify the \"window\" or
62−-- \"partition\" over which they operate. The syntax for this looks like:
63−-- @SUM(salary) OVER (PARTITION BY department)@. The Rel8 type 'Partition'
64−-- represents everything that comes after @OVER@.
65−--
66−-- 'Partition' is a 'Monoid', so 'Window's created with 'partitionBy' and
67−-- 'orderWindowBy' can be combined using '<>'.
68−type Partition :: Type -> Type
69−newtype Partition a = Partition (Opaleye.Window a)
70− deriving newtype (Contravariant, Semigroup, Monoid)
71−
72−
73−-- | 'over' adds a 'Partition' to a 'Window' expression.
74−--
75−-- @@@
76−-- 'Rel8.Table.Window.cumulative' ('Rel8.Expr.Aggregate.sum' . salary) `over` 'partitionBy' department <> 'orderPartitionBy' (salary >$< 'Rel8.desc')
77−-- @@@
78−over :: Window a b -> Partition a -> Window a b
79−over (Window (Opaleye.Windows (Opaleye.PackMap w))) (Partition p) =
80− Window $ Opaleye.Windows $ Opaleye.PackMap $ \f ->
81− w (\(o, p') -> f (o, p' <> p))
82−infixl 1 `over`
83−
84−
85−-- | Restricts a window function to operate only the group of rows that share
86−-- the same value(s) for the given expression(s).
87−partitionBy :: forall b a. EqTable b => (a -> b) -> Partition a
88−partitionBy f =
89− Partition $ contramap (toColumns . f) $ getConst $
90− htabulateA @(Columns b) $ \field ->
91− Const $ Opaleye.partitionBy (toColumn . toPrimExpr . (`hfield` field))
92−
93−
94−-- | Controls the order in which rows are processed by window functions. This
95−-- does not need to match the ordering of the overall query.
96−orderPartitionBy :: Order a -> Partition a
97−orderPartitionBy (Order ordering) = Partition $ Opaleye.orderPartitionBy ordering
tests/Main.hs+178−288
@@ -1,11 +1,12 @@
1−{-# language BangPatterns #-}
2{-# language BlockArguments #-}
1{-# language BlockArguments #-}
2+{-# language DataKinds #-}
3{-# language DeriveAnyClass #-}
3{-# language DeriveAnyClass #-}
4{-# language DeriveGeneric #-}
4{-# language DeriveGeneric #-}
5{-# language DerivingStrategies #-}
5{-# language DerivingStrategies #-}
6+{-# language DisambiguateRecordFields #-}
6{-# language FlexibleContexts #-}
7{-# language FlexibleContexts #-}
7{-# language FlexibleInstances #-}
8{-# language FlexibleInstances #-}
8−{-# language MonoLocalBinds #-}
9+{-# language GADTs #-}
9{-# language NamedFieldPuns #-}
10{-# language NamedFieldPuns #-}
10{-# language OverloadedStrings #-}
11{-# language OverloadedStrings #-}
11{-# language RecordWildCards #-}
12{-# language RecordWildCards #-}
@@ -13,15 +14,17 @@
13{-# language StandaloneDeriving #-}
14{-# language StandaloneDeriving #-}
14{-# language TypeApplications #-}
15{-# language TypeApplications #-}
15
16
17+{-# options_ghc -fno-warn-redundant-constraints #-}
18+
16module Main
19module Main
17 ( main
20 ( main
18 )
21 )
19where
22where
20
23
21-- base
24-- base
22−import Control.Applicative ( empty, liftA2, liftA3 )
25+import Control.Applicative ( liftA2, liftA3 )
23−import Control.Exception ( bracket, throwIO )
26+import Control.Monad (void)
24−import Control.Monad ( (>=>), void )
27+import Control.Monad.IO.Class ( MonadIO, liftIO )
25import Data.Bifunctor ( bimap )
28import Data.Bifunctor ( bimap )
26import Data.Foldable ( for_ )
29import Data.Foldable ( for_ )
27import Data.Int ( Int32, Int64 )
30import Data.Int ( Int32, Int64 )
@@ -35,27 +38,25 @@ import GHC.Generics ( Generic )
35import qualified Data.ByteString.Lazy
38import qualified Data.ByteString.Lazy
36
39
37-- case-insensitive
40-- case-insensitive
38−import Data.CaseInsensitive ( mk )
41+import Data.CaseInsensitive (mk)
39
42
40-- containers
43-- containers
41−import Data.Containers.ListUtils ( nubOrdOn )
42import qualified Data.Map.Strict as Map
44import qualified Data.Map.Strict as Map
43
45
44-- hasql
46-- hasql
45−import Hasql.Connection ( Connection, acquire, release )
47+import Hasql.Connection ( Connection, acquire, release )
46import Hasql.Session ( sql, run )
48import Hasql.Session ( sql, run )
47
49
48−-- hasql-transaction
49−import Hasql.Transaction ( Transaction, condemn, statement )
50−import qualified Hasql.Transaction.Sessions as Hasql
51−
52-- hedgehog
50-- hedgehog
53import Hedgehog ( property, (===), forAll, cover, diff, evalM, PropertyT, TestT, test, Gen )
51import Hedgehog ( property, (===), forAll, cover, diff, evalM, PropertyT, TestT, test, Gen )
54import qualified Hedgehog.Gen as Gen
52import qualified Hedgehog.Gen as Gen
55import qualified Hedgehog.Range as Range
53import qualified Hedgehog.Range as Range
56
54
57−-- mmorph
55+-- lifted-base
56+import Control.Exception.Lifted ( bracket, throwIO, bracket_ )
57+
58+-- monad-control
58−import Control.Monad.Morph ( hoist )
59+import Control.Monad.Trans.Control ( MonadBaseControl )
59
60
60-- rel8
61-- rel8
61import Rel8 ( Result )
62import Rel8 ( Result )
@@ -71,16 +72,12 @@ import Test.Tasty
71import Test.Tasty.Hedgehog ( testProperty )
72import Test.Tasty.Hedgehog ( testProperty )
72
73
73-- text
74-- text
74−import Data.Text ( Text, pack, unpack )
75+import Data.Text (Text, pack)
75import qualified Data.Text.Lazy
76import qualified Data.Text.Lazy
76−import Data.Text.Encoding ( decodeUtf8 )
77
77
78-- time
78-- time
79import Data.Time
79import Data.Time
80
80
81−-- transformers
82−import Control.Monad.Trans.Class ( lift )
83−
84-- tmp-postgres
81-- tmp-postgres
85import qualified Database.Postgres.Temp as TmpPostgres
82import qualified Database.Postgres.Temp as TmpPostgres
86
83
@@ -116,13 +113,11 @@ tests =
116 , testCatMaybeTable getTestDatabase
113 , testCatMaybeTable getTestDatabase
117 , testCatMaybe getTestDatabase
114 , testCatMaybe getTestDatabase
118 , testMaybeTable getTestDatabase
115 , testMaybeTable getTestDatabase
119− , testAggregateMaybeTable getTestDatabase
120 , testNestedTables getTestDatabase
116 , testNestedTables getTestDatabase
121 , testMaybeTableApplicative getTestDatabase
117 , testMaybeTableApplicative getTestDatabase
122 , testLogicalFixities getTestDatabase
118 , testLogicalFixities getTestDatabase
123 , testUpdate getTestDatabase
119 , testUpdate getTestDatabase
124 , testDelete getTestDatabase
120 , testDelete getTestDatabase
125− , testUpsert getTestDatabase
126 , testSelectNestedPairs getTestDatabase
121 , testSelectNestedPairs getTestDatabase
127 , testSelectArray getTestDatabase
122 , testSelectArray getTestDatabase
128 , testNestedMaybeTable getTestDatabase
123 , testNestedMaybeTable getTestDatabase
@@ -138,7 +133,6 @@ tests =
138 flip run conn do
133 flip run conn do
139 sql "CREATE EXTENSION citext"
134 sql "CREATE EXTENSION citext"
140 sql "CREATE TABLE test_table ( column1 text not null, column2 bool not null )"
135 sql "CREATE TABLE test_table ( column1 text not null, column2 bool not null )"
141− sql "CREATE TABLE unique_table ( \"key\" text not null unique, \"value\" text not null )"
142 sql "CREATE SEQUENCE test_seq"
136 sql "CREATE SEQUENCE test_seq"
143
137
144 return db
138 return db
@@ -146,21 +140,19 @@ tests =
146 stopTestDatabase = TmpPostgres.stop
140 stopTestDatabase = TmpPostgres.stop
147
141
148
142
149−connect :: TmpPostgres.DB -> IO Connection
150−connect = acquire . TmpPostgres.toConnectionString >=> either (maybe empty (fail . unpack . decodeUtf8)) pure
151−
152−
153databasePropertyTest
143databasePropertyTest
154 :: TestName
144 :: TestName
155− -> ((TestT Transaction () -> PropertyT IO ()) -> PropertyT IO ())
145+ -> (((Connection -> TestT IO ()) -> PropertyT IO ()) -> PropertyT IO ())
156 -> IO TmpPostgres.DB -> TestTree
146 -> IO TmpPostgres.DB -> TestTree
157databasePropertyTest testName f getTestDatabase =
147databasePropertyTest testName f getTestDatabase =
158− withResource (connect =<< getTestDatabase) release $ \c ->
148+ withResource connect release $ \c ->
159 testProperty testName $ property do
149 testProperty testName $ property do
160− connection <- lift c
150+ connection <- liftIO c
161− f $ test . hoist \m -> do
151+ f \g -> test $ rollingBack connection $ g connection
162− e <- run (Hasql.transaction Hasql.Serializable Hasql.Write (m <* condemn)) connection
152+
163− either throwIO pure e
153+ where
154+
155+ connect = either (error . show) return =<< acquire . TmpPostgres.toConnectionString =<< getTestDatabase
164
156
165
157
166data TestTable f = TestTable
158data TestTable f = TestTable
@@ -192,17 +184,18 @@ testSelectTestTable :: IO TmpPostgres.DB -> TestTree
192testSelectTestTable = databasePropertyTest "Can SELECT TestTable" \transaction -> do
184testSelectTestTable = databasePropertyTest "Can SELECT TestTable" \transaction -> do
193 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
185 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
194
186
195− transaction do
187+ transaction \connection -> do
196− selected <- lift do
188+ void do
189+ liftIO $ Rel8.insert connection
197− statement () $ Rel8.insert Rel8.Insert
190+ Rel8.Insert
198− { into = testTableSchema
191+ { into = testTableSchema
199− , rows = Rel8.values $ map Rel8.lit rows
192+ , rows = map Rel8.lit rows
200− , onConflict = Rel8.DoNothing
193+ , onConflict = Rel8.DoNothing
201− , returning = pure ()
194+ , returning = Rel8.NumberOfRowsAffected
202− }
195+ }
203
196
204− statement () $ Rel8.select do
197+ selected <- liftIO $ Rel8.select connection do
205− Rel8.each testTableSchema
198+ Rel8.each testTableSchema
206
199
207 sort selected === sort rows
200 sort selected === sort rows
208
201
@@ -219,12 +212,11 @@ testWhere_ = databasePropertyTest "WHERE (Rel8.where_)" \transaction -> do
219
212
220 let expected = filter (\t -> testTableColumn2 t == magicBool) rows
213 let expected = filter (\t -> testTableColumn2 t == magicBool) rows
221
214
222− transaction do
215+ transaction \connection -> do
223− selected <- lift do
224− statement () $ Rel8.select do
216+ selected <- liftIO $ Rel8.select connection do
225− t <- Rel8.values $ Rel8.lit <$> rows
217+ t <- Rel8.values $ Rel8.lit <$> rows
226− Rel8.where_ $ testTableColumn2 t Rel8.==. Rel8.lit magicBool
218+ Rel8.where_ $ testTableColumn2 t Rel8.==. Rel8.lit magicBool
227− return t
219+ return t
228
220
229 sort selected === sort expected
221 sort selected === sort expected
230
222
@@ -237,12 +229,11 @@ testFilter :: IO TmpPostgres.DB -> TestTree
237testFilter = databasePropertyTest "filter" \transaction -> do
229testFilter = databasePropertyTest "filter" \transaction -> do
238 rows <- forAll $ Gen.list (Range.linear 1 10) genTestTable
230 rows <- forAll $ Gen.list (Range.linear 1 10) genTestTable
239
231
240− transaction do
232+ transaction \connection -> do
241 let expected = filter testTableColumn2 rows
233 let expected = filter testTableColumn2 rows
242
234
243− selected <- lift do
235+ selected <- liftIO $ Rel8.select connection
244− statement () $ Rel8.select do
245− Rel8.filter testTableColumn2 =<< Rel8.values (Rel8.lit <$> rows)
236+ $ Rel8.filter testTableColumn2 =<< Rel8.values (Rel8.lit <$> rows)
246
237
247 sort selected === sort expected
238 sort selected === sort expected
248
239
@@ -257,10 +248,9 @@ testLimit = databasePropertyTest "LIMIT (Rel8.limit)" \transaction -> do
257
248
258 n <- forAll $ Gen.integral (Range.linear 0 10)
249 n <- forAll $ Gen.integral (Range.linear 0 10)
259
250
260− transaction do
251+ transaction \connection -> do
261− selected <- lift do
252+ selected <- liftIO $ Rel8.select connection do
262− statement () $ Rel8.select do
263− Rel8.limit n $ Rel8.values (Rel8.lit <$> rows)
253+ Rel8.limit n $ Rel8.values (Rel8.lit <$> rows)
264
254
265 diff (length selected) (<=) (fromIntegral n)
255 diff (length selected) (<=) (fromIntegral n)
266
256
@@ -278,10 +268,9 @@ testUnion = databasePropertyTest "UNION (Rel8.union)" \transaction -> evalM do
278 left <- forAll $ Gen.list (Range.linear 0 10) genTestTable
268 left <- forAll $ Gen.list (Range.linear 0 10) genTestTable
279 right <- forAll $ Gen.list (Range.linear 0 10) genTestTable
269 right <- forAll $ Gen.list (Range.linear 0 10) genTestTable
280
270
281− transaction do
271+ transaction \connection -> do
282− selected <- lift do
272+ selected <- liftIO $ Rel8.select connection do
283− statement () $ Rel8.select do
284− Rel8.values (Rel8.lit <$> nub left) `Rel8.union` Rel8.values (Rel8.lit <$> nub right)
273+ Rel8.values (Rel8.lit <$> nub left) `Rel8.union` Rel8.values (Rel8.lit <$> nub right)
285
274
286 sort selected === sort (nub (left ++ right))
275 sort selected === sort (nub (left ++ right))
287
276
@@ -290,11 +279,9 @@ testDistinct :: IO TmpPostgres.DB -> TestTree
290testDistinct = databasePropertyTest "DISTINCT (Rel8.distinct)" \transaction -> do
279testDistinct = databasePropertyTest "DISTINCT (Rel8.distinct)" \transaction -> do
291 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
280 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
292
281
293− transaction do
282+ transaction \connection -> do
294− selected <- lift do
295− statement () $ Rel8.select do
296− Rel8.distinct do
283+ selected <- liftIO $ Rel8.select connection $ Rel8.distinct do
297− Rel8.values (Rel8.lit <$> rows)
284+ Rel8.values (Rel8.lit <$> rows)
298
285
299 sort selected === nub (sort rows)
286 sort selected === nub (sort rows)
300
287
@@ -307,10 +294,8 @@ testExists :: IO TmpPostgres.DB -> TestTree
307testExists = databasePropertyTest "EXISTS (Rel8.exists)" \transaction -> do
294testExists = databasePropertyTest "EXISTS (Rel8.exists)" \transaction -> do
308 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
295 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
309
296
310− transaction do
297+ transaction \connection -> do
311− exists <- lift do
312− statement () $ Rel8.select do
313− Rel8.exists $ Rel8.values $ Rel8.lit <$> rows
298+ exists <- liftIO $ Rel8.select connection $ Rel8.exists $ Rel8.values $ Rel8.lit <$> rows
314
299
315 case rows of
300 case rows of
316 [] -> exists === [False]
301 [] -> exists === [False]
@@ -321,10 +306,9 @@ testOptional :: IO TmpPostgres.DB -> TestTree
321testOptional = databasePropertyTest "Rel8.optional" \transaction -> do
306testOptional = databasePropertyTest "Rel8.optional" \transaction -> do
322 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
307 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
323
308
324− transaction do
309+ transaction \connection -> do
325− selected <- lift do
310+ selected <- liftIO $ Rel8.select connection do
326− statement () $ Rel8.select do
327− Rel8.optional $ Rel8.values (Rel8.lit <$> rows)
311+ Rel8.optional $ Rel8.values (Rel8.lit <$> rows)
328
312
329 case rows of
313 case rows of
330 [] -> selected === [Nothing]
314 [] -> selected === [Nothing]
@@ -335,10 +319,9 @@ testAnd :: IO TmpPostgres.DB -> TestTree
335testAnd = databasePropertyTest "AND (&&.)" \transaction -> do
319testAnd = databasePropertyTest "AND (&&.)" \transaction -> do
336 (x, y) <- forAll $ liftA2 (,) Gen.bool Gen.bool
320 (x, y) <- forAll $ liftA2 (,) Gen.bool Gen.bool
337
321
338− transaction do
322+ transaction \connection -> do
339− [result] <- lift do
323+ [result] <- liftIO $ Rel8.select connection $ pure $
340− statement () $ Rel8.select do
341− pure $ Rel8.lit x Rel8.&&. Rel8.lit y
324+ Rel8.lit x Rel8.&&. Rel8.lit y
342
325
343 result === (x && y)
326 result === (x && y)
344
327
@@ -347,10 +330,9 @@ testOr :: IO TmpPostgres.DB -> TestTree
347testOr = databasePropertyTest "OR (||.)" \transaction -> do
330testOr = databasePropertyTest "OR (||.)" \transaction -> do
348 (x, y) <- forAll $ liftA2 (,) Gen.bool Gen.bool
331 (x, y) <- forAll $ liftA2 (,) Gen.bool Gen.bool
349
332
350− transaction do
333+ transaction \connection -> do
351− [result] <- lift do
352− statement () $ Rel8.select $ pure $
334+ [result] <- liftIO $ Rel8.select connection $ pure $
353− Rel8.lit x Rel8.||. Rel8.lit y
335+ Rel8.lit x Rel8.||. Rel8.lit y
354
336
355 result === (x || y)
337 result === (x || y)
356
338
@@ -359,10 +341,9 @@ testLogicalFixities :: IO TmpPostgres.DB -> TestTree
359testLogicalFixities = databasePropertyTest "Logical operator fixities" \transaction -> do
341testLogicalFixities = databasePropertyTest "Logical operator fixities" \transaction -> do
360 (u, v, w, x) <- forAll $ (,,,) <$> Gen.bool <*> Gen.bool <*> Gen.bool <*> Gen.bool
342 (u, v, w, x) <- forAll $ (,,,) <$> Gen.bool <*> Gen.bool <*> Gen.bool <*> Gen.bool
361
343
362− transaction do
344+ transaction \connection -> do
363− [result] <- lift do
345+ [result] <- liftIO $ Rel8.select connection $ pure $
364− statement () $ Rel8.select do
365− pure $ Rel8.lit u Rel8.||. Rel8.lit v Rel8.&&. Rel8.lit w Rel8.==. Rel8.lit x
346+ Rel8.lit u Rel8.||. Rel8.lit v Rel8.&&. Rel8.lit w Rel8.==. Rel8.lit x
366
347
367 result === (u || v && w == x)
348 result === (u || v && w == x)
368
349
@@ -371,10 +352,9 @@ testNot :: IO TmpPostgres.DB -> TestTree
371testNot = databasePropertyTest "NOT (not_)" \transaction -> do
352testNot = databasePropertyTest "NOT (not_)" \transaction -> do
372 x <- forAll Gen.bool
353 x <- forAll Gen.bool
373
354
374− transaction do
355+ transaction \connection -> do
375− [result] <- lift do
356+ [result] <- liftIO $ Rel8.select connection $ pure $
376− statement () $ Rel8.select do
377− pure $ Rel8.not_ $ Rel8.lit x
357+ Rel8.not_ $ Rel8.lit x
378
358
379 result === not x
359 result === not x
380
360
@@ -383,10 +363,9 @@ testBool :: IO TmpPostgres.DB -> TestTree
383testBool = databasePropertyTest "ifThenElse_" \transaction -> do
363testBool = databasePropertyTest "ifThenElse_" \transaction -> do
384 (x, y, z) <- forAll $ liftA3 (,,) Gen.bool Gen.bool Gen.bool
364 (x, y, z) <- forAll $ liftA3 (,,) Gen.bool Gen.bool Gen.bool
385
365
386− transaction do
366+ transaction \connection -> do
387− [result] <- lift do
367+ [result] <- liftIO $ Rel8.select connection $ pure $
388− statement () $ Rel8.select do
389− pure $ Rel8.bool (Rel8.lit z) (Rel8.lit y) (Rel8.lit x)
368+ Rel8.bool (Rel8.lit z) (Rel8.lit y) (Rel8.lit x)
390
369
391 result === if x then y else z
370 result === if x then y else z
392
371
@@ -398,10 +377,9 @@ testAp = databasePropertyTest "Cartesian product (<*>)" \transaction -> do
398 (Gen.list (Range.linear 1 10) genTestTable)
377 (Gen.list (Range.linear 1 10) genTestTable)
399 (Gen.list (Range.linear 1 10) genTestTable)
378 (Gen.list (Range.linear 1 10) genTestTable)
400
379
401− transaction do
380+ transaction \connection -> do
402− result <- lift do
381+ result <- liftIO $ Rel8.select connection $ do
403− statement () $ Rel8.select do
404− liftA2 (,) (Rel8.values (Rel8.lit <$> rows1)) (Rel8.values (Rel8.lit <$> rows2))
382+ liftA2 (,) (Rel8.values (Rel8.lit <$> rows1)) (Rel8.values (Rel8.lit <$> rows2))
405
383
406 sort result === sort (liftA2 (,) rows1 rows2)
384 sort result === sort (liftA2 (,) rows1 rows2)
407
385
@@ -430,22 +408,21 @@ testDBType getTestDatabase = testGroup "DBType instances"
430 where
408 where
431 dbTypeTest :: (Eq a, Show a, Rel8.DBType a) => TestName -> Gen a -> TestTree
409 dbTypeTest :: (Eq a, Show a, Rel8.DBType a) => TestName -> Gen a -> TestTree
432 dbTypeTest name generator = testGroup name
410 dbTypeTest name generator = testGroup name
433− [ databasePropertyTest name (t generator) getTestDatabase
411+ [ databasePropertyTest name (t (==) generator) getTestDatabase
434− , databasePropertyTest ("Maybe " <> name) (t (Gen.maybe generator)) getTestDatabase
412+ , databasePropertyTest ("Maybe " <> name) (t (==) (Gen.maybe generator)) getTestDatabase
435 ]
413 ]
436
414
437− t :: forall a b. (Eq a, Show a, Rel8.Sql Rel8.DBType a)
415+ t :: forall a b. (Show a, Rel8.Sql Rel8.DBType a)
416+ => (a -> a -> Bool)
438− => Gen a
417+ -> Gen a
439− -> (TestT Transaction () -> PropertyT IO b)
418+ -> ((Connection -> TestT IO ()) -> PropertyT IO b)
440 -> PropertyT IO b
419 -> PropertyT IO b
441− t generator transaction = do
420+ t eq generator transaction = do
442 x <- forAll generator
421 x <- forAll generator
443
422
444− transaction do
423+ transaction \connection -> do
445− [res] <- lift do
446− statement () $ Rel8.select do
447− pure (Rel8.litExpr x)
424+ [res] <- liftIO $ Rel8.select connection $ pure (Rel8.litExpr x)
448− diff res (==) x
425+ diff res eq x
449
426
450 genDay :: Gen Day
427 genDay :: Gen Day
451 genDay = do
428 genDay = do
@@ -487,15 +464,13 @@ testDBEq getTestDatabase = testGroup "DBEq instances"
487
464
488 t :: forall a. (Eq a, Show a, Rel8.Sql Rel8.DBEq a)
465 t :: forall a. (Eq a, Show a, Rel8.Sql Rel8.DBEq a)
489 => Gen a
466 => Gen a
490− -> (TestT Transaction () -> PropertyT IO ())
467+ -> ((Connection -> TestT IO ()) -> PropertyT IO ())
491 -> PropertyT IO ()
468 -> PropertyT IO ()
492 t generator transaction = do
469 t generator transaction = do
493 (x, y) <- forAll (liftA2 (,) generator generator)
470 (x, y) <- forAll (liftA2 (,) generator generator)
494
471
495− transaction do
472+ transaction \connection -> do
496− [res] <- lift do
497− statement () $ Rel8.select do
498− pure $ Rel8.litExpr x Rel8.==. Rel8.litExpr y
473+ [res] <- liftIO $ Rel8.select connection $ pure $ Rel8.litExpr x Rel8.==. Rel8.litExpr y
499 res === (x == y)
474 res === (x == y)
500
475
501
476
@@ -503,10 +478,9 @@ testTableEquality :: IO TmpPostgres.DB -> TestTree
503testTableEquality = databasePropertyTest "TestTable equality" \transaction -> do
478testTableEquality = databasePropertyTest "TestTable equality" \transaction -> do
504 (x, y) <- forAll $ liftA2 (,) genTestTable genTestTable
479 (x, y) <- forAll $ liftA2 (,) genTestTable genTestTable
505
480
506− transaction do
481+ transaction \connection -> do
507− [eq] <- lift do
482+ [eq] <- liftIO $ Rel8.select connection do
508− statement () $ Rel8.select do
509− pure $ Rel8.lit x Rel8.==: Rel8.lit y
483+ pure $ Rel8.lit x Rel8.==: Rel8.lit y
510
484
511 eq === (x == y)
485 eq === (x == y)
512
486
@@ -515,10 +489,8 @@ testFromString :: IO TmpPostgres.DB -> TestTree
515testFromString = databasePropertyTest "FromString" \transaction -> do
489testFromString = databasePropertyTest "FromString" \transaction -> do
516 str <- forAll $ Gen.list (Range.linear 0 10) Gen.unicode
490 str <- forAll $ Gen.list (Range.linear 0 10) Gen.unicode
517
491
518− transaction do
492+ transaction \connection -> do
519− [result] <- lift do
520− statement () $ Rel8.select do
521− pure $ fromString str
493+ [result] <- liftIO $ Rel8.select connection $ pure $ fromString str
522 result === pack str
494 result === pack str
523
495
524
496
@@ -526,11 +498,10 @@ testCatMaybeTable :: IO TmpPostgres.DB -> TestTree
526testCatMaybeTable = databasePropertyTest "catMaybeTable" \transaction -> do
498testCatMaybeTable = databasePropertyTest "catMaybeTable" \transaction -> do
527 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
499 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
528
500
529− transaction do
501+ transaction \connection -> do
530− selected <- lift do
531− statement () $ Rel8.select do
502+ selected <- liftIO $ Rel8.select connection do
532− testTable <- Rel8.values $ Rel8.lit <$> rows
503+ testTable <- Rel8.values $ Rel8.lit <$> rows
533− Rel8.catMaybeTable $ Rel8.bool Rel8.nothingTable (pure testTable) (testTableColumn2 testTable)
504+ Rel8.catMaybeTable $ Rel8.bool Rel8.nothingTable (pure testTable) (testTableColumn2 testTable)
534
505
535 sort selected === sort (filter testTableColumn2 rows)
506 sort selected === sort (filter testTableColumn2 rows)
536
507
@@ -539,10 +510,9 @@ testCatMaybe :: IO TmpPostgres.DB -> TestTree
539testCatMaybe = databasePropertyTest "catMaybe" \transaction -> evalM do
510testCatMaybe = databasePropertyTest "catMaybe" \transaction -> evalM do
540 rows <- forAll $ Gen.list (Range.linear 0 10) $ Gen.maybe Gen.bool
511 rows <- forAll $ Gen.list (Range.linear 0 10) $ Gen.maybe Gen.bool
541
512
542− transaction do
513+ transaction \connection -> do
543− selected <- lift do
514+ selected <- evalM $ liftIO $ Rel8.select connection do
544− statement () $ Rel8.select do
545− Rel8.catNull =<< Rel8.values (map Rel8.lit rows)
515+ Rel8.catNull =<< Rel8.values (map Rel8.lit rows)
546
516
547 sort selected === sort (catMaybes rows)
517 sort selected === sort (catMaybes rows)
548
518
@@ -551,38 +521,15 @@ testMaybeTable :: IO TmpPostgres.DB -> TestTree
551testMaybeTable = databasePropertyTest "maybeTable" \transaction -> evalM do
521testMaybeTable = databasePropertyTest "maybeTable" \transaction -> evalM do
552 (rows, def) <- forAll $ liftA2 (,) (Gen.list (Range.linear 0 10) genTestTable) genTestTable
522 (rows, def) <- forAll $ liftA2 (,) (Gen.list (Range.linear 0 10) genTestTable) genTestTable
553
523
554− transaction do
524+ transaction \connection -> do
555− selected <- lift do
525+ selected <- liftIO $ Rel8.select connection $
556− statement () $ Rel8.select do
557− Rel8.maybeTable (Rel8.lit def) id <$> Rel8.optional (Rel8.values (Rel8.lit <$> rows))
526+ Rel8.maybeTable (Rel8.lit def) id <$> Rel8.optional (Rel8.values (Rel8.lit <$> rows))
558
527
559 case rows of
528 case rows of
560 [] -> selected === [def]
529 [] -> selected === [def]
561 _ -> sort selected === sort rows
530 _ -> sort selected === sort rows
562
531
563
532
564−testAggregateMaybeTable :: IO TmpPostgres.DB -> TestTree
565−testAggregateMaybeTable = databasePropertyTest "aggregateMaybeTable" \transaction -> evalM do
566− rows <- forAll $ Gen.list (Range.linear 0 10) (Gen.maybe (Gen.int64 (Range.linear 0 10)))
567−
568− let
569− aggregate = go 0 False False
570− where
571− go !n nothing _ (Just a : as) = go (n + a) nothing True as
572− go n _ just (Nothing : as) = go n True just as
573− go _ False False [] = []
574− go _ True False [] = [Nothing]
575− go n False True [] = [Just n]
576− go n True True [] = [Nothing, Just n]
577−
578− transaction do
579− selected <- lift do
580− statement () $ Rel8.select do
581− Rel8.aggregate $ Rel8.aggregateMaybeTable Rel8.sum <$> Rel8.values (Rel8.lit <$> rows)
582−
583− sort selected === aggregate rows
584−
585−
586data TwoTestTables f =
533data TwoTestTables f =
587 TwoTestTables
534 TwoTestTables
588 { testTable1 :: TestTable f
535 { testTable1 :: TestTable f
@@ -603,10 +550,9 @@ testNestedTables = databasePropertyTest "Nested TestTables" \transaction -> eval
603 Gen.list (Range.linear 0 10) $
550 Gen.list (Range.linear 0 10) $
604 liftA2 TwoTestTables genTestTable genTestTable
551 liftA2 TwoTestTables genTestTable genTestTable
605
552
606− transaction do
553+ transaction \connection -> do
607− selected <- lift do
554+ selected <- liftIO $ Rel8.select connection do
608− statement () $ Rel8.select do
609− Rel8.values (Rel8.lit <$> rows)
555+ Rel8.values (Rel8.lit <$> rows)
610
556
611 sort selected === sort rows
557 sort selected === sort rows
612
558
@@ -616,12 +562,11 @@ testMaybeTableApplicative = databasePropertyTest "MaybeTable (<*>)" \transaction
616 rows1 <- genRows
562 rows1 <- genRows
617 rows2 <- genRows
563 rows2 <- genRows
618
564
619− transaction do
565+ transaction \connection -> do
620− selected <- lift do
621− statement () $ Rel8.select do
566+ selected <- liftIO $ Rel8.select connection do
622− as <- Rel8.optional (Rel8.values (Rel8.lit <$> rows1))
567+ as <- Rel8.optional (Rel8.values (Rel8.lit <$> rows1))
623− bs <- Rel8.optional (Rel8.values (Rel8.lit <$> rows2))
568+ bs <- Rel8.optional (Rel8.values (Rel8.lit <$> rows2))
624− pure $ liftA2 (,) as bs
569+ pure $ liftA2 (,) as bs
625
570
626 case (rows1, rows2) of
571 case (rows1, rows2) of
627 ([], []) -> selected === [Nothing]
572 ([], []) -> selected === [Nothing]
@@ -633,6 +578,14 @@ testMaybeTableApplicative = databasePropertyTest "MaybeTable (<*>)" \transaction
633 genRows = forAll do
578 genRows = forAll do
634 Gen.list (Range.linear 0 10) $ liftA2 TestTable (Gen.text (Range.linear 0 10) Gen.unicode) (pure True)
579 Gen.list (Range.linear 0 10) $ liftA2 TestTable (Gen.text (Range.linear 0 10) Gen.unicode) (pure True)
635
580
581+rollingBack
582+ :: (MonadBaseControl IO m, MonadIO m)
583+ => Connection -> m a -> m a
584+rollingBack connection =
585+ bracket_
586+ (liftIO (run (sql "BEGIN") connection))
587+ (liftIO (run (sql "ROLLBACK") connection))
588+
636
589
637genTestTable :: Gen (TestTable Result)
590genTestTable :: Gen (TestTable Result)
638genTestTable = do
591genTestTable = do
@@ -645,19 +598,19 @@ testUpdate :: IO TmpPostgres.DB -> TestTree
645testUpdate = databasePropertyTest "Can UPDATE TestTable" \transaction -> do
598testUpdate = databasePropertyTest "Can UPDATE TestTable" \transaction -> do
646 rows <- forAll $ Gen.map (Range.linear 0 5) $ liftA2 (,) genTestTable genTestTable
599 rows <- forAll $ Gen.map (Range.linear 0 5) $ liftA2 (,) genTestTable genTestTable
647
600
648− transaction do
601+ transaction \connection -> do
649− selected <- lift do
602+ void $ liftIO $ Rel8.insert connection
650− statement () $ Rel8.insert Rel8.Insert
603+ Rel8.Insert
651 { into = testTableSchema
604 { into = testTableSchema
652− , rows = Rel8.values $ map Rel8.lit $ Map.keys rows
605+ , rows = map Rel8.lit $ Map.keys rows
653 , onConflict = Rel8.DoNothing
606 , onConflict = Rel8.DoNothing
654− , returning = pure ()
607+ , returning = Rel8.NumberOfRowsAffected
655 }
608 }
656
609
610+ void $ liftIO $ Rel8.update connection
657− statement () $ Rel8.update Rel8.Update
611+ Rel8.Update
658 { target = testTableSchema
612 { target = testTableSchema
659− , from = pure ()
660− , set = \_ r ->
613+ , set = \r ->
661 let updates = map (bimap Rel8.lit Rel8.lit) $ Map.toList rows
614 let updates = map (bimap Rel8.lit Rel8.lit) $ Map.toList rows
662 in
615 in
663 foldl
616 foldl
@@ -671,12 +624,12 @@ testUpdate = databasePropertyTest "Can UPDATE TestTable" \transaction -> do
671 )
624 )
672 r
625 r
673 updates
626 updates
674− , updateWhere = \_ _ -> Rel8.lit True
627+ , updateWhere = \_ -> Rel8.lit True
675− , returning = pure ()
628+ , returning = Rel8.NumberOfRowsAffected
676 }
629 }
677
630
678− statement () $ Rel8.select do
631+ selected <- liftIO $ Rel8.select connection do
679− Rel8.each testTableSchema
632+ Rel8.each testTableSchema
680
633
681 sort selected === sort (Map.elems rows)
634 sort selected === sort (Map.elems rows)
682
635
@@ -689,96 +642,29 @@ testDelete :: IO TmpPostgres.DB -> TestTree
689testDelete = databasePropertyTest "Can DELETE TestTable" \transaction -> do
642testDelete = databasePropertyTest "Can DELETE TestTable" \transaction -> do
690 rows <- forAll $ Gen.list (Range.linear 0 5) genTestTable
643 rows <- forAll $ Gen.list (Range.linear 0 5) genTestTable
691
644
692− transaction do
645+ transaction \connection -> do
693− (deleted, selected) <- lift do
646+ void $ liftIO $ Rel8.insert connection
694− statement () $ Rel8.insert Rel8.Insert
647+ Rel8.Insert
695 { into = testTableSchema
648 { into = testTableSchema
696− , rows = Rel8.values $ map Rel8.lit rows
649+ , rows = map Rel8.lit rows
697 , onConflict = Rel8.DoNothing
650 , onConflict = Rel8.DoNothing
698− , returning = pure ()
651+ , returning = Rel8.NumberOfRowsAffected
699 }
652 }
700
653
654+ deleted <-
655+ liftIO $ Rel8.delete connection
701− deleted <- statement () $ Rel8.delete Rel8.Delete
656+ Rel8.Delete
702 { from = testTableSchema
657 { from = testTableSchema
703− , using = pure ()
704− , deleteWhere = const testTableColumn2
658+ , deleteWhere = testTableColumn2
705 , returning = Rel8.Projection id
659 , returning = Rel8.Projection id
706 }
660 }
707
661
708− selected <- statement () $ Rel8.select do
662+ selected <- liftIO $ Rel8.select connection do
709− Rel8.each testTableSchema
663+ Rel8.each testTableSchema
710−
711− pure (deleted, selected)
712
664
713 sort (deleted <> selected) === sort rows
665 sort (deleted <> selected) === sort rows
714
666
715
667
716−data UniqueTable f = UniqueTable
717− { uniqueTableKey :: Rel8.Column f Text
718− , uniqueTableValue :: Rel8.Column f Text
719− }
720− deriving stock Generic
721− deriving anyclass Rel8.Rel8able
722−
723−
724−deriving stock instance Eq (UniqueTable Result)
725−deriving stock instance Ord (UniqueTable Result)
726−deriving stock instance Show (UniqueTable Result)
727−
728−
729−uniqueTableSchema :: Rel8.TableSchema (UniqueTable Rel8.Name)
730−uniqueTableSchema =
731− Rel8.TableSchema
732− { name = "unique_table"
733− , schema = Nothing
734− , columns = UniqueTable
735− { uniqueTableKey = "key"
736− , uniqueTableValue = "value"
737− }
738− }
739−
740−
741−genUniqueTable :: Gen (UniqueTable Result)
742−genUniqueTable = do
743− uniqueTableKey <- Gen.text (Range.linear 0 5) Gen.alphaNum
744− uniqueTableValue <- Gen.text (Range.linear 0 5) Gen.alphaNum
745− pure UniqueTable {..}
746−
747−
748−testUpsert :: IO TmpPostgres.DB -> TestTree
749−testUpsert = databasePropertyTest "Can UPSERT UniqueTable" \transaction -> do
750− as <- unique $ forAll $ Gen.list (Range.linear 0 20) genUniqueTable
751− bs <- unique $ forAll $ Gen.list (Range.linear 0 20) genUniqueTable
752−
753− transaction do
754− selected <- lift do
755− statement () $ Rel8.insert Rel8.Insert
756− { into = uniqueTableSchema
757− , rows = Rel8.values $ Rel8.lit <$> as
758− , onConflict = Rel8.DoNothing
759− , returning = pure ()
760− }
761−
762− statement () $ Rel8.insert Rel8.Insert
763− { into = uniqueTableSchema
764− , rows = Rel8.values $ Rel8.lit <$> bs
765− , onConflict = Rel8.DoUpdate Rel8.Upsert
766− { index = uniqueTableKey
767− , set = \UniqueTable {uniqueTableValue} old -> old {uniqueTableValue}
768− , updateWhere = \_ _ -> Rel8.true
769− }
770− , returning = pure ()
771− }
772−
773− statement () $ Rel8.select do
774− Rel8.each uniqueTableSchema
775−
776− fromUniqueTables selected === fromUniqueTables bs <> fromUniqueTables as
777− where
778− unique = fmap (nubOrdOn uniqueTableKey)
779− fromUniqueTables = Map.fromList . map \(UniqueTable key value) -> (key, value)
780−
781−
782newtype HKNestedPair f = HKNestedPair { pairOne :: (TestTable f, TestTable f) }
668newtype HKNestedPair f = HKNestedPair { pairOne :: (TestTable f, TestTable f) }
783 deriving stock Generic
669 deriving stock Generic
784 deriving anyclass Rel8.Rel8able
670 deriving anyclass Rel8.Rel8able
@@ -792,10 +678,9 @@ testSelectNestedPairs :: IO TmpPostgres.DB -> TestTree
792testSelectNestedPairs = databasePropertyTest "Can SELECT nested pairs" \transaction -> do
678testSelectNestedPairs = databasePropertyTest "Can SELECT nested pairs" \transaction -> do
793 rows <- forAll $ Gen.list (Range.linear 0 10) $ HKNestedPair <$> liftA2 (,) genTestTable genTestTable
679 rows <- forAll $ Gen.list (Range.linear 0 10) $ HKNestedPair <$> liftA2 (,) genTestTable genTestTable
794
680
795− transaction do
681+ transaction \connection -> do
796− selected <- lift do
682+ selected <- liftIO $ Rel8.select connection do
797− statement () $ Rel8.select do
798− Rel8.values $ map Rel8.lit rows
683+ Rel8.values $ map Rel8.lit rows
799
684
800 sort selected === sort rows
685 sort selected === sort rows
801
686
@@ -804,20 +689,18 @@ testSelectArray :: IO TmpPostgres.DB -> TestTree
804testSelectArray = databasePropertyTest "Can SELECT Arrays (with aggregation)" \transaction -> do
689testSelectArray = databasePropertyTest "Can SELECT Arrays (with aggregation)" \transaction -> do
805 rows <- forAll $ Gen.list (Range.linear 1 10) Gen.bool
690 rows <- forAll $ Gen.list (Range.linear 1 10) Gen.bool
806
691
807− transaction do
692+ transaction \connection -> do
808− selected <- lift do
693+ selected <- liftIO $ Rel8.select connection do
809− statement () $ Rel8.select do
810− Rel8.many $ Rel8.values (map Rel8.lit rows)
694+ Rel8.many $ Rel8.values (map Rel8.lit rows)
811
695
812 selected === [foldMap pure rows]
696 selected === [foldMap pure rows]
813
697
814− selected' <- lift do
815− statement () $ Rel8.select do
698+ selected' <- liftIO $ Rel8.select connection $ do
816− a <- Rel8.catListTable =<< do
699+ a <- Rel8.catListTable =<< do
817− Rel8.many $ Rel8.values (map Rel8.lit rows)
700+ Rel8.many $ Rel8.values (map Rel8.lit rows)
818− b <- Rel8.catListTable =<< do
701+ b <- Rel8.catListTable =<< do
819− Rel8.many $ Rel8.values (map Rel8.lit rows)
702+ Rel8.many $ Rel8.values (map Rel8.lit rows)
820− pure (a, b)
703+ pure (a, b)
821
704
822 selected' === liftA2 (,) rows rows
705 selected' === liftA2 (,) rows rows
823
706
@@ -839,11 +722,10 @@ testNestedMaybeTable :: IO TmpPostgres.DB -> TestTree
839testNestedMaybeTable = databasePropertyTest "Can nest MaybeTable within other tables" \transaction -> do
722testNestedMaybeTable = databasePropertyTest "Can nest MaybeTable within other tables" \transaction -> do
840 let example = NestedMaybeTable { nmt1 = True, nmt2 = Just (TestTable "Hi" True) }
723 let example = NestedMaybeTable { nmt1 = True, nmt2 = Just (TestTable "Hi" True) }
841
724
842− transaction do
725+ transaction \connection -> do
843− selected <- lift do
844− statement () $ Rel8.select do
726+ selected <- liftIO $ Rel8.select connection do
845− x <- Rel8.values [Rel8.lit example]
727+ x <- Rel8.values [Rel8.lit example]
846− pure $ Rel8.maybeTable (Rel8.lit False) (\_ -> Rel8.lit True) (nmt2 x)
728+ pure $ Rel8.maybeTable (Rel8.lit False) (\_ -> Rel8.lit True) (nmt2 x)
847
729
848 selected === [True]
730 selected === [True]
849
731
@@ -851,12 +733,11 @@ testNestedMaybeTable = databasePropertyTest "Can nest MaybeTable within other ta
851testEvaluate :: IO TmpPostgres.DB -> TestTree
733testEvaluate :: IO TmpPostgres.DB -> TestTree
852testEvaluate = databasePropertyTest "evaluate has the evaluation order we expect" \transaction -> do
734testEvaluate = databasePropertyTest "evaluate has the evaluation order we expect" \transaction -> do
853
735
854− transaction do
736+ transaction \connection -> do
855− selected <- lift do
856− statement () $ Rel8.select do
737+ selected <- liftIO $ Rel8.select connection do
857− x <- Rel8.values (Rel8.lit <$> ['a', 'b', 'c'])
738+ x <- Rel8.values (Rel8.lit <$> ['a', 'b', 'c'])
858− y <- Rel8.evaluate (Rel8.nextval "test_seq")
739+ y <- Rel8.evaluate (Rel8.nextval "test_seq")
859− pure (x, (y, y))
740+ pure (x, (y, y))
860
741
861 normalize selected ===
742 normalize selected ===
862 [ ('a', (0, 0))
743 [ ('a', (0, 0))
@@ -864,12 +745,11 @@ testEvaluate = databasePropertyTest "evaluate has the evaluation order we expect
864 , ('c', (2, 2))
745 , ('c', (2, 2))
865 ]
746 ]
866
747
867− selected' <- lift do
868− statement () $ Rel8.select do
748+ selected' <- liftIO $ Rel8.select connection do
869− x <- Rel8.values (Rel8.lit <$> ['a', 'b', 'c'])
749+ x <- Rel8.values (Rel8.lit <$> ['a', 'b', 'c'])
870− y <- Rel8.values (Rel8.lit <$> ['d', 'e', 'f'])
750+ y <- Rel8.values (Rel8.lit <$> ['d', 'e', 'f'])
871− z <- Rel8.evaluate (Rel8.nextval "test_seq")
751+ z <- Rel8.evaluate (Rel8.nextval "test_seq")
872− pure ((x, y), (z, z))
752+ pure ((x, y), (z, z))
873
753
874 normalize selected' ===
754 normalize selected' ===
875 [ (('a', 'd'), (0, 0))
755 [ (('a', 'd'), (0, 0))
@@ -887,3 +767,13 @@ testEvaluate = databasePropertyTest "evaluate has the evaluation order we expect
887 normalize :: [(x, (Int64, Int64))] -> [(x, (Int64, Int64))]
767 normalize :: [(x, (Int64, Int64))] -> [(x, (Int64, Int64))]
888 normalize [] = []
768 normalize [] = []
889 normalize xs@((_, (i, _)) : _) = map (fmap (\(a, b) -> (a - i, b - i))) xs
769 normalize xs@((_, (i, _)) : _) = map (fmap (\(a, b) -> (a - i, b - i))) xs
770+
771+{-
772+ selected <- liftIO $ Rel8.select connection do
773+ x <- Rel8.values (Rel8.lit <$> ['a', 'b', 'c'])
774+ x <- Rel8.values (Rel8.lit <$> ['d', 'e', 'f'])
775+ y <- Rel8.evaluate (Rel8.nextval "test_seq")
776+ pure (x, y, y)
777+
778+ selected === [('a', 1, 1), ('b', 2, 2), ('c', 3, 3)]
779+-}
tests/Rel8/Generic/Rel8able/Test.hs+15−46
@@ -1,11 +1,11 @@
1{-# language DataKinds #-}
1{-# language DataKinds #-}
2{-# language DeriveAnyClass #-}
2{-# language DeriveAnyClass #-}
3{-# language DeriveGeneric #-}
3{-# language DeriveGeneric #-}
4−{-# language DerivingStrategies #-}
4+{-# language DerivingVia #-}
5{-# language DuplicateRecordFields #-}
5{-# language DuplicateRecordFields #-}
6{-# language FlexibleInstances #-}
6{-# language FlexibleInstances #-}
7{-# language MultiParamTypeClasses #-}
7{-# language MultiParamTypeClasses #-}
8−{-# language StandaloneKindSignatures #-}
8+{-# language StandaloneDeriving #-}
9{-# language TypeFamilies #-}
9{-# language TypeFamilies #-}
10{-# language UndecidableInstances #-}
10{-# language UndecidableInstances #-}
11
11
@@ -98,14 +98,24 @@ data S3Object = S3Object
98 deriving stock Generic
98 deriving stock Generic
99
99
100
100
101+deriving via HKDT S3Object
102+ instance Table Result S3Object
103+
104+
105+deriving via HKDT S3Object
101−instance x ~ HKD S3Object Expr => ToExprs x S3Object
106+ instance x ~ HKD S3Object Expr => ToExprs x S3Object
102
107
103
108
104data HKDSum = HKDSumA Text | HKDSumB Bool Char | HKDSumC
109data HKDSum = HKDSumA Text | HKDSumB Bool Char | HKDSumC
105 deriving stock Generic
110 deriving stock Generic
106
111
107
112
113+deriving via HKDT HKDSum
114+ instance Table Result HKDSum
115+
116+
117+deriving via HKDT HKDSum
108−instance x ~ HKD HKDSum Expr => ToExprs x HKDSum
118+ instance x ~ HKD HKDSum Expr => ToExprs x HKDSum
109
119
110
120
111data HKDTest f = HKDTest
121data HKDTest f = HKDTest
@@ -138,51 +148,10 @@ data TableSum f
138 deriving stock Generic
148 deriving stock Generic
139
149
140
150
141−data BarbieSum f
142− = BarbieSumA (f Bool) (f Text)
143− | BarbieSumB
144− | BarbieSumC (f Text)
145− deriving stock Generic
146−
147−
148data TableProduct f = TableProduct
151data TableProduct f = TableProduct
149− { sum :: HADT f BarbieSum
152+ { sum :: HADT f TableSum
150 , list :: TableList f
153 , list :: TableList f
151 , foos :: HList f (HADT f TableSum, Lift f HKDSum, HKDTest f)
154 , foos :: HList f (HADT f TableSum, Lift f HKDSum, HKDTest f)
152 }
155 }
153 deriving stock Generic
156 deriving stock Generic
154 deriving anyclass Rel8able
157 deriving anyclass Rel8able
155−
156−
157−data TableTestB f = TableTestB
158− { foo :: f Bool
159− , bar :: f (Maybe Bool)
160− }
161− deriving stock Generic
162− deriving anyclass Rel8able
163−
164−
165−data NestedTableTestB f = NestedTableTestB
166− { foo :: f Bool
167− , bar :: f (Maybe Bool)
168− , baz :: Column f Char
169− , nest :: TableTestB f
170− }
171− deriving stock Generic
172− deriving anyclass Rel8able
173−
174−
175−newtype IdRecord a f = IdRecord { recordId :: Column f a }
176− deriving stock Generic
177−
178−
179−instance DBType a => Rel8able (IdRecord a)
180−
181−
182−type Nest :: KRel8able -> KRel8able -> KRel8able
183−data Nest t u f = Nest
184− { foo :: t f
185− , bar :: u f
186− }
187− deriving stock Generic
188− deriving anyclass Rel8able