packages feed

rel8 1.7.0.0 → 1.8.0.0

raw patch · 179 files changed

+907/−16974 lines, 179 filesdep +rel8-internaldep +template-haskelldep +th-abstractiondep −attoparsecdep −base-compatdep −base16dep ~basedep ~hasqldep ~hedgehogPVP ok

version bump matches the API change (PVP)

Dependencies added: rel8-internal, template-haskell, th-abstraction

Dependencies removed: attoparsec, base-compat, base16, contravariant, pretty, semialign, utf8-string

Dependency ranges changed: base, hasql, hedgehog, iproute, opaleye

API changes (from Hackage documentation)

- Rel8: ($dmenumValue) :: (DBEnum a, Enumable a) => a -> String
- Rel8: ($dmenumerate) :: (DBEnum a, Enumable a) => [a]
- Rel8: ($dmeqTable) :: (EqTable a, GTable TEqTable TColumns (Rep (Record a)), Columns a ~ GColumns TColumns (Rep (Record a))) => Columns a (Dict (Sql DBEq))
- Rel8: ($dmfromColumns) :: (Table context a, Generic (Record a), GTable (TTable context) TColumns (Rep (Record a)), Columns a ~ GColumns TColumns (Rep (Record a))) => Columns a context -> a
- Rel8: ($dmfromResult) :: (Table context a, Generic (Record (FromExprs a)), GSerialize TSerialize TColumns (Rep (Record a)) (Rep (Record (FromExprs a))), Columns a ~ GColumns TColumns (Rep (Record a))) => Columns a Result -> FromExprs a
- Rel8: ($dmordTable) :: (OrdTable a, GTable TOrdTable TColumns (Rep (Record a)), Columns a ~ GColumns TColumns (Rep (Record a))) => Columns a (Dict (Sql DBOrd))
- Rel8: ($dmtoColumns) :: (Table context a, Generic (Record a), GTable (TTable context) TColumns (Rep (Record a)), Columns a ~ GColumns TColumns (Rep (Record a))) => a -> Columns a context
- Rel8: ($dmtoResult) :: (Table context a, Generic (Record (FromExprs a)), GSerialize TSerialize TColumns (Rep (Record a)) (Rep (Record (FromExprs a))), Columns a ~ GColumns TColumns (Rep (Record a))) => FromExprs a -> Columns a Result
- Rel8: -- context to the corresponding Haskell type.
- Rel8: -- | The <tt>FromExprs</tt> type family maps a type in the <tt>Expr</tt>
- Rel8: infix 4 >=?
- Rel8: infixl 1 `over`
- Rel8: infixl 3 <|>:
- Rel8: infixl 4 $+
- Rel8: infixr 2 ||.
- Rel8: infixr 3 &&.
- Rel8: infixr 6 <>.
- Rel8.Expr.Text: infix 2 !~*
- Rel8.Expr.Text: infixr 6 ++.
- Rel8.Table.Verify: [SomeTableSchema] :: forall (k :: (Type -> Type) -> Type). (ToExprs (k Expr) (GFromExprs k), Rel8able k) => TableSchema (k Name) -> SomeTableSchema
- Rel8.Table.Verify: checkedShowCreateTable :: Rel8able k => TableSchema (k Name) -> Either (Map String (NonEmpty [String])) String
- Rel8.Table.Verify: data SomeTableSchema
- Rel8.Table.Verify: getSchemaErrors :: [SomeTableSchema] -> Statement () (Maybe Text)
- Rel8.Table.Verify: instance GHC.Generics.Generic (Rel8.Table.Verify.Attribute f)
- Rel8.Table.Verify: instance GHC.Generics.Generic (Rel8.Table.Verify.Cast f)
- Rel8.Table.Verify: instance GHC.Generics.Generic (Rel8.Table.Verify.PGAttribute f)
- Rel8.Table.Verify: instance GHC.Generics.Generic (Rel8.Table.Verify.PGCast f)
- Rel8.Table.Verify: instance GHC.Generics.Generic (Rel8.Table.Verify.PGClass f)
- Rel8.Table.Verify: instance GHC.Generics.Generic (Rel8.Table.Verify.PGNamespace f)
- Rel8.Table.Verify: instance GHC.Generics.Generic (Rel8.Table.Verify.PGTable f)
- Rel8.Table.Verify: instance GHC.Generics.Generic (Rel8.Table.Verify.PGType f)
- Rel8.Table.Verify: instance GHC.Show.Show (Rel8.Table.Verify.Attribute Rel8.Schema.Result.Result)
- Rel8.Table.Verify: instance GHC.Show.Show (Rel8.Table.Verify.Cast Rel8.Schema.Result.Result)
- Rel8.Table.Verify: instance GHC.Show.Show (Rel8.Table.Verify.PGAttribute Rel8.Schema.Result.Result)
- Rel8.Table.Verify: instance GHC.Show.Show (Rel8.Table.Verify.PGCast Rel8.Schema.Result.Result)
- Rel8.Table.Verify: instance GHC.Show.Show (Rel8.Table.Verify.PGClass Rel8.Schema.Result.Result)
- Rel8.Table.Verify: instance GHC.Show.Show (Rel8.Table.Verify.PGNamespace Rel8.Schema.Result.Result)
- Rel8.Table.Verify: instance GHC.Show.Show (Rel8.Table.Verify.PGTable Rel8.Schema.Result.Result)
- Rel8.Table.Verify: instance GHC.Show.Show (Rel8.Table.Verify.PGType Rel8.Schema.Result.Result)
- Rel8.Table.Verify: instance GHC.Show.Show Rel8.Table.Verify.CheckEnv
- Rel8.Table.Verify: instance GHC.Show.Show Rel8.Table.Verify.ColumnError
- Rel8.Table.Verify: instance GHC.Show.Show Rel8.Table.Verify.ColumnInfo
- Rel8.Table.Verify: instance GHC.Show.Show Rel8.Table.Verify.Oid
- Rel8.Table.Verify: instance GHC.Show.Show Rel8.Table.Verify.Relkind
- Rel8.Table.Verify: instance GHC.Show.Show Rel8.Table.Verify.TableInfo
- Rel8.Table.Verify: instance GHC.Show.Show Rel8.Table.Verify.TypeInfo
- Rel8.Table.Verify: instance Rel8.Generic.Rel8able.Rel8able Rel8.Table.Verify.Attribute
- Rel8.Table.Verify: instance Rel8.Generic.Rel8able.Rel8able Rel8.Table.Verify.Cast
- Rel8.Table.Verify: instance Rel8.Generic.Rel8able.Rel8able Rel8.Table.Verify.PGAttribute
- Rel8.Table.Verify: instance Rel8.Generic.Rel8able.Rel8able Rel8.Table.Verify.PGCast
- Rel8.Table.Verify: instance Rel8.Generic.Rel8able.Rel8able Rel8.Table.Verify.PGClass
- Rel8.Table.Verify: instance Rel8.Generic.Rel8able.Rel8able Rel8.Table.Verify.PGNamespace
- Rel8.Table.Verify: instance Rel8.Generic.Rel8able.Rel8able Rel8.Table.Verify.PGTable
- Rel8.Table.Verify: instance Rel8.Generic.Rel8able.Rel8able Rel8.Table.Verify.PGType
- Rel8.Table.Verify: instance Rel8.Type.DBType Rel8.Table.Verify.Oid
- Rel8.Table.Verify: instance Rel8.Type.DBType Rel8.Table.Verify.Relkind
- Rel8.Table.Verify: instance Rel8.Type.Eq.DBEq Rel8.Table.Verify.Oid
- Rel8.Table.Verify: instance Rel8.Type.Eq.DBEq Rel8.Table.Verify.Relkind
- Rel8.Table.Verify: showCreateTable :: Rel8able k => TableSchema (k Name) -> String
- Rel8.Tabulate: instance (Rel8.Table.Eq.EqTable k, Rel8.Table.Table Rel8.Expr.Expr a, GHC.Base.Semigroup a) => GHC.Base.Monoid (Rel8.Tabulate.Tabulation k a)
- Rel8.Tabulate: instance (Rel8.Table.Eq.EqTable k, Rel8.Table.Table Rel8.Expr.Expr a, GHC.Base.Semigroup a) => GHC.Base.Semigroup (Rel8.Tabulate.Tabulation k a)
- Rel8.Tabulate: instance GHC.Base.Functor (Rel8.Tabulate.Tabulation k)
- Rel8.Tabulate: instance GHC.Base.Monoid (Rel8.Tabulate.Predicate k)
- Rel8.Tabulate: instance GHC.Base.Semigroup (Rel8.Tabulate.Predicate k)
- Rel8.Tabulate: instance Rel8.Table.Eq.EqTable k => Data.Functor.Bind.Class.Apply (Rel8.Tabulate.Tabulation k)
- Rel8.Tabulate: instance Rel8.Table.Eq.EqTable k => Data.Functor.Bind.Class.Bind (Rel8.Tabulate.Tabulation k)
- Rel8.Tabulate: instance Rel8.Table.Eq.EqTable k => GHC.Base.Applicative (Rel8.Tabulate.Tabulation k)
- Rel8.Tabulate: instance Rel8.Table.Eq.EqTable k => GHC.Base.Monad (Rel8.Tabulate.Tabulation k)
- Rel8.Tabulate: instance Rel8.Table.Eq.EqTable k => Rel8.Table.Alternative.AltTable (Rel8.Tabulate.Tabulation k)
- Rel8.Tabulate: instance Rel8.Table.Eq.EqTable k => Rel8.Table.Alternative.AlternativeTable (Rel8.Tabulate.Tabulation k)
- Rel8.Tabulate: instance Rel8.Table.Projection.Biprojectable Rel8.Tabulate.Tabulation
- Rel8.Tabulate: instance Rel8.Table.Projection.Projectable (Rel8.Tabulate.Tabulation k)
+ Rel8: OnConstraint :: String -> Conflict exprs
+ Rel8: OnIndex :: Index exprs -> Conflict exprs
+ Rel8: [Index] :: forall index exprs. Table Expr index => (exprs -> index) -> Maybe (exprs -> Expr Bool) -> Index exprs
+ Rel8: data Conflict exprs
+ Rel8: data Index exprs
+ Rel8.Array: notElem :: Sql DBEq a => Expr a -> Expr [a] -> Expr Bool
+ Rel8.Array: notElem1 :: Sql DBEq a => Expr a -> Expr (NonEmpty a) -> Expr Bool
+ Rel8.Range: Empty :: Range a
+ Rel8.Range: Excl :: a -> Bound a
+ Rel8.Range: Incl :: a -> Bound a
+ Rel8.Range: Inf :: Bound a
+ Rel8.Range: Multirange :: Multirange a -> Multirange a
+ Rel8.Range: Range :: Bound a -> Bound a -> Range a
+ Rel8.Range: class DBOrd a => DBRange a
+ Rel8.Range: data Bound a
+ Rel8.Range: data Range a
+ Rel8.Range: multirange :: DBRange a => [Expr (Range a)] -> Expr (Multirange a)
+ Rel8.Range: multirangeDecoder :: DBRange a => Value (Multirange a)
+ Rel8.Range: multirangeEncoder :: DBRange a => Value (Multirange a)
+ Rel8.Range: multirangeTypeName :: DBRange a => QualifiedName
+ Rel8.Range: newtype Multirange a
+ Rel8.Range: range :: DBRange a => Range (Expr a) -> Expr (Range a)
+ Rel8.Range: rangeAgg :: forall a (fold :: Fold). DBRange a => Aggregator' fold (Expr (Range a)) (Expr (Multirange a))
+ Rel8.Range: rangeDecoder :: DBRange a => Value (Range a)
+ Rel8.Range: rangeEncoder :: DBRange a => Value (Range a)
+ Rel8.Range: rangeTypeName :: DBRange a => QualifiedName
+ Rel8.TH: deriveRel8able :: Name -> Q [Dec]
+ Rel8.TH: deriveRel8ables :: [Name] -> Q [Dec]
+ Rel8.TH: instance GHC.Internal.Show.Show Rel8.TH.ParsedDatatype
+ Rel8.TH: instance GHC.Internal.Show.Show Rel8.TH.ParsedField
+ Rel8.Tabulate: instance (Rel8.Internal.Table.Eq.EqTable k, Rel8.Internal.Table.Table Rel8.Internal.Expr.Expr a, GHC.Internal.Base.Semigroup a) => GHC.Internal.Base.Monoid (Rel8.Tabulate.Tabulation k a)
+ Rel8.Tabulate: instance (Rel8.Internal.Table.Eq.EqTable k, Rel8.Internal.Table.Table Rel8.Internal.Expr.Expr a, GHC.Internal.Base.Semigroup a) => GHC.Internal.Base.Semigroup (Rel8.Tabulate.Tabulation k a)
+ Rel8.Tabulate: instance GHC.Internal.Base.Functor (Rel8.Tabulate.Tabulation k)
+ Rel8.Tabulate: instance GHC.Internal.Base.Monoid (Rel8.Tabulate.Predicate k)
+ Rel8.Tabulate: instance GHC.Internal.Base.Semigroup (Rel8.Tabulate.Predicate k)
+ Rel8.Tabulate: instance Rel8.Internal.Table.Eq.EqTable k => Data.Functor.Bind.Class.Apply (Rel8.Tabulate.Tabulation k)
+ Rel8.Tabulate: instance Rel8.Internal.Table.Eq.EqTable k => Data.Functor.Bind.Class.Bind (Rel8.Tabulate.Tabulation k)
+ Rel8.Tabulate: instance Rel8.Internal.Table.Eq.EqTable k => GHC.Internal.Base.Applicative (Rel8.Tabulate.Tabulation k)
+ Rel8.Tabulate: instance Rel8.Internal.Table.Eq.EqTable k => GHC.Internal.Base.Monad (Rel8.Tabulate.Tabulation k)
+ Rel8.Tabulate: instance Rel8.Internal.Table.Eq.EqTable k => Rel8.Internal.Table.Alternative.AltTable (Rel8.Tabulate.Tabulation k)
+ Rel8.Tabulate: instance Rel8.Internal.Table.Eq.EqTable k => Rel8.Internal.Table.Alternative.AlternativeTable (Rel8.Tabulate.Tabulation k)
+ Rel8.Tabulate: instance Rel8.Internal.Table.Projection.Biprojectable Rel8.Tabulate.Tabulation
+ Rel8.Tabulate: instance Rel8.Internal.Table.Projection.Projectable (Rel8.Tabulate.Tabulation k)
- Rel8: Abort :: OnConflict names
+ Rel8: Abort :: OnConflict exprs
- Rel8: DoNothing :: OnConflict names
+ Rel8: DoNothing :: Maybe (Conflict exprs) -> OnConflict exprs
- Rel8: DoUpdate :: Upsert names -> OnConflict names
+ Rel8: DoUpdate :: Upsert exprs -> OnConflict exprs
- Rel8: [Insert] :: forall names exprs a. Selects names exprs => TableSchema names -> Query exprs -> OnConflict names -> Returning names a -> Insert a
+ Rel8: [Insert] :: forall names exprs a. Selects names exprs => TableSchema names -> Query exprs -> OnConflict exprs -> Returning names a -> Insert a
- Rel8: [Upsert] :: forall names exprs index excluded. (Selects names exprs, Projecting names index, excluded ~ exprs) => Projection names index -> Maybe (exprs -> Expr Bool) -> (excluded -> exprs -> exprs) -> (excluded -> exprs -> Expr Bool) -> Upsert names
+ Rel8: [Upsert] :: forall excluded exprs. excluded ~ exprs => Conflict exprs -> (excluded -> exprs -> exprs) -> (excluded -> exprs -> Expr Bool) -> Upsert exprs
- Rel8: data OnConflict names
+ Rel8: data OnConflict exprs
- Rel8: data Upsert names
+ Rel8: data Upsert exprs
- Rel8.Array: infix 4 `elem1`
+ Rel8.Array: infix 4 `notElem1`

Files

Changelog.md view
@@ -1,4 +1,45 @@ +<a id='changelog-1.8.0.0'></a>+# 1.8.0.0 — 2026-09-16++## Added++- Added `Rel8.TH.deriveRel8able` and `Rel8.TH.deriveRel8ables` for deriving `Rel8able` instances using `TemplateHaskell`. +  This can be significantly faster than using `Generics`. In testing, we have seen 80% reductions in build time!+  +- Expose all `rel8` internal modules from the `rel8-internal` package.++- Added new `Conflict` and `Index` types. `Conflict` represents a [`conflict_target`](https://www.postgresql.org/docs/current/sql-insert.html#SQL-ON-CONFLICT) in an `ON CONFLICT`. It can be either a named constraint (`ON CONSTRAINT`) or a an `Index`.++- Added `Index`. `Index` is a description of a unique index which PostgreSQL can use for *unique index inference*. This is an alternative to specifying an explicit named constraint in a `conflict_target`.++- Add `notElem` and `notElem1` to `Rel8.Array`++- Added preliminary support for PostgreSQL ranges.++- Support GHC-9.14 and `semialign >= 1.4`.++- Added `notElem` and `notElem1` to `Rel8.Array`.++- Added `DBType Aeson.Object` instance.++- Bumped a variety of bounds.++## Changed++- The `Upsert` type was changed. Previously it had the columns (`index`, `predicate`) of what is now the `Index` type baked into its record. It now instead has a single `conflict` column (of type `Conflict`, which can be either an `Index` or a named constraint).+- The `DoNothing` constructor of `OnConflict` was changed to also take an optional `Conflict` value. Even though `ON CONFLICT DO NOTHING` does not generally require a `conflict_target`, there are cases where it can be necessary, e.g., if you have table that has both deferrable and non-deferrable constraints.++- `rel8` now requires at least version `0.10.8.0` of `opaleye`++## Fixed++- `elem` and `elem1` now use `IS NOT DISTINCT FROM` semantics (matching `(==.)`) when the element type is nullable, so `null` is found in an array containing `null`. Previously they were implemented with the array containment operator `<@`, which never matches `null`.++- Fixed some issues around the truncation of long column names.++- Improved documentation.+ <a id='changelog-1.7.0.0'></a> # 1.7.0.0 — 2025-07-31 @@ -12,9 +53,11 @@  - Added new `Encoder` type with three members: `binary`, which is the Hasql binary encoder, `text` which encodes a type in PostgreSQL's text format (needed for nested arrays) and `quote`, which is the does the thing that the function we previously called `encode` does (i.e., `a -> Opaleye.PrimExpr`). +- Add `elem` and `elem1` to `Rel8.Array` for testing if an element is contained in `[]` and `NonEmpty` `Expr`s.+ - Support hasql-1.9 -- Add `elem` and `elem1` to `Rel8.Array` for testing if an element is contained in `[]` and `NonEmpty` `Expr`s.+- Support GHC-9.12  ## Changed 
− README.md
@@ -1,17 +0,0 @@-# Welcome!--Welcome to Rel8! Rel8 is a Haskell library for interacting with PostgreSQL databases, built on top of the fantastic Opaleye library.--The main objectives of Rel8 are:--* *Conciseness*: Users using Rel8 should not need to write boiler-plate code. By using expressive types, we can provide sufficient information for the compiler to infer code whenever possible.--* *Inferrable*: Despite using a lot of type level magic, Rel8 aims to have excellent and predictable type inference.--* *Familiar*: writing Rel8 queries should feel like normal Haskell programming.--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:--[![Rel8 presentation at ZuriHac 2021](https://img.youtube.com/vi/3uwrtjxiq6E/hqdefault.jpg)](http://www.youtube.com/watch?v=3uwrtjxiq6E)--For more details, check out the [official documentation](https://rel8.readthedocs.io/en/latest/).
rel8.cabal view
@@ -1,8 +1,8 @@-cabal-version:       2.0+cabal-version:       3.0 name:                rel8-version:             1.7.0.0+version:             1.8.0.0 synopsis:            Hey! Hey! Can u rel8?-license:             BSD3+license:             BSD-3-Clause license-file:        LICENSE author:              Oliver Charles maintainer:          ollie@ocharles.org.uk@@ -10,7 +10,6 @@ bug-reports:         https://github.com/circuithub/rel8/issues build-type:          Simple extra-doc-files:-    README.md     Changelog.md  source-repository head@@ -19,33 +18,19 @@  library   build-depends:-      aeson-    , attoparsec-    , base >= 4.16 && < 4.22-    , base16 >= 1.0-    , base-compat >= 0.11 && < 0.15+      rel8-internal ==1.8.0.0+    , base >= 4.16 && < 4.23     , bifunctors     , bytestring-    , case-insensitive     , comonad-    , containers-    , contravariant-    , hasql >= 1.8 && < 1.10-    , iproute ^>= 1.7-    , opaleye ^>= 0.10.2.1-    , pretty+    , opaleye ^>= 0.10.8.0     , profunctors     , product-profunctors-    , scientific-    , semialign     , semigroupoids-    , text-    , these     , time-    , transformers-    , utf8-string-    , uuid-    , vector+    , containers+    , template-haskell+    , th-abstraction    default-language:     Haskell2010@@ -59,9 +44,11 @@     -Wno-missing-role-annotations     -Wno-missing-deriving-strategies     -Wno-term-variable-capture+    -Wno-all-missed-specializations    hs-source-dirs:     src+   exposed-modules:     Rel8     Rel8.Array@@ -70,183 +57,9 @@     Rel8.Expr.Num     Rel8.Expr.Text     Rel8.Expr.Time-    Rel8.Table.Verify+    Rel8.Range     Rel8.Tabulate--  other-modules:-    Rel8.Aggregate-    Rel8.Aggregate.Fold-    Rel8.Aggregate.Function--    Rel8.Column-    Rel8.Column.ADT-    Rel8.Column.Either-    Rel8.Column.Lift-    Rel8.Column.List-    Rel8.Column.Maybe-    Rel8.Column.NonEmpty-    Rel8.Column.Null-    Rel8.Column.These--    Rel8.Expr-    Rel8.Expr.Aggregate-    Rel8.Expr.Array-    Rel8.Expr.Bool-    Rel8.Expr.Default-    Rel8.Expr.Eq-    Rel8.Expr.Function-    Rel8.Expr.List-    Rel8.Expr.NonEmpty-    Rel8.Expr.Null-    Rel8.Expr.Opaleye-    Rel8.Expr.Ord-    Rel8.Expr.Order-    Rel8.Expr.Read-    Rel8.Expr.Sequence-    Rel8.Expr.Serialize-    Rel8.Expr.Show-    Rel8.Expr.Subscript-    Rel8.Expr.Window--    Rel8.FCF--    Rel8.Kind.Algebra-    Rel8.Kind.Context--    Rel8.Generic.Construction-    Rel8.Generic.Construction.ADT-    Rel8.Generic.Construction.Record-    Rel8.Generic.Map-    Rel8.Generic.Record-    Rel8.Generic.Rel8able-    Rel8.Generic.Table-    Rel8.Generic.Table.ADT-    Rel8.Generic.Table.Record--    Rel8.Order--    Rel8.Query-    Rel8.Query.Aggregate-    Rel8.Query.Distinct-    Rel8.Query.Each-    Rel8.Query.Either-    Rel8.Query.Evaluate-    Rel8.Query.Exists-    Rel8.Query.Filter-    Rel8.Query.Function-    Rel8.Query.Indexed-    Rel8.Query.Limit-    Rel8.Query.List-    Rel8.Query.Loop-    Rel8.Query.Materialize-    Rel8.Query.Maybe-    Rel8.Query.Null-    Rel8.Query.Opaleye-    Rel8.Query.Order-    Rel8.Query.Rebind-    Rel8.Query.Set-    Rel8.Query.SQL-    Rel8.Query.These-    Rel8.Query.Values-    Rel8.Query.Window--    Rel8.Schema.Context.Nullify-    Rel8.Schema.Dict-    Rel8.Schema.Escape-    Rel8.Schema.Field-    Rel8.Schema.HTable-    Rel8.Schema.HTable.Either-    Rel8.Schema.HTable.Identity-    Rel8.Schema.HTable.Label-    Rel8.Schema.HTable.List-    Rel8.Schema.HTable.MapTable-    Rel8.Schema.HTable.Maybe-    Rel8.Schema.HTable.NonEmpty-    Rel8.Schema.HTable.Nullify-    Rel8.Schema.HTable.Product-    Rel8.Schema.HTable.These-    Rel8.Schema.HTable.Vectorize-    Rel8.Schema.Kind-    Rel8.Schema.Name-    Rel8.Schema.Null-    Rel8.Schema.QualifiedName-    Rel8.Schema.Result-    Rel8.Schema.Spec-    Rel8.Schema.Table--    Rel8.Statement-    Rel8.Statement.Delete-    Rel8.Statement.Insert-    Rel8.Statement.OnConflict-    Rel8.Statement.Prepared-    Rel8.Statement.Returning-    Rel8.Statement.Rows-    Rel8.Statement.Run-    Rel8.Statement.Select-    Rel8.Statement.Set-    Rel8.Statement.SQL-    Rel8.Statement.Update-    Rel8.Statement.Using-    Rel8.Statement.View-    Rel8.Statement.Where--    Rel8.Table-    Rel8.Table.ADT-    Rel8.Table.Aggregate-    Rel8.Table.Aggregate.Maybe-    Rel8.Table.Alternative-    Rel8.Table.Bool-    Rel8.Table.Cols-    Rel8.Table.Either-    Rel8.Table.Eq-    Rel8.Table.HKD-    Rel8.Table.List-    Rel8.Table.Maybe-    Rel8.Table.Name-    Rel8.Table.NonEmpty-    Rel8.Table.Null-    Rel8.Table.Nullify-    Rel8.Table.Opaleye-    Rel8.Table.Ord-    Rel8.Table.Order-    Rel8.Table.Projection-    Rel8.Table.Rel8able-    Rel8.Table.Serialize-    Rel8.Table.These-    Rel8.Table.Transpose-    Rel8.Table.Undefined-    Rel8.Table.Window--    Rel8.Type-    Rel8.Type.Array-    Rel8.Type.Builder.ByteString-    Rel8.Type.Builder.Fold-    Rel8.Type.Builder.Time-    Rel8.Type.Composite-    Rel8.Type.Decimal-    Rel8.Type.Decoder-    Rel8.Type.Eq-    Rel8.Type.Encoder-    Rel8.Type.Enum-    Rel8.Type.Information-    Rel8.Type.JSONEncoded-    Rel8.Type.JSONBEncoded-    Rel8.Type.Monoid-    Rel8.Type.Name-    Rel8.Type.Nullable-    Rel8.Type.Num-    Rel8.Type.Ord-    Rel8.Type.Parser-    Rel8.Type.Parser.ByteString-    Rel8.Type.Parser.Time-    Rel8.Type.ReadShow-    Rel8.Type.Semigroup-    Rel8.Type.String-    Rel8.Type.Sum-    Rel8.Type.Tag--    Rel8.Window-+    Rel8.TH  test-suite tests   type:             exitcode-stdio-1.0@@ -258,10 +71,11 @@     , containers     , hasql     , hasql-transaction-    , hedgehog          >= 1.0 && < 1.6+    , hedgehog          >= 1.0 && < 1.8     , mmorph     , iproute     , rel8+    , rel8-internal     , scientific     , tasty     , tasty-hedgehog@@ -275,6 +89,7 @@    other-modules:     Rel8.Generic.Rel8able.Test+    Rel8.TH.Rel8able.Test    main-is:          Main.hs   hs-source-dirs:   tests
src/Rel8.hs view
@@ -360,6 +360,8 @@     -- ** @INSERT@   , Insert(..)   , OnConflict(..)+  , Conflict (..)+  , Index (..)   , Upsert(..)   , insert   , unsafeDefault@@ -396,115 +398,115 @@ import Prelude ()  -- rel8-import Rel8.Aggregate-import Rel8.Aggregate.Fold-import Rel8.Aggregate.Function-import Rel8.Column-import Rel8.Column.ADT-import Rel8.Column.Either-import Rel8.Column.Lift-import Rel8.Column.List-import Rel8.Column.Maybe-import Rel8.Column.NonEmpty-import Rel8.Column.Null-import Rel8.Column.These-import Rel8.Expr-import Rel8.Expr.Aggregate-import Rel8.Expr.Array-import Rel8.Expr.Bool-import Rel8.Expr.Default-import Rel8.Expr.Eq-import Rel8.Expr.Function-import Rel8.Expr.Null-import Rel8.Expr.Opaleye (unsafeCastExpr, unsafeCoerceExpr, unsafeLiteral, unsafePrimExpr)-import Rel8.Expr.Ord-import Rel8.Expr.Order-import Rel8.Expr.Serialize-import Rel8.Expr.Sequence-import Rel8.Expr.Text ( like, ilike )-import Rel8.Expr.Window-import Rel8.Generic.Rel8able ( KRel8able, Rel8able )-import Rel8.Order-import Rel8.Query-import Rel8.Query.Aggregate-import Rel8.Query.Distinct-import Rel8.Query.Each-import Rel8.Query.Either-import Rel8.Query.Evaluate-import Rel8.Query.Exists-import Rel8.Query.Filter-import Rel8.Query.Function-import Rel8.Query.Indexed-import Rel8.Query.Limit-import Rel8.Query.List-import Rel8.Query.Loop-import Rel8.Query.Materialize-import Rel8.Query.Maybe-import Rel8.Query.Null-import Rel8.Query.Order-import Rel8.Query.Rebind-import Rel8.Query.SQL (showQuery)-import Rel8.Query.Set-import Rel8.Query.These-import Rel8.Query.Values-import Rel8.Query.Window-import Rel8.Schema.Field-import Rel8.Schema.HTable-import Rel8.Schema.Name-import Rel8.Schema.Null hiding ( nullable )-import Rel8.Schema.QualifiedName-import Rel8.Schema.Result ( Result )-import Rel8.Schema.Table-import Rel8.Statement-import Rel8.Statement.Delete-import Rel8.Statement.Insert-import Rel8.Statement.OnConflict-import Rel8.Statement.Prepared-import Rel8.Statement.Returning-import Rel8.Statement.Run-import Rel8.Statement.Select-import Rel8.Statement.SQL-import Rel8.Statement.Update-import Rel8.Statement.View-import Rel8.Table-import Rel8.Table.ADT-import Rel8.Table.Aggregate-import Rel8.Table.Aggregate.Maybe-import Rel8.Table.Alternative-import Rel8.Table.Bool-import Rel8.Table.Either-import Rel8.Table.Eq-import Rel8.Table.HKD-import Rel8.Table.List-import Rel8.Table.Maybe-import Rel8.Table.Name-import Rel8.Table.NonEmpty-import Rel8.Table.Null-import Rel8.Table.Opaleye ( castTable )-import Rel8.Table.Ord-import Rel8.Table.Order-import Rel8.Table.Projection-import Rel8.Table.Rel8able ()-import Rel8.Table.Serialize-import Rel8.Table.These-import Rel8.Table.Transpose-import Rel8.Table.Window-import Rel8.Type-import Rel8.Type.Composite-import Rel8.Type.Eq-import Rel8.Type.Enum-import Rel8.Type.Information-import Rel8.Type.JSONBEncoded-import Rel8.Type.JSONEncoded-import Rel8.Type.Monoid-import Rel8.Type.Name-import Rel8.Type.Num-import Rel8.Type.Ord-import Rel8.Type.ReadShow-import Rel8.Type.Semigroup-import Rel8.Type.String-import Rel8.Type.Sum-import Rel8.Window+import Rel8.Internal.Aggregate+import Rel8.Internal.Aggregate.Fold+import Rel8.Internal.Aggregate.Function+import Rel8.Internal.Column+import Rel8.Internal.Column.ADT+import Rel8.Internal.Column.Either+import Rel8.Internal.Column.Lift+import Rel8.Internal.Column.List+import Rel8.Internal.Column.Maybe+import Rel8.Internal.Column.NonEmpty+import Rel8.Internal.Column.Null+import Rel8.Internal.Column.These+import Rel8.Internal.Expr+import Rel8.Internal.Expr.Aggregate+import Rel8.Internal.Expr.Array+import Rel8.Internal.Expr.Bool+import Rel8.Internal.Expr.Default+import Rel8.Internal.Expr.Eq+import Rel8.Internal.Expr.Function+import Rel8.Internal.Expr.Null+import Rel8.Internal.Expr.Opaleye (unsafeCastExpr, unsafeCoerceExpr, unsafeLiteral, unsafePrimExpr)+import Rel8.Internal.Expr.Ord+import Rel8.Internal.Expr.Order+import Rel8.Internal.Expr.Serialize+import Rel8.Internal.Expr.Sequence+import Rel8.Internal.Expr.Text ( like, ilike )+import Rel8.Internal.Expr.Window+import Rel8.Internal.Generic.Rel8able ( KRel8able, Rel8able )+import Rel8.Internal.Order+import Rel8.Internal.Query+import Rel8.Internal.Query.Aggregate+import Rel8.Internal.Query.Distinct+import Rel8.Internal.Query.Each+import Rel8.Internal.Query.Either+import Rel8.Internal.Query.Evaluate+import Rel8.Internal.Query.Exists+import Rel8.Internal.Query.Filter+import Rel8.Internal.Query.Function+import Rel8.Internal.Query.Indexed+import Rel8.Internal.Query.Limit+import Rel8.Internal.Query.List+import Rel8.Internal.Query.Loop+import Rel8.Internal.Query.Materialize+import Rel8.Internal.Query.Maybe+import Rel8.Internal.Query.Null+import Rel8.Internal.Query.Order+import Rel8.Internal.Query.Rebind+import Rel8.Internal.Query.SQL (showQuery)+import Rel8.Internal.Query.Set+import Rel8.Internal.Query.These+import Rel8.Internal.Query.Values+import Rel8.Internal.Query.Window+import Rel8.Internal.Schema.Field+import Rel8.Internal.Schema.HTable+import Rel8.Internal.Schema.Name+import Rel8.Internal.Schema.Null hiding ( nullable )+import Rel8.Internal.Schema.QualifiedName+import Rel8.Internal.Schema.Result ( Result )+import Rel8.Internal.Schema.Table+import Rel8.Internal.Statement+import Rel8.Internal.Statement.Delete+import Rel8.Internal.Statement.Insert+import Rel8.Internal.Statement.OnConflict+import Rel8.Internal.Statement.Prepared+import Rel8.Internal.Statement.Returning+import Rel8.Internal.Statement.Run+import Rel8.Internal.Statement.Select+import Rel8.Internal.Statement.SQL+import Rel8.Internal.Statement.Update+import Rel8.Internal.Statement.View+import Rel8.Internal.Table+import Rel8.Internal.Table.ADT+import Rel8.Internal.Table.Aggregate+import Rel8.Internal.Table.Aggregate.Maybe+import Rel8.Internal.Table.Alternative+import Rel8.Internal.Table.Bool+import Rel8.Internal.Table.Either+import Rel8.Internal.Table.Eq+import Rel8.Internal.Table.HKD+import Rel8.Internal.Table.List+import Rel8.Internal.Table.Maybe+import Rel8.Internal.Table.Name+import Rel8.Internal.Table.NonEmpty+import Rel8.Internal.Table.Null+import Rel8.Internal.Table.Opaleye ( castTable )+import Rel8.Internal.Table.Ord+import Rel8.Internal.Table.Order+import Rel8.Internal.Table.Projection+import Rel8.Internal.Table.Rel8able ()+import Rel8.Internal.Table.Serialize+import Rel8.Internal.Table.These+import Rel8.Internal.Table.Transpose+import Rel8.Internal.Table.Window+import Rel8.Internal.Type+import Rel8.Internal.Type.Composite+import Rel8.Internal.Type.Eq+import Rel8.Internal.Type.Enum+import Rel8.Internal.Type.Information+import Rel8.Internal.Type.JSONBEncoded+import Rel8.Internal.Type.JSONEncoded+import Rel8.Internal.Type.Monoid+import Rel8.Internal.Type.Name+import Rel8.Internal.Type.Num+import Rel8.Internal.Type.Ord+import Rel8.Internal.Type.ReadShow+import Rel8.Internal.Type.Semigroup+import Rel8.Internal.Type.String+import Rel8.Internal.Type.Sum+import Rel8.Internal.Window   -- $running@@ -534,11 +536,11 @@ -- data Thing f = ThingEmployer (Employer f) | ThingPotato (Potato f) | Nullary --     deriving stock Generic ----- data Employer f = Employer { employerId :: f Int32, employerName :: f Text}+-- data Employer f = Employer { employerId :: Column f Int32, employerName :: Column f Text} --   deriving stock Generic --   deriving anyclass Rel8able ----- data Potato f = Potato { size :: f Int32, grower :: f Text }+-- data Potato f = Potato { size :: Column f Int32, grower :: Column f Text } --   deriving stock Generic --   deriving anyclass Rel8able -- @
− src/Rel8/Aggregate.hs
@@ -1,197 +0,0 @@-{-# language DataKinds #-}-{-# language GADTs #-}-{-# language KindSignatures #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Aggregate-  ( Aggregator' (Aggregator)-  , Aggregator-  , Aggregator1-  , toAggregator-  , toAggregator1-  , filterWhereExplicit-  , unsafeMakeAggregator-  )-where---- base-import Control.Applicative (liftA2)-import Data.Kind (Type)-import Prelude---- opaleye-import qualified Opaleye.Aggregate as Opaleye-import qualified Opaleye.Internal.MaybeFields as Opaleye-import qualified Opaleye.Internal.Operators as Opaleye---- product-profunctor-import Data.Profunctor.Product-  ( ProductProfunctor, purePP, (****)-  , SumProfunctor, (+++!)-  )---- profunctors-import Data.Profunctor (Profunctor, dimap)---- rel8-import Rel8.Expr (Expr)-import Rel8.Expr.Opaleye (toPrimExpr, toColumn)-import Rel8.Aggregate.Fold (Fallback (Empty, Fallback), Fold (Full, Semi))---- semigroupoids-import Data.Functor.Apply (Apply, liftF2)----- | 'Aggregator'' is the most general form of \"aggregator\", of which--- 'Aggregator' and 'Aggregator1' are special cases. 'Aggregator''s are--- comprised of aggregation functions and/or @GROUP BY@ clauses.------ Aggregation functions operating on individual 'Rel8.Expr's such as--- 'Rel8.sum' can be combined into 'Aggregator's operating on larger types--- using the 'Applicative', 'Profunctor' and 'ProductProfunctor' interfaces.--- Working with 'Profunctor's can sometimes be awkward so for every 'Rel8.sum'--- we also provide a 'Rel8.sumOn' which bundles an 'Data.Profunctor.lmap'. For--- complex aggregations, we recommend using these functions along with--- @ApplicativeDo@, @BlockArguments@, @OverloadedRecordDot@ and--- @RecordWildCards@:------ @------ data Input f = Input---   { orderId :: Column f OrderId---   , customerId :: Column f CustomerId---   , productId :: Column f ProductId---   , quantity :: Column f Int64---   , price :: Column f Scientific---   }---   deriving (Generic, Rel8able)--------- totalPrice :: Input Expr -> Expr Scientific--- totalPrice input = fromIntegral input.quantity * input.price--------- data Result f = Result---   { customerId :: Column f CustomerId---   , totalOrders :: Column f Int64---   , productsOrdered :: Column f Int64---   , totalPrice :: Column f Scientific---   }---   deriving (Generic, Rel8able)--------- allResults :: Query (Result Expr)--- allResults =---   aggregate---     do---       customerId <- groupByOn (.customerId)---       totalOrders <- countDistinctOn (.orderId)---       productsOrdered <- countDistinctOn (.productId)---       totalPrice <- sumOn totalPrice---       pure Result {..}---     do---       order <- each orderSchema---       orderLine <- each orderLineSchema---       where_ $ order.id ==. orderLine.orderId---       pure---         Input---           { orderId = order.id---           , customerId = order.customerId---           , productId = orderLine.productId---           , quantity = orderLine.quantity---           , price = orderLine.price---           }--- @-type Aggregator' :: Fold -> Type -> Type -> Type-data Aggregator' fold i a = Aggregator !(Fallback fold a) !(Opaleye.Aggregator i a)---instance Profunctor (Aggregator' fold) where-  dimap f g (Aggregator fallback a) =-    Aggregator (fmap g fallback) (dimap f g a)---instance ProductProfunctor (Aggregator' fold) where-  purePP = pure-  (****) = (<*>)---instance SumProfunctor (Aggregator' fold) where-  Aggregator fallback a +++! Aggregator fallback' b =-    flip Aggregator (a +++! b) $ case fallback of-      Empty -> case fallback' of-        Empty -> Empty-        Fallback x -> Fallback (Right x)-      Fallback x -> Fallback (Left x)---instance Functor (Aggregator' fold i) where-  fmap = dimap id---instance Apply (Aggregator' fold i) where-  liftF2 f (Aggregator fallback a) (Aggregator fallback' b) =-    Aggregator (liftF2 f fallback fallback') (liftA2 f a b)---instance Applicative (Aggregator' fold i) where-  pure a = Aggregator (pure a) (pure a)-  liftA2 = liftF2----- | An 'Aggregator' takes a 'Rel8.Query' producing a collection of rows of--- type @a@ and transforms it into a 'Rel8.Query' producing a single row of--- type @b@. If the given 'Rel8.Query' produces an empty collection of rows,--- then the single row in the resulting 'Rel8.Query' contains the identity--- values of the aggregation functions comprising the 'Aggregator' (i.e.,--- @0@ for 'Rel8.sum', 'Rel8.false' for 'Rel8.or', etc.).------ 'Aggregator' is a special form of 'Aggregator'' parameterised by 'Full'.-type Aggregator :: Type -> Type -> Type-type Aggregator = Aggregator' 'Full----- | An 'Aggregator1' takes a collection of rows of type @a@, groups them, and--- transforms each group into a single row of type @b@. This corresponds to--- aggregators using @GROUP BY@ in SQL. If given an empty collection of rows,--- 'Aggregator1' will have no groups and will therefore also return an empty--- collection of rows.------ 'Aggregator1' is a special form of 'Aggregator'' parameterised by 'Semi'.-type Aggregator1 :: Type -> Type -> Type-type Aggregator1 = Aggregator' 'Semi----- | 'toAggregator1' turns an 'Aggregator' into an 'Aggregator1'.-toAggregator1 :: Aggregator' fold i a -> Aggregator1 i a-toAggregator1 (Aggregator _ a) = Aggregator Empty a----- | Given a value to fall back on if given an empty collection of rows,--- 'toAggregator' turns an 'Aggregator1' into an 'Aggregator'.-toAggregator :: a -> Aggregator' fold i a -> Aggregator' fold' i a-toAggregator fallback (Aggregator _ a) = Aggregator (Fallback fallback) a---filterWhereExplicit :: ()-  => Opaleye.IfPP a a-  -> (i -> Expr Bool)-  -> Aggregator i a-  -> Aggregator' fold i a-filterWhereExplicit ifPP f (Aggregator (Fallback fallback) aggregator) =-  Aggregator (Fallback fallback) aggregator'-  where-    aggregator' =-      Opaleye.fromMaybeFieldsExplicit ifPP fallback-        <$> Opaleye.filterWhere (toColumn . toPrimExpr . f) aggregator---unsafeMakeAggregator :: forall (i :: Type) (o :: Type) (fold :: Fold) i' o'.  ()-  => (i -> i')-  -> (o' -> o)-  -> Fallback fold o-  -> Opaleye.Aggregator i' o'-  -> Aggregator' fold i o-unsafeMakeAggregator input output fallback =-  Aggregator fallback . dimap input output
− src/Rel8/Aggregate/Fold.hs
@@ -1,52 +0,0 @@-{-# language DataKinds #-}-{-# language GADTs #-}-{-# language LambdaCase #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Aggregate.Fold-  ( Fallback (Empty, Fallback)-  , Fold (Semi, Full)-  )-where---- base-import Control.Applicative (liftA2)-import Data.Kind (Type)-import Prelude---- semigroupoids-import Data.Functor.Apply (Apply, liftF2)----- | 'Fold' is a kind that parameterises aggregations. Aggregations--- parameterised by 'Semi' are analogous to 'Data.Semigroup.Foldable.foldMap1'--- (i.e, they can only produce results on a non-empty 'Rel8.Query') whereas--- aggregations parameterised by 'Full' are analagous to 'foldMap' (given a--- non-empty) query, they return the identity values of the aggregation--- functions.-type Fold :: Type-data Fold = Semi | Full---type Fallback :: Fold -> Type -> Type-data Fallback fold a where-  Fallback :: !a -> Fallback fold a-  Empty :: Fallback 'Semi a---instance Functor (Fallback fold) where-  fmap f = \case-    Fallback a -> Fallback (f a)-    Empty -> Empty---instance Apply (Fallback fold) where-  liftF2 f (Fallback a) (Fallback b) = Fallback (f a b)-  liftF2 _ (Fallback _) Empty = Empty-  liftF2 _ Empty (Fallback _) = Empty-  liftF2 _ Empty Empty = Empty---instance Applicative (Fallback fold) where-  pure = Fallback-  liftA2 = liftF2
− src/Rel8/Aggregate/Function.hs
@@ -1,45 +0,0 @@-{-# language FlexibleContexts #-}-{-# language MonoLocalBinds #-}--module Rel8.Aggregate.Function (-  aggregateFunction,-  rawAggregateFunction,-) where---- base-import Prelude---- opaleye-import qualified Opaleye.Internal.Aggregate as Opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Aggregate (Aggregator1, unsafeMakeAggregator)-import Rel8.Aggregate.Fold (Fallback (Empty))-import Rel8.Expr (Expr)-import Rel8.Expr.Opaleye (castExpr, fromColumn, fromPrimExpr)-import Rel8.Schema.Null (Sql)-import Rel8.Schema.QualifiedName (QualifiedName, showQualifiedName)-import Rel8.Table (Table)-import Rel8.Table.Opaleye (unpackspec)-import Rel8.Type (DBType)----- | 'aggregateFunction' allows the use use of custom aggregation functions--- or PostgreSQL aggregation functions which are not otherwise supported by--- Rel8.-aggregateFunction ::-  (Table Expr i, Sql DBType a) =>-  QualifiedName ->-  Aggregator1 i (Expr a)-aggregateFunction name = castExpr <$> rawAggregateFunction name---rawAggregateFunction :: Table Expr i => QualifiedName -> Aggregator1 i (Expr a)-rawAggregateFunction name =-  unsafeMakeAggregator-    id-    (fromPrimExpr . fromColumn)-    Empty-    (Opaleye.makeAggrExplicit unpackspec-      (Opaleye.AggrOther (showQualifiedName name)))
src/Rel8/Array.hs view
@@ -1,6 +1,8 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MonoLocalBinds #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}  module Rel8.Array   (@@ -10,7 +12,7 @@   , index, indexExpr   , last, lastExpr   , length, lengthExpr-  , elem+  , elem, notElem      -- ** @NonEmptyTable@   , NonEmptyTable@@ -18,7 +20,7 @@   , index1, index1Expr   , last1, last1Expr   , length1, length1Expr-  , elem1+  , elem1, notElem1      -- ** Unsafe   , unsafeSubscript@@ -27,34 +29,74 @@ where  -- base+import Data.Int (Int32) import Data.List.NonEmpty (NonEmpty)-import Prelude hiding (elem, head, last, length)+import Prelude hiding (elem, head, last, length, notElem) +-- opaleye+import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye+ -- rel8-import Rel8.Expr (Expr)-import Rel8.Expr.Array (listOf, nonEmptyOf)-import Rel8.Expr.Function (rawBinaryOperator)-import Rel8.Expr.List-import Rel8.Expr.NonEmpty-import Rel8.Expr.Subscript-import Rel8.Schema.Null (Sql)-import Rel8.Table.List-import Rel8.Table.NonEmpty-import Rel8.Type.Eq (DBEq)+import Rel8.Internal.Expr (Expr)+import Rel8.Internal.Expr.Bool (not_)+import Rel8.Internal.Expr.Function (rawFunction)+import Rel8.Internal.Expr.List+import Rel8.Internal.Expr.NonEmpty+import Rel8.Internal.Expr.Null (isNonNull, isNull)+import Rel8.Internal.Expr.Opaleye (fromPrimExpr, toPrimExpr)+import Rel8.Internal.Expr.Subscript+import Rel8.Internal.Schema.Null (Nullity (NotNull, Null), Sql, nullable)+import Rel8.Internal.Table.List+import Rel8.Internal.Table.NonEmpty+import Rel8.Internal.Type (DBType)+import Rel8.Internal.Type.Eq (DBEq)   -- | @'elem' a as@ tests whether @a@ is an element of the list @as@. elem :: Sql DBEq a => Expr a -> Expr [a] -> Expr Bool-elem = (<@) . listOf . pure-  where-    (<@) = rawBinaryOperator "<@"+elem = memberOf infix 4 `elem`   -- | @'elem1' a as@ tests whether @a@ is an element of the non-empty list -- @as@. elem1 :: Sql DBEq a => Expr a -> Expr (NonEmpty a) -> Expr Bool-elem1 = (<@) . nonEmptyOf . pure-  where-    (<@) = rawBinaryOperator "<@"+elem1 = memberOf infix 4 `elem1`+++-- | @'notElem' a as@ tests whether @a@ is not an element of the list @as@.+notElem :: Sql DBEq a => Expr a -> Expr [a] -> Expr Bool+notElem = notMemberOf+infix 4 `notElem`+++-- | @'notElem1' a as@ tests whether @a@ is not an element of the non-empty+-- list @as@.+notElem1 :: Sql DBEq a => Expr a -> Expr (NonEmpty a) -> Expr Bool+notElem1 = notMemberOf+infix 4 `notElem1`+++memberOf :: forall a t. (Sql DBEq a, DBType (t a))+  => Expr a -> Expr (t a) -> Expr Bool+memberOf = case nullable @a of+  Null -> \ma mas -> isNonNull (position mas ma)+  NotNull -> eqAny+++notMemberOf :: forall a t. (Sql DBEq a, DBType (t a))+  => Expr a -> Expr (t a) -> Expr Bool+notMemberOf = case nullable @a of+  Null -> \ma mas -> isNull (position mas ma)+  NotNull -> \a as -> not_ (eqAny a as)+++position :: (DBType (t (Maybe a)), DBType a)+  => Expr (t (Maybe a)) -> Expr (Maybe a) -> Expr (Maybe Int32)+position as a = rawFunction "array_position" (as, a)+++eqAny :: Expr a -> Expr as -> Expr Bool+eqAny a as =+  fromPrimExpr (Opaleye.AnyExpr (Opaleye.:==) (toPrimExpr a) (toPrimExpr as))
− src/Rel8/Column.hs
@@ -1,31 +0,0 @@-{-# language DataKinds #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}--module Rel8.Column-  ( Column-  , TColumn-  )-where---- base-import Data.Kind ( Type )-import Prelude ()---- rel8-import Rel8.FCF ( Eval, Exp )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Result ( Result )----- | This type family is used to specify columns in 'Rel8able's. In @Column f--- a@, @f@ is the context of the column (which should be left polymorphic in--- 'Rel8able' definitions), and @a@ is the type of the column.-type Column :: K.Context -> Type -> Type-type family Column context a where-  Column Result  a = a-  Column context a = context a---data TColumn :: K.Context -> Type -> Exp Type-type instance Eval (TColumn f a) = Column f a
− src/Rel8/Column/ADT.hs
@@ -1,23 +0,0 @@-{-# language DataKinds #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}--module Rel8.Column.ADT-  ( HADT-  )-where---- base-import Data.Kind ( Type )-import Prelude ()---- rel8-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Result ( Result )-import Rel8.Table.ADT ( ADT )---type HADT :: K.Context -> K.Rel8able -> Type-type family HADT context t where-  HADT Result t = t Result-  HADT context t = ADT t context
− src/Rel8/Column/Either.hs
@@ -1,26 +0,0 @@-{-# language DataKinds #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilyDependencies #-}--module Rel8.Column.Either-  ( HEither-  )-where---- base-import Data.Kind ( Type )-import Prelude---- rel8-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Result ( Result )-import Rel8.Table.Either ( EitherTable )----- | Nest an 'Either' value within a 'Rel8able'. @HEither f a b@ will produce a--- 'EitherTable' @a b@ in the 'Expr' context, and a 'Either' @a b@ in the--- 'Result' context.-type HEither :: K.Context -> Type -> Type -> Type-type family HEither context = either | either -> context where-  HEither Result = Either-  HEither context = EitherTable context
− src/Rel8/Column/Lift.hs
@@ -1,23 +0,0 @@-{-# language DataKinds #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}--module Rel8.Column.Lift-  ( Lift-  )-where---- base-import Data.Kind ( Type )-import Prelude ()---- rel8-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Result ( Result )-import Rel8.Table.HKD ( HKD )---type Lift :: K.Context -> Type -> Type-type family Lift context a where-  Lift Result a = a-  Lift context a = HKD a context
− src/Rel8/Column/List.hs
@@ -1,25 +0,0 @@-{-# language DataKinds #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilyDependencies #-}--module Rel8.Column.List-  ( HList-  )-where---- base-import Data.Kind ( Type )-import Prelude ()---- rel8-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Result ( Result )-import Rel8.Table.List ( ListTable )----- | Nest a list within a 'Rel8able'. @HList f a@ will produce a 'ListTable'--- @a@ in the 'Expr' context, and a @[a]@ in the 'Result' context.-type HList :: K.Context -> Type -> Type-type family HList context = list | list -> context where-  HList Result = []-  HList context = ListTable context
− src/Rel8/Column/Maybe.hs
@@ -1,26 +0,0 @@-{-# language DataKinds #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilyDependencies #-}--module Rel8.Column.Maybe-  ( HMaybe-  )-where---- base-import Data.Kind ( Type )-import Prelude---- rel8-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Result ( Result )-import Rel8.Table.Maybe ( MaybeTable )----- | Nest a 'Maybe' value within a 'Rel8able'. @HMaybe f a@ will produce a--- 'MaybeTable' @a@ in the 'Expr' context, and a 'Maybe' @a@ in the 'Result'--- context.-type HMaybe :: K.Context -> Type -> Type-type family HMaybe context = maybe | maybe -> context where-  HMaybe Result = Maybe-  HMaybe context = MaybeTable context
− src/Rel8/Column/NonEmpty.hs
@@ -1,27 +0,0 @@-{-# language DataKinds #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilyDependencies #-}--module Rel8.Column.NonEmpty-  ( HNonEmpty-  )-where---- base-import Data.Kind ( Type )-import Data.List.NonEmpty ( NonEmpty )-import Prelude ()---- rel8-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Result ( Result )-import Rel8.Table.NonEmpty ( NonEmptyTable )----- | Nest a 'NonEmpty' list within a 'Rel8able'. @HNonEmpty f a@ will produce a--- 'NonEmptyTable' @a@ in the 'Expr' context, and a 'NonEmpty' @a@ in the--- 'Result' context.-type HNonEmpty :: K.Context -> Type -> Type-type family HNonEmpty context = nonEmpty | nonEmpty -> context where-  HNonEmpty Result = NonEmpty-  HNonEmpty context = NonEmptyTable context
− src/Rel8/Column/Null.hs
@@ -1,26 +0,0 @@-{-# language DataKinds #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilyDependencies #-}--module Rel8.Column.Null-  ( HNull-  )-where---- base-import Data.Kind ( Type )-import Prelude---- rel8-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Result ( Result )-import Rel8.Table.Null ( NullTable )----- | Nest a 'Null' value within a 'Rel8able'. @HNull f a@ will produce a--- 'NullTable' @a@ in the 'Expr' context, and a @'Maybe' a@ in the 'Result'--- context.-type HNull :: K.Context -> Type -> Type-type family HNull context = maybe | maybe -> context where-  HNull Result = Maybe-  HNull context = NullTable context
− src/Rel8/Column/These.hs
@@ -1,29 +0,0 @@-{-# language DataKinds #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilyDependencies #-}--module Rel8.Column.These-  ( HThese-  )-where---- base-import Data.Kind ( Type )-import Prelude ()---- rel8-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Result ( Result )-import Rel8.Table.These ( TheseTable )---- these-import Data.These ( These )----- | Nest an 'These' value within a 'Rel8able'. @HThese f a b@ will produce a--- 'TheseTable' @a b@ in the 'Expr' context, and a 'These' @a b@ in the--- 'Result' context.-type HThese :: K.Context -> Type -> Type -> Type-type family HThese context = these | these -> context where-  HThese Result = These-  HThese context = TheseTable context
src/Rel8/Decoder.hs view
@@ -3,4 +3,4 @@   Parser,   parseDecoder, ) where-import Rel8.Type.Decoder+import Rel8.Internal.Type.Decoder
src/Rel8/Encoder.hs view
@@ -1,4 +1,4 @@ module Rel8.Encoder (   Encoder (..), ) where-import Rel8.Type.Encoder+import Rel8.Internal.Type.Encoder
− src/Rel8/Expr.hs
@@ -1,137 +0,0 @@-{-# language DataKinds #-}-{-# language DerivingStrategies #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language OverloadedStrings #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language UndecidableInstances #-}--module Rel8.Expr-  ( Expr(..)-  )-where---- base-import Data.Functor.Identity ( Identity( Identity ) )-import Data.Ratio (denominator, numerator)-import Data.String ( IsString, fromString )-import Prelude hiding ( null )---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Expr.Function (function)-import Rel8.Expr.Null ( liftOpNull, nullify )-import Rel8.Expr.Opaleye-  ( castExpr-  , fromPrimExpr-  , mapPrimExpr-  , zipPrimExprsWith-  )-import Rel8.Expr.Serialize ( litExpr )-import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Null ( Nullity( Null, NotNull ), Sql, nullable )-import Rel8.Table-  ( Table, Columns, Context, fromColumns, toColumns-  , FromExprs, fromResult, toResult-  , Transpose-  )-import Rel8.Type ( DBType )-import Rel8.Type.Monoid ( DBMonoid, memptyExpr )-import Rel8.Type.Num ( DBFloating, DBFractional, DBNum )-import Rel8.Type.Semigroup ( DBSemigroup, (<>.) )---- scientific-import Data.Scientific (fromRationalRepetendLimited)----- | Typed SQL expressions.-type Expr :: K.Context-newtype Expr a = Expr Opaleye.PrimExpr-  deriving stock Show---instance Sql DBSemigroup a => Semigroup (Expr a) where-  (<>) = case nullable @a of-    Null -> liftOpNull (<>.)-    NotNull -> (<>.)-  {-# INLINABLE (<>) #-}---instance Sql DBMonoid a => Monoid (Expr a) where-  mempty = case nullable @a of-    Null -> nullify memptyExpr-    NotNull -> memptyExpr-  {-# INLINABLE mempty #-}---instance (Sql IsString a, Sql DBType a) => IsString (Expr a) where-  fromString = litExpr . case nullable @a of-    Null -> Just . fromString-    NotNull -> fromString---instance Sql DBNum a => Num (Expr a) where-  (+) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:+))-  (*) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:*))-  (-) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:-))--  abs = mapPrimExpr (Opaleye.UnExpr Opaleye.OpAbs)-  negate = mapPrimExpr (Opaleye.UnExpr Opaleye.OpNegate)--  signum = castExpr . mapPrimExpr (Opaleye.UnExpr (Opaleye.UnOpOther "SIGN"))--  fromInteger = castExpr . fromPrimExpr . Opaleye.ConstExpr . Opaleye.IntegerLit---instance Sql DBFractional a => Fractional (Expr a) where-  (/) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:/))--  fromRational = castExpr . Expr . toScientific-    where-      toScientific r = case fromRationalRepetendLimited 20 r of-        Right (s, Nothing) -> Opaleye.ConstExpr (Opaleye.NumericLit s)-        _ -> Opaleye.BinExpr (Opaleye.:/) (int n) (int d)-          where-            int = Opaleye.ConstExpr . Opaleye.NumericLit . fromInteger-            n = numerator r-            d = denominator r---instance Sql DBFloating a => Floating (Expr a) where-  pi = function "pi" ()-  exp = function "exp"-  log = function "ln"-  sqrt = function "sqrt"-  (**) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:^))-  logBase a b = function "log" (a, b)-  sin = function "sin"-  cos = function "cos"-  tan = function "tan"-  asin = function "asin"-  acos = function "acos"-  atan = function "atan"-  sinh = function "sinh"-  cosh = function "cosh"-  tanh = function "tanh"-  asinh = function "asinh"-  acosh = function "acosh"-  atanh = function "atanh"---instance Sql DBType a => Table Expr (Expr a) where-  type Columns (Expr a) = HIdentity a-  type Context (Expr a) = Expr-  type FromExprs (Expr a) = a-  type Transpose to (Expr a) = to a--  toColumns a = HIdentity a-  fromColumns (HIdentity a) = a-  toResult a = HIdentity (Identity a)-  fromResult (HIdentity (Identity a)) = a
− src/Rel8/Expr.hs-boot
@@ -1,20 +0,0 @@-{-# language DataKinds #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Expr-  ( Expr(..)-  )-where---- base-import Prelude ()---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Schema.Kind ( Context )---type Expr :: Context-newtype Expr a = Expr Opaleye.PrimExpr
− src/Rel8/Expr/Aggregate.hs
@@ -1,495 +0,0 @@-{-# language DataKinds #-}-{-# language DisambiguateRecordFields #-}-{-# language FlexibleContexts #-}-{-# language NamedFieldPuns #-}-{-# language OverloadedStrings #-}-{-# language ScopedTypeVariables #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}--{-# options_ghc -fno-warn-redundant-constraints #-}--module Rel8.Expr.Aggregate-  ( count, countOn, countStar-  , countDistinct, countDistinctOn-  , countWhere, countWhereOn-  , and, andOn, or, orOn-  , min, minOn, max, maxOn-  , sum, sumOn, sumWhere-  , avg, avgOn-  , stringAgg, stringAggOn-  , mode, modeOn-  , percentile, percentileOn-  , percentileContinuous, percentileContinuousOn-  , hypotheticalRank-  , hypotheticalDenseRank-  , hypotheticalPercentRank-  , hypotheticalCumeDist-  , groupByExpr, groupByExprOn-  , distinctAggregate-  , filterWhereExplicit-  , listAggExpr, listAggExprOn, nonEmptyAggExpr, nonEmptyAggExprOn-  , listCatExpr, listCatExprOn, nonEmptyCatExpr, nonEmptyCatExprOn-  , slistAggExpr, snonEmptyAggExpr-  , slistCatExpr, snonEmptyCatExpr-  )-where---- base-import Data.Functor.Contravariant ((>$<))-import Data.Int ( Int64 )-import Data.List.NonEmpty ( NonEmpty )-import Data.String (IsString)-import Prelude hiding (and, max, min, null, or, show, sum)---- opaleye-import qualified Opaleye.Aggregate as Opaleye-import qualified Opaleye.Internal.Aggregate as Opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye-import qualified Opaleye.Internal.Operators as Opaleye---- profunctors-import Data.Profunctor (dimap, lmap)---- rel8-import Rel8.Aggregate-  ( Aggregator' (Aggregator)-  , Aggregator1-  , filterWhereExplicit-  , unsafeMakeAggregator-  )-import Rel8.Aggregate.Fold (Fallback (Empty, Fallback))-import Rel8.Expr ( Expr )-import Rel8.Expr.Array (sempty)-import Rel8.Expr.Bool (false, true)-import Rel8.Expr.Eq ((/=.))-import Rel8.Expr.Opaleye-  ( castExpr-  , fromColumn-  , fromPrimExpr-  , toColumn-  , toPrimExpr-  , unsafeCastExpr-  )-import Rel8.Expr.Order (asc)-import Rel8.Expr.Read (sread)-import Rel8.Expr.Show (show)-import qualified Rel8.Expr.Text as Text-import Rel8.Order (Order (Order))-import Rel8.Schema.Null ( Sql, Unnullify )-import Rel8.Table.Opaleye (fromOrder, unpackspec)-import Rel8.Table.Order (ascTable)-import Rel8.Type ( DBType, typeInformation )-import Rel8.Type.Array (arrayTypeName, quoteArrayElement)-import Rel8.Type.Eq ( DBEq )-import Rel8.Type.Information (TypeInformation)-import Rel8.Type.Num (DBFractional, DBNum)-import Rel8.Type.Ord (DBMax, DBMin, DBOrd)-import Rel8.Type.String ( DBString )-import Rel8.Type.Sum ( DBSum )----- | Count the occurances of a single column. Corresponds to @COUNT(a)@-count :: Aggregator' fold (Expr a) (Expr Int64)-count =-  unsafeMakeAggregator-    (toColumn . toPrimExpr)-    (fromPrimExpr . fromColumn)-    (Fallback 0)-    Opaleye.count----- | Applies 'count' to the column selected by the given function.-countOn :: (i -> Expr a) -> Aggregator' fold i (Expr Int64)-countOn f = lmap f count----- | Count the number of distinct occurrences of a single column. Corresponds to--- @COUNT(DISTINCT a)@-countDistinct :: Sql DBEq a-  => Aggregator' fold (Expr a) (Expr Int64)-countDistinct = distinctAggregate count----- | Applies 'countDistinct' to the column selected by the given function.-countDistinctOn :: Sql DBEq a-  => (i -> Expr a) -> Aggregator' fold i (Expr Int64)-countDistinctOn f = lmap f countDistinct----- | Corresponds to @COUNT(*)@.-countStar :: Aggregator' fold i (Expr Int64)-countStar = lmap (const true) count----- | A count of the number of times a given expression is @true@.-countWhere :: Aggregator' fold (Expr Bool) (Expr Int64)-countWhere = filterWhereExplicit ifPP id countStar----- | Applies 'countWhere' to the column selected by the given function.-countWhereOn :: (i -> Expr Bool) -> Aggregator' fold i (Expr Int64)-countWhereOn f = lmap f countWhere----- | Corresponds to @bool_and@.-and :: Aggregator' fold (Expr Bool) (Expr Bool)-and =-  unsafeMakeAggregator-    (toColumn . toPrimExpr)-    (fromPrimExpr . fromColumn)-    (Fallback true)-    Opaleye.boolAnd----- | Applies 'and' to the column selected by the given function.-andOn :: (i -> Expr Bool) -> Aggregator' fold i (Expr Bool)-andOn f = lmap f and----- | Corresponds to @bool_or@.-or :: Aggregator' fold (Expr Bool) (Expr Bool)-or =-  unsafeMakeAggregator-    (toColumn . toPrimExpr)-    (fromPrimExpr . fromColumn)-    (Fallback false)-    Opaleye.boolOr----- | Applies 'or' to the column selected by the given function.-orOn :: (i -> Expr Bool) -> Aggregator' fold i (Expr Bool)-orOn f = lmap f or----- | Produce an aggregation for @Expr a@ using the @max@ function.-max :: Sql DBMax a => Aggregator1 (Expr a) (Expr a)-max =-  unsafeMakeAggregator-    (toColumn . toPrimExpr)-    (fromPrimExpr . fromColumn)-    Empty-    Opaleye.unsafeMax----- | Applies 'max' to the column selected by the given function.-maxOn :: Sql DBMax a => (i -> Expr a) -> Aggregator1 i (Expr a)-maxOn f = lmap f max----- | Produce an aggregation for @Expr a@ using the @min@ function.-min :: Sql DBMin a => Aggregator1 (Expr a) (Expr a)-min =-  unsafeMakeAggregator-    (toColumn . toPrimExpr)-    (fromPrimExpr . fromColumn)-    Empty-    Opaleye.unsafeMin----- | Applies 'min' to the column selected by the given function.-minOn :: Sql DBMin a => (i -> Expr a) -> Aggregator1 i (Expr a)-minOn f = lmap f min----- | Corresponds to @sum@. Note that in SQL, @sum@ is type changing - for--- example the @sum@ of @integer@ returns a @bigint@. Rel8 doesn't support--- this, and will add explicit casts back to the original input type. This can--- lead to overflows, and if you anticipate very large sums, you should upcast--- your input.-sum :: (Sql DBNum a, Sql DBSum a) => Aggregator' fold (Expr a) (Expr a)-sum =-  unsafeMakeAggregator-    (toColumn . toPrimExpr)-    (fromPrimExpr . fromColumn)-    (Fallback 0)-    Opaleye.unsafeSum----- | Applies 'sum' to the column selected by the given fucntion.-sumOn :: (Sql DBNum a, Sql DBSum a)-  => (i -> Expr a) -> Aggregator' fold i (Expr a)-sumOn f = lmap f sum----- | 'sumWhere' is a combination of 'Rel8.filterWhere' and 'sumOn'.-sumWhere :: (Sql DBNum a, Sql DBSum a)-  => (i -> Expr Bool) -> (i -> Expr a) -> Aggregator' fold i (Expr a)-sumWhere condition = filterWhereExplicit ifPP condition . sumOn----- | Corresponds to @avg@. Note that in SQL, @avg@ is type changing - for--- example, the @avg@ of @integer@ returns a @numeric@. Rel8 doesn't support--- this, and will add explicit casts back to the original input type. If you--- need a fractional result on an integral column, you should cast your input--- to 'Double' or 'Data.Scientific.Scientific' before calling 'avg'.-avg :: Sql DBSum a => Aggregator1 (Expr a) (Expr a)-avg =-  unsafeMakeAggregator-    (toColumn . toPrimExpr)-    (fromPrimExpr . fromColumn)-    Empty-    Opaleye.unsafeAvg----- | Applies 'avg' to the column selected by the given fucntion.-avgOn :: Sql DBSum a => (i -> Expr a) -> Aggregator1 i (Expr a)-avgOn f = lmap f avg----- | Corresponds to @string_agg()@.-stringAgg :: (Sql IsString a, Sql DBString a)-  => Expr a -> Aggregator' fold (Expr a) (Expr a)-stringAgg delimiter =-  unsafeMakeAggregator-    (toColumn . toPrimExpr)-    (castExpr . fromPrimExpr . fromColumn)-    (Fallback "")-    (Opaleye.stringAgg (toColumn (toPrimExpr delimiter)))----- | Applies 'stringAgg' to the column selected by the given function.-stringAggOn :: (Sql IsString a, Sql DBString a)-  => Expr a -> (i -> Expr a) -> Aggregator' fold i (Expr a)-stringAggOn delimiter f = lmap f (stringAgg delimiter)----- | Corresponds to @mode() WITHIN GROUP (ORDER BY _)@.-mode :: Sql DBOrd a => Aggregator1 (Expr a) (Expr a)-mode =-  unsafeMakeAggregator-    id-    (fromPrimExpr . fromColumn)-    Empty-    (Opaleye.withinGroup ((\(Order o) -> o) ascTable)-      (Opaleye.makeAggrExplicit (pure ()) (Opaleye.AggrOther "mode")))----- | Applies 'mode' to the column selected by the given function.-modeOn :: Sql DBOrd a => (i -> Expr a) -> Aggregator1 i (Expr a)-modeOn f = lmap f mode----- | Corresponds to @percentile_disc(_) WITHIN GROUP (ORDER BY _)@.-percentile :: Sql DBOrd a => Expr Double -> Aggregator1 (Expr a) (Expr a)-percentile fraction = -  unsafeMakeAggregator-    (\a -> (fraction, a))-    (castExpr . fromPrimExpr . fromColumn)-    Empty-    (Opaleye.withinGroup ((\(Order o) -> o) (snd >$< ascTable))-      (Opaleye.makeAggrExplicit-        (lmap fst unpackspec)-        (Opaleye.AggrOther "percentile_disc")))----- | Applies 'percentile' to the column selected by the given function.-percentileOn ::-  Sql DBOrd a =>-  Expr Double ->-  (i -> Expr a) ->-  Aggregator1 i (Expr a)-percentileOn fraction f = lmap f (percentile fraction)----- | Corresponds to @percentile_cont(_) WITHIN GROUP (ORDER BY _)@.-percentileContinuous ::-  Sql DBFractional a =>-  Expr Double ->-  Aggregator1 (Expr a) (Expr a)-percentileContinuous fraction = -  unsafeMakeAggregator-    (\a -> (fraction, a))-    (castExpr . fromPrimExpr . fromColumn)-    Empty-    (Opaleye.withinGroup ((\(Order o) -> o) (unsafeCastExpr @Double . snd >$< asc))-      (Opaleye.makeAggrExplicit-        (lmap fst unpackspec)-        (Opaleye.AggrOther "percentile_disc")))------ | Applies 'percentileContinuous' to the column selected by the given--- function.-percentileContinuousOn ::-  Sql DBFractional a =>-  Expr Double ->-  (i -> Expr a) ->-  Aggregator1 i (Expr a)-percentileContinuousOn fraction f = lmap f (percentileContinuous fraction)----- | Corresponds to @rank(_) WITHIN GROUP (ORDER BY _)@.-hypotheticalRank ::-  Order a ->-  a ->-  Aggregator' fold a (Expr Int64)-hypotheticalRank (Order order) args = -  unsafeMakeAggregator-    (\a -> (args, a))-    (castExpr . fromPrimExpr . fromColumn)-    (Fallback 1)-    (Opaleye.withinGroup (snd >$< order)-      (Opaleye.makeAggrExplicit-        (fromOrder (fst >$< order))-        (Opaleye.AggrOther "rank")))----- | Corresponds to @dense_rank(_) WITHIN GROUP (ORDER BY _)@.-hypotheticalDenseRank ::-  Order a ->-  a ->-  Aggregator' fold a (Expr Int64)-hypotheticalDenseRank (Order order) args = -  unsafeMakeAggregator-    (const args)-    (castExpr . fromPrimExpr . fromColumn)-    (Fallback 1)-    (Opaleye.withinGroup order-      (Opaleye.makeAggrExplicit (fromOrder order)-        (Opaleye.AggrOther "dense_rank")))----- | Corresponds to @percent_rank(_) WITHIN GROUP (ORDER BY _)@.-hypotheticalPercentRank ::-  Order a ->-  a ->-  Aggregator' fold a (Expr Double)-hypotheticalPercentRank (Order order) args = -  unsafeMakeAggregator-    (const args)-    (castExpr . fromPrimExpr . fromColumn)-    (Fallback 0)-    (Opaleye.withinGroup order-      (Opaleye.makeAggrExplicit (fromOrder order)-        (Opaleye.AggrOther "percent_rank")))----- | Corresponds to @cume_dist(_) WITHIN GROUP (ORDER BY _)@.-hypotheticalCumeDist ::-  Order a ->-  a ->-  Aggregator' fold a (Expr Double)-hypotheticalCumeDist (Order order) args = -  unsafeMakeAggregator-    (const args)-    (castExpr . fromPrimExpr . fromColumn)-    (Fallback 1)-    (Opaleye.withinGroup order-      (Opaleye.makeAggrExplicit (fromOrder order)-        (Opaleye.AggrOther "cume_dist")))----- | Aggregate a value by grouping by it.-groupByExpr :: Sql DBEq a => Aggregator1 (Expr a) (Expr a)-groupByExpr =-  unsafeMakeAggregator-    (toColumn . toPrimExpr)-    (fromPrimExpr . fromColumn)-    Empty-    Opaleye.groupBy----- | Applies 'groupByExpr' to the column selected by the given function.-groupByExprOn :: Sql DBEq a => (i -> Expr a) -> Aggregator1 i (Expr a)-groupByExprOn f = lmap f groupByExpr----- | Collect expressions values as a list.-listAggExpr :: Sql DBType a => Aggregator' fold (Expr a) (Expr [a])-listAggExpr = slistAggExpr typeInformation----- | Applies 'listAggExpr' to the column selected by the given function.-listAggExprOn :: Sql DBType a => (i -> Expr a) -> Aggregator' fold i (Expr [a])-listAggExprOn f = lmap f listAggExpr----- | Collect expressions values as a non-empty list.-nonEmptyAggExpr :: Sql DBType a => Aggregator1 (Expr a) (Expr (NonEmpty a))-nonEmptyAggExpr = snonEmptyAggExpr typeInformation----- | Applies 'nonEmptyAggExpr' to the column selected by the given function.-nonEmptyAggExprOn :: Sql DBType a-  => (i -> Expr a) -> Aggregator1 i (Expr (NonEmpty a))-nonEmptyAggExprOn f = lmap f nonEmptyAggExpr----- | Concatenate lists into a single list.-listCatExpr :: Sql DBType a => Aggregator' fold (Expr [a]) (Expr [a])-listCatExpr = slistCatExpr typeInformation----- | Applies 'listCatExpr' to the column selected by the given function.-listCatExprOn :: Sql DBType a-  => (i -> Expr [a]) -> Aggregator' fold i (Expr [a])-listCatExprOn f = lmap f listCatExpr----- | Concatenate non-empty lists into a single non-empty list.-nonEmptyCatExpr :: Sql DBType a-  => Aggregator1 (Expr (NonEmpty a)) (Expr (NonEmpty a))-nonEmptyCatExpr = snonEmptyCatExpr typeInformation----- | Applies 'nonEmptyCatExpr' to the column selected by the given function.-nonEmptyCatExprOn :: Sql DBType a-  => (i -> Expr (NonEmpty a)) -> Aggregator1 i (Expr (NonEmpty a))-nonEmptyCatExprOn f = lmap f nonEmptyCatExpr----- | 'distinctAggregate' modifies an 'Aggregator' to consider only distinct--- values of each particular column. Note that this "distinction" only happens--- within each column individually, not across all columns simultaneously.-distinctAggregate :: Aggregator' fold i a -> Aggregator' fold i a-distinctAggregate (Aggregator fallback a) =-  Aggregator fallback (Opaleye.distinctAggregator a)---slistAggExpr :: ()-  => TypeInformation (Unnullify a) -> Aggregator' fold (Expr a) (Expr [a])-slistAggExpr info =-  unsafeMakeAggregator-    (toColumn . quoteArrayElement info . toPrimExpr)-    (fromPrimExpr . fromColumn)-    (Fallback (sempty info))-    Opaleye.arrayAgg---snonEmptyAggExpr :: ()-  => TypeInformation (Unnullify a) -> Aggregator1 (Expr a) (Expr (NonEmpty a))-snonEmptyAggExpr info =-  unsafeMakeAggregator-    (toColumn . quoteArrayElement info . toPrimExpr)-    (fromPrimExpr . fromColumn)-    Empty-    Opaleye.arrayAgg---slistCatExpr :: ()-  => TypeInformation (Unnullify a) -> Aggregator' fold (Expr [a]) (Expr [a])-slistCatExpr info = dimap (unbracket . show) (sread name . bracket) agg-  where-    bracket a = "{" <> a <> "}"-    unbracket a = Text.substr a 2 (Just (Text.length a - 2))-    agg = filterWhereExplicit ifPP (/=. "") (stringAgg ",")-    name = arrayTypeName info---snonEmptyCatExpr :: ()-  => TypeInformation (Unnullify a)-  -> Aggregator1 (Expr (NonEmpty a)) (Expr (NonEmpty a))-snonEmptyCatExpr info = dimap (unbracket . show) (sread name . bracket) agg-  where-    bracket a = "{" <> a <> "}"-    unbracket a = Text.substr a 2 (Just (Text.length a - 2))-    agg = filterWhereExplicit ifPP (/=. "") (stringAgg ",")-    name = arrayTypeName info---ifPP :: Opaleye.IfPP (Expr a) (Expr a)-ifPP = dimap from to Opaleye.ifPPField-  where-    from = toColumn . toPrimExpr-    to = fromPrimExpr . fromColumn
− src/Rel8/Expr/Array.hs
@@ -1,55 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language TypeFamilies #-}--{-# options_ghc -fno-warn-redundant-constraints #-}--module Rel8.Expr.Array-  ( listOf, nonEmptyOf-  , slistOf, snonEmptyOf-  , sappend, sappend1, sempty-  )-where---- base-import Data.List.NonEmpty (NonEmpty)-import Prelude---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import {-# SOURCE #-} Rel8.Expr ( Expr )-import Rel8.Expr.Opaleye (fromPrimExpr, toPrimExpr, zipPrimExprsWith)-import Rel8.Type ( DBType, typeInformation )-import Rel8.Type.Array (array)-import Rel8.Type.Information ( TypeInformation(..) )-import Rel8.Schema.Null (Unnullify, Sql)---sappend :: Expr [a] -> Expr [a] -> Expr [a]-sappend = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:||))---sappend1 :: Expr (NonEmpty a) -> Expr (NonEmpty a) -> Expr (NonEmpty a)-sappend1 = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:||))---sempty :: TypeInformation (Unnullify a) -> Expr [a]-sempty info = fromPrimExpr $ array info []---slistOf :: TypeInformation (Unnullify a) -> [Expr a] -> Expr [a]-slistOf info = fromPrimExpr . array info . fmap toPrimExpr---snonEmptyOf :: TypeInformation (Unnullify a) -> NonEmpty (Expr a) -> Expr (NonEmpty a)-snonEmptyOf info = fromPrimExpr . array info . fmap toPrimExpr---listOf :: Sql DBType a => [Expr a] -> Expr [a]-listOf = slistOf typeInformation---nonEmptyOf :: Sql DBType a => NonEmpty (Expr a) -> Expr (NonEmpty a)-nonEmptyOf = snonEmptyOf typeInformation
− src/Rel8/Expr/Bool.hs
@@ -1,90 +0,0 @@-{-# language GADTs #-}--module Rel8.Expr.Bool-  ( false, true-  , (&&.), (||.), not_-  , and_, or_-  , boolExpr-  , caseExpr-  , coalesce-  )-where---- base-import Data.Foldable ( foldl' )-import Prelude hiding ( null )---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import {-# SOURCE #-} Rel8.Expr ( Expr( Expr ) )-import Rel8.Expr.Opaleye ( mapPrimExpr, toPrimExpr, zipPrimExprsWith )-import Rel8.Expr.Serialize ( litExpr )----- | The SQL @false@ literal.-false :: Expr Bool-false = litExpr False----- | The SQL @true@ literal.-true :: Expr Bool-true = litExpr True----- | The SQL @AND@ operator.-(&&.) :: Expr Bool -> Expr Bool -> Expr Bool-(&&.) = zipPrimExprsWith (Opaleye.BinExpr Opaleye.OpAnd)-infixr 3 &&.----- | The SQL @OR@ operator.-(||.) :: Expr Bool -> Expr Bool -> Expr Bool-(||.) = zipPrimExprsWith (Opaleye.BinExpr Opaleye.OpOr)-infixr 2 ||.----- | The SQL @NOT@ operator.-not_ :: Expr Bool -> Expr Bool-not_ = mapPrimExpr (Opaleye.UnExpr Opaleye.OpNot)----- | Fold @AND@ over a collection of expressions.-and_ :: Foldable f => f (Expr Bool) -> Expr Bool-and_ = foldl' (&&.) true----- | Fold @OR@ over a collection of expressions.-or_ :: Foldable f => f (Expr Bool) -> Expr Bool-or_ = foldl' (||.) false----- | Eliminate a boolean-valued expression.------ Corresponds to 'Data.Bool.bool'.-boolExpr :: Expr a -> Expr a -> Expr Bool -> Expr a-boolExpr ifFalse ifTrue condition = caseExpr [(condition, ifTrue)] ifFalse----- | A multi-way if/then/else statement. The first argument to @caseExpr@ is a--- list of alternatives. The first alternative that is of the form @(true, x)@--- will be returned. If no such alternative is found, a fallback expression is--- returned.------ Corresponds to a @CASE@ expression in SQL.-caseExpr :: [(Expr Bool, Expr a)] -> Expr a -> Expr a-caseExpr branches (Expr fallback) =-  Expr $ Opaleye.CaseExpr (map go branches) fallback-  where-    go (condition, value) = (toPrimExpr condition, toPrimExpr value)----- | Convert a @Expr (Maybe Bool)@ to a @Expr Bool@ by treating @Nothing@ as--- @False@. This can be useful when combined with 'Rel8.where_', which expects--- a @Bool@, and produces expressions that optimize better than general case--- analysis.-coalesce :: Expr (Maybe Bool) -> Expr Bool-coalesce (Expr a) = Expr a &&. Expr (Opaleye.FunExpr "COALESCE" [a, untrue])-  where-    untrue = Opaleye.ConstExpr (Opaleye.BoolLit False)
− src/Rel8/Expr/Default.hs
@@ -1,40 +0,0 @@-module Rel8.Expr.Default-  ( unsafeDefault-  )-where---- base-import Prelude ()---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Opaleye ( fromPrimExpr )----- | Corresponds to the SQL @DEFAULT@ expression.------ This 'Expr' is unsafe for numerous reasons, and should be used with care:------ 1. This 'Expr' only makes sense in an @INSERT@ or @UPDATE@ statement.------ 2. Rel8 is not able to verify that a particular column actually has a--- @DEFAULT@ value. Trying to use @unsafeDefault@ where there is no default--- will cause a runtime crash------ 3. @DEFAULT@ values cannot be transformed. For example, the innocuous Rel8--- code @unsafeDefault + 1@ will crash, despite type checking.------ Also note, PostgreSQL's syntax rules mean that @DEFAULT@ can only appear in--- @INSERT@ expressions whose rows are specified using @VALUES@. This means--- that if the @rows@ field of your 'Rel8.Insert' record doesn\'t look like--- @values [..]@, then @unsafeDefault@ won't work.------ Given all these caveats, we suggest avoiding the use of default values where--- possible, instead being explicit. A common scenario where default values are--- used is with auto-incrementing identifier columns. In this case, we suggest--- using 'Rel8.nextval' instead.-unsafeDefault :: Expr a-unsafeDefault = fromPrimExpr Opaleye.DefaultInsertExpr
− src/Rel8/Expr/Eq.hs
@@ -1,101 +0,0 @@-{-# language FlexibleContexts #-}-{-# language GADTs #-}-{-# language ScopedTypeVariables #-}-{-# language TypeApplications #-}-{-# language ViewPatterns #-}--{-# options_ghc -fno-warn-redundant-constraints #-}--module Rel8.Expr.Eq-  ( (==.), (/=.)-  , (==?), (/=?)-  , in_-  )-where---- base-import Data.Foldable ( toList )-import Data.List.NonEmpty ( nonEmpty )-import Prelude---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Bool ( (&&.), (||.), false, or_, coalesce )-import Rel8.Expr.Null ( isNull, unsafeLiftOpNull )-import Rel8.Expr.Opaleye ( fromPrimExpr, toPrimExpr, zipPrimExprsWith )-import Rel8.Schema.Null ( Nullity( NotNull, Null ), Sql, nullable )-import Rel8.Type.Eq ( DBEq )---eq :: DBEq a => Expr a -> Expr a -> Expr Bool-eq = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:==))---ne :: DBEq a => Expr a -> Expr a -> Expr Bool-ne = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:<>))----- | Compare two expressions for equality. ------ This corresponds to the SQL @IS NOT DISTINCT FROM@ operator, and will equate--- @null@ values as @true@. This differs from @=@ which would return @null@.--- This operator matches Haskell's '==' operator. For an operator identical to--- SQL @=@, see '==?'.-(==.) :: forall a. Sql DBEq a => Expr a -> Expr a -> Expr Bool-(==.) = case nullable @a of-  Null -> \ma mb -> isNull ma &&. isNull mb ||. ma ==? mb-  NotNull -> eq-infix 4 ==.-{-# INLINABLE (==.) #-}----- | Test if two expressions are different (not equal).------ This corresponds to the SQL @IS DISTINCT FROM@ operator, and will return--- @false@ when comparing two @null@ values. This differs from ordinary @<>@--- which would return @null@. This operator is closer to Haskell's '/='--- operator. For an operator identical to SQL @<>@, see '/=?'.-(/=.) :: forall a. Sql DBEq a => Expr a -> Expr a -> Expr Bool-(/=.) = case nullable @a of-  Null -> \ma mb -> isNull ma `ne` isNull mb ||. ma /=? mb-  NotNull -> ne-infix 4 /=.-{-# INLINABLE (/=.) #-}----- | Test if two expressions are equal. This operator is usually the best--- choice when forming join conditions, as PostgreSQL has a much harder time--- optimizing a join that has multiple 'True' conditions.------ This corresponds to the SQL @=@ operator, though it will always return a--- 'Bool'.-(==?) :: DBEq a => Expr (Maybe a) -> Expr (Maybe a) -> Expr Bool-a ==? b = coalesce $ unsafeLiftOpNull eq a b-infix 4 ==?----- | Test if two expressions are different. ------ This corresponds to the SQL @<>@ operator, though it will always return a--- 'Bool'.-(/=?) :: DBEq a => Expr (Maybe a) -> Expr (Maybe a) -> Expr Bool-a /=? b = coalesce $ unsafeLiftOpNull ne a b-infix 4 /=?----- | Like the SQL @IN@ operator, but implemented by folding over a list with--- '==.' and '||.'.-in_ :: forall a f. (Sql DBEq a, Foldable f)-  => Expr a -> f (Expr a) -> Expr Bool-in_ a (toList -> as) = case nullable @a of-  Null -> or_ $ map (a ==.) as-  NotNull -> case nonEmpty as of-     Nothing -> false-     Just xs ->-       fromPrimExpr $-         Opaleye.BinExpr Opaleye.OpIn-           (toPrimExpr a)-           (Opaleye.ListExpr (toPrimExpr <$> xs))
− src/Rel8/Expr/Function.hs
@@ -1,93 +0,0 @@-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language RecordWildCards #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Expr.Function-  ( Arguments-  , function-  , primFunction-  , rawFunction-  , binaryOperator-  , rawBinaryOperator-  )-where---- base-import Data.Kind ( Constraint, Type )-import Prelude---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import {-# SOURCE #-} Rel8.Expr (Expr)-import Rel8.Expr.Opaleye-  ( castExpr-  , fromPrimExpr, toPrimExpr, zipPrimExprsWith-  )-import Rel8.Schema.HTable (hfoldMap)-import Rel8.Schema.Null ( Sql )-import Rel8.Schema.QualifiedName-  ( QualifiedName (..)-  , showQualifiedName-  , showQualifiedOperator-  -  )-import Rel8.Table (Table, toColumns)-import Rel8.Type ( DBType )----- | This type class is basically @'Table' 'Expr'@, where each column of the--- 'Table' is an argument to the function, but it also has an additional--- instance for @()@ for calling functions with no arguments.-type Arguments :: Type -> Constraint-class Arguments a where-  arguments :: a -> [Opaleye.PrimExpr]---instance Table Expr a => Arguments a where-  arguments = hfoldMap (pure . toPrimExpr) . toColumns---instance {-# OVERLAPS #-} Arguments () where-  arguments _ = []----- | @'function' name arguments@ runs the PostgreSQL function @name@ with--- the arguments @arguments@ returning an @'Expr' a@.-function :: (Arguments arguments, Sql DBType a)-  => QualifiedName -> arguments -> Expr a-function qualified = castExpr . rawFunction qualified----- | A less safe version of 'function' that does not wrap the return value in--- a cast.-rawFunction :: Arguments arguments => QualifiedName -> arguments -> Expr a-rawFunction qualified = fromPrimExpr . primFunction qualified---primFunction :: Arguments arguments-  => QualifiedName -> arguments -> Opaleye.PrimExpr-primFunction qualified = Opaleye.FunExpr name . arguments-  where-    name = showQualifiedName qualified----- | Construct an expression by applying an infix binary operator to two--- operands.-binaryOperator :: Sql DBType c => QualifiedName -> Expr a -> Expr b -> Expr c-binaryOperator operator a b = castExpr $ rawBinaryOperator operator a b----- | A less safe version of 'binaryOperator' that does not wrap the return--- value in a cast.-rawBinaryOperator :: QualifiedName -> Expr a -> Expr b -> Expr c-rawBinaryOperator operator a b =-  zipPrimExprsWith (Opaleye.BinExpr (Opaleye.OpOther name)) a b-  where-    name = showQualifiedOperator operator
− src/Rel8/Expr/List.hs
@@ -1,52 +0,0 @@-{-# language FlexibleContexts #-}-{-# language MonoLocalBinds #-}--module Rel8.Expr.List (-  headExpr,-  indexExpr,-  lastExpr,-  sheadExpr,-  sindexExpr,-  slastExpr,-  lengthExpr,-) where---- base-import Data.Int (Int32)-import Prelude---- rel8-import Rel8.Expr (Expr)-import Rel8.Expr.Opaleye (mapPrimExpr, toPrimExpr)-import Rel8.Schema.Null (Nullify, Sql, Unnullify)-import Rel8.Type (DBType, typeInformation)-import Rel8.Type.Information (TypeInformation)-import qualified Rel8.Type.Array as Prim---headExpr :: Sql DBType a => Expr [a] -> Expr (Nullify a)-headExpr = sheadExpr typeInformation---indexExpr :: Sql DBType a => Expr Int32 -> Expr [a] -> Expr (Nullify a)-indexExpr = sindexExpr typeInformation---lastExpr :: Sql DBType a => Expr [a] -> Expr (Nullify a)-lastExpr = slastExpr typeInformation---sheadExpr :: TypeInformation (Unnullify a) -> Expr [a] -> Expr (Nullify a)-sheadExpr info = mapPrimExpr (Prim.head info)---sindexExpr :: TypeInformation (Unnullify a) -> Expr Int32 -> Expr [a] -> Expr (Nullify a)-sindexExpr info i = mapPrimExpr (Prim.index info (toPrimExpr i))---slastExpr :: TypeInformation (Unnullify a) -> Expr [a] -> Expr (Nullify a)-slastExpr info = mapPrimExpr (Prim.last info)---lengthExpr :: Expr [a] -> Expr Int32-lengthExpr = mapPrimExpr (Prim.length)
− src/Rel8/Expr/NonEmpty.hs
@@ -1,53 +0,0 @@-{-# language FlexibleContexts #-}-{-# language MonoLocalBinds #-}--module Rel8.Expr.NonEmpty (-  head1Expr,-  index1Expr,-  last1Expr,-  shead1Expr,-  sindex1Expr,-  slast1Expr,-  length1Expr,-) where---- base-import Data.Int (Int32)-import Data.List.NonEmpty (NonEmpty)-import Prelude---- rel8-import Rel8.Expr (Expr)-import Rel8.Expr.Opaleye (mapPrimExpr, toPrimExpr)-import Rel8.Schema.Null (Nullify, Sql, Unnullify)-import Rel8.Type (DBType, typeInformation)-import Rel8.Type.Information (TypeInformation)-import qualified Rel8.Type.Array as Prim---head1Expr :: Sql DBType a => Expr (NonEmpty a) -> Expr a-head1Expr = shead1Expr typeInformation---index1Expr :: Sql DBType a => Expr Int32 -> Expr (NonEmpty a) -> Expr (Nullify a)-index1Expr = sindex1Expr typeInformation---last1Expr :: Sql DBType a => Expr (NonEmpty a) -> Expr a-last1Expr = slast1Expr typeInformation---shead1Expr :: TypeInformation (Unnullify a) -> Expr (NonEmpty a) -> Expr a-shead1Expr info = mapPrimExpr (Prim.head info)---sindex1Expr :: TypeInformation (Unnullify a) -> Expr Int32 -> Expr (NonEmpty a) -> Expr (Nullify a)-sindex1Expr info i = mapPrimExpr (Prim.index info (toPrimExpr i))---slast1Expr :: TypeInformation (Unnullify a) -> Expr (NonEmpty a) -> Expr a-slast1Expr info = mapPrimExpr (Prim.last info)---length1Expr :: Expr (NonEmpty a) -> Expr Int32-length1Expr = mapPrimExpr (Prim.length)
− src/Rel8/Expr/Null.hs
@@ -1,106 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language TypeFamilies #-}--{-# options -fno-warn-redundant-constraints #-}--module Rel8.Expr.Null-  ( null, snull, nullableExpr, nullableOf-  , isNull, isNonNull-  , nullify, unsafeUnnullify-  , mapNull, liftOpNull-  , unsafeMapNull, unsafeLiftOpNull-  )-where---- base-import Prelude hiding ( null )---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import {-# SOURCE #-} Rel8.Expr ( Expr( Expr ) )-import Rel8.Expr.Bool ( (||.), boolExpr )-import Rel8.Expr.Opaleye ( scastExpr, mapPrimExpr )-import Rel8.Schema.Null ( NotNull )-import Rel8.Type ( DBType, typeInformation )-import Rel8.Type.Information ( TypeInformation )----- | Lift an expression that can't be @null@ to a type that might be @null@.--- This is an identity operation in terms of any generated query, and just--- modifies the query's type.-nullify :: NotNull a => Expr a -> Expr (Maybe a)-nullify (Expr a) = Expr a----- | Assume that a nullable column's value is non-null. If the column is--- actually @null@, this will lead to runtime errors when you try to decode--- the value into Haskell, so you should prefer to use 'Rel8.nullable'--- unless you know what you're doing.-unsafeUnnullify :: Expr (Maybe a) -> Expr a-unsafeUnnullify (Expr a) = Expr a----- | Like 'maybe', but to eliminate @null@.-nullableExpr :: Expr b -> (Expr a -> Expr b) -> Expr (Maybe a) -> Expr b-nullableExpr b f ma = boolExpr (f (unsafeUnnullify ma)) b (isNull ma)---nullableOf :: DBType a => Maybe (Expr a) -> Expr (Maybe a)-nullableOf = maybe null nullify----- | Like 'Data.Maybe.isNothing', but for @null@.-isNull :: Expr (Maybe a) -> Expr Bool-isNull = mapPrimExpr (Opaleye.UnExpr Opaleye.OpIsNull)----- | Like 'Data.Maybe.isJust', but for @null@.-isNonNull :: Expr (Maybe a) -> Expr Bool-isNonNull = mapPrimExpr (Opaleye.UnExpr Opaleye.OpIsNotNull)----- | Lift an operation on non-@null@ values to an operation on possibly @null@--- values. When given @null@, @mapNull f@ returns @null@.--- --- This is like 'fmap' for 'Maybe'.-mapNull :: DBType b-  => (Expr a -> Expr b) -> Expr (Maybe a) -> Expr (Maybe b)-mapNull f ma = boolExpr (unsafeMapNull f ma) null (isNull ma)----- | Lift a binary operation on non-@null@ expressions to an equivalent binary--- operator on possibly @null@ expressions. If either of the final arguments--- are @null@, @liftOpNull@ returns @null@.------ This is like 'liftA2' for 'Maybe'.-liftOpNull :: DBType c-  => (Expr a -> Expr b -> Expr c)-  -> Expr (Maybe a) -> Expr (Maybe b) -> Expr (Maybe c)-liftOpNull f ma mb =-  boolExpr (unsafeLiftOpNull f ma mb) null-    (isNull ma ||. isNull mb)-{-# INLINABLE liftOpNull #-}---snull :: TypeInformation a -> Expr (Maybe a)-snull info = scastExpr info $ Expr $ Opaleye.ConstExpr Opaleye.NullLit----- | Corresponds to SQL @null@.-null :: DBType a => Expr (Maybe a)-null = snull typeInformation---unsafeMapNull :: NotNull b-  => (Expr a -> Expr b) -> Expr (Maybe a) -> Expr (Maybe b)-unsafeMapNull f ma = nullify (f (unsafeUnnullify ma))---unsafeLiftOpNull :: NotNull c-  => (Expr a -> Expr b -> Expr c)-  -> Expr (Maybe a) -> Expr (Maybe b) -> Expr (Maybe c)-unsafeLiftOpNull f ma mb =-  nullify (f (unsafeUnnullify ma) (unsafeUnnullify mb))
src/Rel8/Expr/Num.hs view
@@ -17,13 +17,13 @@ import Prelude ( (+), (-), fst, negate, signum, snd )  -- rel-import Rel8.Expr ( Expr( Expr ) )-import Rel8.Expr.Eq ( (==.) )-import Rel8.Expr.Function (function)-import Rel8.Expr.Opaleye ( castExpr )-import Rel8.Schema.Null ( Homonullable, Sql )-import Rel8.Table.Bool ( bool )-import Rel8.Type.Num ( DBFractional, DBIntegral, DBNum )+import Rel8.Internal.Expr ( Expr( Expr ) )+import Rel8.Internal.Expr.Eq ( (==.) )+import Rel8.Internal.Expr.Function (function)+import Rel8.Internal.Expr.Opaleye ( castExpr )+import Rel8.Internal.Schema.Null ( Homonullable, Sql )+import Rel8.Internal.Table.Bool ( bool )+import Rel8.Internal.Type.Num ( DBFractional, DBIntegral, DBNum )   -- | Cast 'DBIntegral' types to 'DBNum' types. For example, this can be useful
− src/Rel8/Expr/Opaleye.hs
@@ -1,118 +0,0 @@-{-# language FlexibleContexts #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}--{-# options_ghc -fno-warn-redundant-constraints #-}--module Rel8.Expr.Opaleye-  ( castExpr, unsafeCastExpr-  , scastExpr, sunsafeCastExpr-  , unsafeCoerceExpr-  , unsafePrimExpr-  , unsafeLiteral-  , fromPrimExpr, toPrimExpr, mapPrimExpr, zipPrimExprsWith, traversePrimExpr-  , toColumn, fromColumn, traverseFieldP-  )-where---- base-import Prelude---- opaleye-import qualified Opaleye.Internal.Column as Opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import {-# SOURCE #-} Rel8.Expr ( Expr( Expr ) )-import Rel8.Schema.Null ( Unnullify, Sql )-import Rel8.Type ( DBType, typeInformation )-import Rel8.Type.Information ( TypeInformation(..) )-import Rel8.Type.Name (TypeName, showTypeName)---- profunctors-import Data.Profunctor ( Profunctor, dimap )---castExpr :: Sql DBType a => Expr a -> Expr a-castExpr = scastExpr typeInformation----- | Cast an expression to a different type. Corresponds to a @CAST()@ function--- call.-unsafeCastExpr :: forall b a. Sql DBType b => Expr a -> Expr b-unsafeCastExpr = case typeInformation @(Unnullify b) of-  TypeInformation {typeName} -> sunsafeCastExpr typeName----- | Change the type of an 'Expr', without a cast. Even more unsafe than--- 'unsafeCastExpr'. Only use this if you are certain that the @typeName@s of--- @a@ and @b@ refer to exactly the same PostgreSQL type.-unsafeCoerceExpr :: Expr a -> Expr b-unsafeCoerceExpr (Expr a) = Expr a----- | Import a raw 'Opaleye.PrimExpr' from @opaleye@, without a cast.------ This is an escape hatch, and can be used if Rel8 cannot adequately express--- the expression you need. If you find yourself using this function, please--- let us know, as it may indicate that something is missing from Rel8!-unsafePrimExpr :: Opaleye.PrimExpr -> Expr a-unsafePrimExpr = fromPrimExpr---scastExpr :: TypeInformation (Unnullify a) -> Expr a -> Expr a-scastExpr TypeInformation {typeName} = sunsafeCastExpr typeName---sunsafeCastExpr :: ()-  => TypeName -> Expr a -> Expr b-sunsafeCastExpr name =-  fromPrimExpr . Opaleye.CastExpr (showTypeName name) . toPrimExpr----- | Unsafely construct an expression from literal SQL.------ This is an escape hatch, and can be used if Rel8 cannot adequately express--- the expression you need. If you find yourself using this function, please let--- us know, as it may indicate that something is missing from Rel8!-unsafeLiteral :: String -> Expr a-unsafeLiteral = Expr . Opaleye.ConstExpr . Opaleye.OtherLit---fromPrimExpr :: Opaleye.PrimExpr -> Expr a-fromPrimExpr = Expr---toPrimExpr :: Expr a -> Opaleye.PrimExpr-toPrimExpr (Expr a) = a---mapPrimExpr :: (Opaleye.PrimExpr -> Opaleye.PrimExpr) -> Expr a -> Expr b-mapPrimExpr f = fromPrimExpr . f . toPrimExpr---zipPrimExprsWith :: ()-  => (Opaleye.PrimExpr -> Opaleye.PrimExpr -> Opaleye.PrimExpr)-  -> Expr a -> Expr b -> Expr c-zipPrimExprsWith f a b = fromPrimExpr (f (toPrimExpr a) (toPrimExpr b))---traversePrimExpr :: Functor f-  => (Opaleye.PrimExpr -> f Opaleye.PrimExpr) -> Expr a -> f (Expr b)-traversePrimExpr f = fmap fromPrimExpr . f . toPrimExpr---traverseFieldP :: Profunctor p-  => p (Opaleye.Field_ n x) (Opaleye.Field_ m y)-  -> p (Expr a) (Expr b)-traverseFieldP =  dimap (toColumn . toPrimExpr) (fromPrimExpr . fromColumn)---toColumn :: Opaleye.PrimExpr -> Opaleye.Field_ n b-toColumn = Opaleye.Column---fromColumn :: Opaleye.Field_ n b -> Opaleye.PrimExpr-fromColumn (Opaleye.Column a) = a
− src/Rel8/Expr/Ord.hs
@@ -1,137 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language GADTs #-}-{-# language ScopedTypeVariables #-}-{-# language TypeApplications #-}--{-# options_ghc -fno-warn-redundant-constraints #-}--module Rel8.Expr.Ord-  ( (<.), (<=.), (>.), (>=.)-  , (<?), (<=?), (>?), (>=?)-  , leastExpr, greatestExpr-  )-where---- base-import Prelude---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Expr ( Expr( Expr ) )-import Rel8.Expr.Bool ( (&&.), (||.), coalesce )-import Rel8.Expr.Null ( isNull, isNonNull, nullableExpr, unsafeLiftOpNull )-import Rel8.Expr.Opaleye ( toPrimExpr, zipPrimExprsWith )-import Rel8.Schema.Null ( Nullity( Null, NotNull ), Sql, nullable )-import Rel8.Type.Ord ( DBOrd )---lt :: DBOrd a => Expr a -> Expr a -> Expr Bool-lt = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:<))---le :: DBOrd a => Expr a -> Expr a -> Expr Bool-le = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:<=))---gt :: DBOrd a => Expr a -> Expr a -> Expr Bool-gt = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:>))---ge :: DBOrd a => Expr a -> Expr a -> Expr Bool-ge = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:>=))----- | Corresponds to the SQL @<@ operator. Note that this differs from SQL @<@--- as @null@ will sort below any other value. For a version of @<@ that exactly--- matches SQL, see '(<?)'.-(<.) :: forall a. Sql DBOrd a => Expr a -> Expr a -> Expr Bool-(<.) = case nullable @a of-  Null -> \ma mb -> isNull ma &&. isNonNull mb ||. ma <? mb-  NotNull -> lt-infix 4 <.----- | Corresponds to the SQL @<=@ operator. Note that this differs from SQL @<=@--- as @null@ will sort below any other value. For a version of @<=@ that exactly--- matches SQL, see '(<=?)'.-(<=.) :: forall a. Sql DBOrd a => Expr a -> Expr a -> Expr Bool-(<=.) = case nullable @a of-  Null -> \ma mb -> isNull ma ||. ma <=? mb-  NotNull -> le-infix 4 <=.----- | Corresponds to the SQL @>@ operator. Note that this differs from SQL @>@--- as @null@ will sort below any other value. For a version of @>@ that exactly--- matches SQL, see '(>?)'.-(>.) :: forall a. Sql DBOrd a => Expr a -> Expr a -> Expr Bool-(>.) = case nullable @a of-  Null -> \ma mb -> isNonNull ma &&. isNull mb ||. ma >? mb-  NotNull -> gt-infix 4 >.----- | Corresponds to the SQL @>=@ operator. Note that this differs from SQL @>@--- as @null@ will sort below any other value. For a version of @>=@ that--- exactly matches SQL, see '(>=?)'.-(>=.) :: forall a. Sql DBOrd a => Expr a -> Expr a -> Expr Bool-(>=.) = case nullable @a of-  Null -> \ma mb -> isNull mb ||. ma >=? mb-  NotNull -> ge-infix 4 >=.----- | Corresponds to the SQL @<@ operator. Returns @null@ if either arguments--- are @null@.-(<?) :: DBOrd a => Expr (Maybe a) -> Expr (Maybe a) -> Expr Bool-a <? b = coalesce $ unsafeLiftOpNull lt a b-infix 4 <?----- | Corresponds to the SQL @<=@ operator. Returns @null@ if either arguments--- are @null@.-(<=?) :: DBOrd a => Expr (Maybe a) -> Expr (Maybe a) -> Expr Bool-a <=? b = coalesce $ unsafeLiftOpNull le a b-infix 4 <=?----- | Corresponds to the SQL @>@ operator. Returns @null@ if either arguments--- are @null@.-(>?) :: DBOrd a => Expr (Maybe a) -> Expr (Maybe a) -> Expr Bool-a >? b = coalesce $ unsafeLiftOpNull gt a b-infix 4 >?----- | Corresponds to the SQL @>=@ operator. Returns @null@ if either arguments--- are @null@.-(>=?) :: DBOrd a => Expr (Maybe a) -> Expr (Maybe a) -> Expr Bool-a >=? b = coalesce $ unsafeLiftOpNull ge a b-infix 4 >=?----- | Given two expressions, return the expression that sorts less than the--- other.--- --- Corresponds to the SQL @least()@ function.-leastExpr :: forall a. Sql DBOrd a => Expr a -> Expr a -> Expr a-leastExpr ma mb = case nullable @a of-  Null -> nullableExpr ma (\a -> nullableExpr mb (least_ a) mb) ma-  NotNull -> least_ ma mb-  where-    least_ a b = Expr (Opaleye.FunExpr "LEAST" [toPrimExpr a, toPrimExpr b])----- | Given two expressions, return the expression that sorts greater than the--- other.--- --- Corresponds to the SQL @greatest()@ function.-greatestExpr :: forall a. Sql DBOrd a => Expr a -> Expr a -> Expr a-greatestExpr ma mb = case nullable @a of-  Null -> nullableExpr mb (\a -> nullableExpr ma (greatest_ a) mb) ma-  NotNull -> greatest_ ma mb-  where-    greatest_ a b =-      Expr (Opaleye.FunExpr "GREATEST" [toPrimExpr a, toPrimExpr b])
− src/Rel8/Expr/Order.hs
@@ -1,69 +0,0 @@-{-# language DataKinds #-}--{-# options_ghc -fno-warn-redundant-constraints #-}--module Rel8.Expr.Order-  ( asc-  , desc-  , nullsFirst-  , nullsLast-  )-where---- base-import Data.Bifunctor ( first )-import Prelude---- opaleye-import Opaleye.Internal.HaskellDB.PrimQuery ( OrderOp( orderDirection, orderNulls ) )-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye-import qualified Opaleye.Internal.Order as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Null ( unsafeUnnullify )-import Rel8.Expr.Opaleye ( toPrimExpr )-import Rel8.Order ( Order( Order ) )-import Rel8.Type.Ord ( DBOrd )----- | Sort a column in ascending order.-asc :: DBOrd a => Order (Expr a)-asc = Order $ Opaleye.Order (\expr -> [(orderOp, toPrimExpr expr)])-  where-    orderOp :: Opaleye.OrderOp-    orderOp = Opaleye.OrderOp-      { orderDirection = Opaleye.OpAsc-      , orderNulls = Opaleye.NullsLast-      }----- | Sort a column in descending order.-desc :: DBOrd a => Order (Expr a)-desc = Order $ Opaleye.Order (\expr -> [(orderOp, toPrimExpr expr)])-  where-    orderOp :: Opaleye.OrderOp-    orderOp = Opaleye.OrderOp-      { orderDirection = Opaleye.OpDesc-      , orderNulls = Opaleye.NullsFirst-      }----- | Transform an ordering so that @null@ values appear first. This corresponds--- to @NULLS FIRST@ in SQL.-nullsFirst :: Order (Expr a) -> Order (Expr (Maybe a))-nullsFirst (Order (Opaleye.Order f)) =-  Order $ Opaleye.Order $ fmap (first g) . f . unsafeUnnullify-  where-    g :: Opaleye.OrderOp -> Opaleye.OrderOp-    g orderOp = orderOp { Opaleye.orderNulls = Opaleye.NullsFirst }----- | Transform an ordering so that @null@ values appear last. This corresponds--- to @NULLS LAST@ in SQL.-nullsLast :: Order (Expr a) -> Order (Expr (Maybe a))-nullsLast (Order (Opaleye.Order f)) =-  Order $ Opaleye.Order $ fmap (first g) . f . unsafeUnnullify-  where-    g :: Opaleye.OrderOp -> Opaleye.OrderOp-    g orderOp = orderOp { Opaleye.orderNulls = Opaleye.NullsLast }
− src/Rel8/Expr/Read.hs
@@ -1,29 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE MonoLocalBinds #-}--module Rel8.Expr.Read-  ( read-  , sread-  )-where---- base-import Prelude ()---- rel8-import Rel8.Expr (Expr)-import Rel8.Expr.Opaleye (unsafeCastExpr, sunsafeCastExpr)-import Rel8.Schema.Null (Sql)-import Rel8.Type (DBType)-import Rel8.Type.Name (TypeName)---- text-import Data.Text (Text)---read :: Sql DBType a => Expr Text -> Expr a-read = unsafeCastExpr---sread :: TypeName -> Expr Text -> Expr a-sread = sunsafeCastExpr
− src/Rel8/Expr/Sequence.hs
@@ -1,25 +0,0 @@-module Rel8.Expr.Sequence-  ( nextval-  )-where---- base-import Data.Int ( Int64 )-import Prelude---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Opaleye (fromPrimExpr)-import Rel8.Schema.QualifiedName (QualifiedName, showQualifiedName)----- | See https://www.postgresql.org/docs/current/functions-sequence.html-nextval :: QualifiedName -> Expr Int64-nextval name =-  fromPrimExpr $-    Opaleye.FunExpr "nextval"-      [ Opaleye.ConstExpr (Opaleye.StringLit (showQualifiedName name))-      ]
− src/Rel8/Expr/Serialize.hs
@@ -1,52 +0,0 @@-{-# language DisambiguateRecordFields #-}-{-# language FlexibleContexts #-}-{-# language NamedFieldPuns #-}-{-# language TypeFamilies #-}--module Rel8.Expr.Serialize-  ( litExpr-  , slitExpr-  , sparseValue-  )-where---- base-import Prelude---- hasql-import qualified Hasql.Decoders as Hasql---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import {-# SOURCE #-} Rel8.Expr ( Expr( Expr ) )-import Rel8.Expr.Opaleye ( scastExpr )-import Rel8.Schema.Null ( Unnullify, Nullity( Null, NotNull ), Sql, nullable )-import Rel8.Type ( DBType, typeInformation )-import Rel8.Type.Decoder (Decoder (..))-import Rel8.Type.Encoder (Encoder (..))-import Rel8.Type.Information ( TypeInformation(..) )----- | Produce an expression from a literal.------ Note that you can usually use 'Rel8.lit', but @litExpr@ can solve problems--- of inference in polymorphic code.-litExpr :: Sql DBType a => a -> Expr a-litExpr = slitExpr nullable typeInformation---slitExpr :: Nullity a -> TypeInformation (Unnullify a) -> a -> Expr a-slitExpr nullity info@TypeInformation {encode = Encoder {quote}} =-  scastExpr info . Expr . encoder-  where-    encoder = case nullity of-      Null -> maybe (Opaleye.ConstExpr Opaleye.NullLit) quote-      NotNull -> quote---sparseValue :: Nullity a -> TypeInformation (Unnullify a) -> Hasql.Row a-sparseValue nullity TypeInformation {decode = Decoder {binary}} = case nullity of-  Null -> Hasql.column $ Hasql.nullable binary-  NotNull -> Hasql.column $ Hasql.nonNullable binary
− src/Rel8/Expr/Show.hs
@@ -1,18 +0,0 @@-module Rel8.Expr.Show-  ( show-  )-where---- base-import Prelude ()---- rel8-import Rel8.Expr (Expr)-import Rel8.Expr.Opaleye (unsafeCastExpr)---- text-import Data.Text (Text)---show :: Expr a -> Expr Text-show = unsafeCastExpr
− src/Rel8/Expr/Subscript.hs
@@ -1,65 +0,0 @@-{-# language FlexibleContexts #-}-{-# language MonoLocalBinds #-}--module Rel8.Expr.Subscript-  ( unsafeSubscript-  , unsafeSubscripts-  )-where---- base-import Data.Foldable (foldl')-import Prelude---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Expr (Expr)-import Rel8.Expr.Opaleye (fromPrimExpr, toPrimExpr)-import Rel8.Schema.HTable (hfoldMap)-import Rel8.Schema.Null (Sql, Unnullify)-import Rel8.Table (Table, toColumns)-import Rel8.Type (DBType, typeInformation)-import Rel8.Type.Array (extractArrayElement)-import Rel8.Type.Information (TypeInformation)----- | @'unsafeSubscript' a i@ will generate the SQL @a[i]@.------ Note that this function is not type checked and the generated SQL has no--- casts. This is only intended an escape hatch to be used if Rel8 cannot--- otherwise express the expression you need. If you find yourself using this--- function, please let us know, as it may indicate that something is missing--- from Rel8!-unsafeSubscript :: Sql DBType b => Expr a -> Expr i -> Expr b-unsafeSubscript = sunsafeSubscript typeInformation----- | @'unsafeSubscripts' a (i, j)@ will generate the SQL @a[i][j]@.------ Note that this function is not type checked and the generated SQL has no--- casts. This is only intended an escape hatch to be used if Rel8 cannot--- otherwise express the expression you need. If you find yourself using this--- function, please let us know, as it may indicate that something is missing--- from Rel8!-unsafeSubscripts :: (Table Expr i, Sql DBType b) => Expr a -> i -> Expr b-unsafeSubscripts = sunsafeSubscripts typeInformation---sunsafeSubscript :: TypeInformation (Unnullify b) -> Expr a -> Expr i -> Expr b-sunsafeSubscript info array i =-  fromPrimExpr . extractArrayElement info $-    Opaleye.ArrayIndex (toPrimExpr array) (toPrimExpr i)---sunsafeSubscripts :: Table Expr i => TypeInformation (Unnullify b) -> Expr a -> i -> Expr b-sunsafeSubscripts info array i =-  fromPrimExpr $ extractArrayElement info $ primSubscripts array indices-  where-    indices = hfoldMap (pure . toPrimExpr) $ toColumns i---primSubscripts :: Expr a -> [Opaleye.PrimExpr] -> Opaleye.PrimExpr-primSubscripts array indices =-  foldl' Opaleye.ArrayIndex (toPrimExpr array) indices
src/Rel8/Expr/Text.hs view
@@ -1,6 +1,3 @@-{-# language DataKinds #-}-{-# language OverloadedStrings #-}- module Rel8.Expr.Text   (     -- * String concatenation@@ -25,277 +22,7 @@ where  -- base-import Data.Bool ( Bool )-import Data.Int ( Int32 )-import Data.Maybe ( Maybe( Nothing, Just ) )-import Prelude ( flip )---- bytestring-import Data.ByteString ( ByteString )---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye+import Prelude hiding (length, repeat, reverse)  -- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Function (binaryOperator, function)-import Rel8.Expr.Opaleye (zipPrimExprsWith)---- text-import Data.Text (Text)----- | The PostgreSQL string concatenation operator.-(++.) :: Expr Text -> Expr Text -> Expr Text-(++.) = binaryOperator "||"-infixr 6 ++.----- * Regular expression operators---- See https://www.postgresql.org/docs/9.5/static/functions-matching.html#FUNCTIONS-POSIX-REGEXP----- | Matches regular expression, case sensitive------ Corresponds to the @~@ operator.-(~.) :: Expr Text -> Expr Text -> Expr Bool-(~.) = binaryOperator "~"-infix 2 ~.----- | Matches regular expression, case insensitive------ Corresponds to the @~*@ operator.-(~*) :: Expr Text -> Expr Text -> Expr Bool-(~*) = binaryOperator "~*"-infix 2 ~*----- | Does not match regular expression, case sensitive------ Corresponds to the @!~@ operator.-(!~) :: Expr Text -> Expr Text -> Expr Bool-(!~) = binaryOperator "!~"-infix 2 !~----- | Does not match regular expression, case insensitive------ Corresponds to the @!~*@ operator.-(!~*) :: Expr Text -> Expr Text -> Expr Bool-(!~*) = binaryOperator "!~*"-infix 2 !~*----- See https://www.postgresql.org/docs/9.5/static/functions-Expr.'PGHtml---- * Standard SQL functions----- | Corresponds to the @bit_length@ function.-bitLength :: Expr Text -> Expr Int32-bitLength = function "bit_length"----- | Corresponds to the @char_length@ function.-charLength :: Expr Text -> Expr Int32-charLength = function "char_length"----- | Corresponds to the @lower@ function.-lower :: Expr Text -> Expr Text-lower = function "lower"----- | Corresponds to the @octet_length@ function.-octetLength :: Expr Text -> Expr Int32-octetLength = function "octet_length"----- | Corresponds to the @upper@ function.-upper :: Expr Text -> Expr Text-upper = function "upper"----- | Corresponds to the @ascii@ function.-ascii :: Expr Text -> Expr Int32-ascii = function "ascii"----- | Corresponds to the @btrim@ function.-btrim :: Expr Text -> Maybe (Expr Text) -> Expr Text-btrim a (Just b) = function "btrim" (a, b)-btrim a Nothing = function "btrim" a----- | Corresponds to the @chr@ function.-chr :: Expr Int32 -> Expr Text-chr = function "chr"----- | Corresponds to the @convert@ function.-convert :: Expr ByteString -> Expr Text -> Expr Text -> Expr ByteString-convert a b c = function "convert" (a, b, c)----- | Corresponds to the @convert_from@ function.-convertFrom :: Expr ByteString -> Expr Text -> Expr Text-convertFrom a b = function "convert_from" (a, b)----- | Corresponds to the @convert_to@ function.-convertTo :: Expr Text -> Expr Text -> Expr ByteString-convertTo a b = function "convert_to" (a, b)----- | Corresponds to the @decode@ function.-decode :: Expr Text -> Expr Text -> Expr ByteString-decode a b = function "decode" (a, b)----- | Corresponds to the @encode@ function.-encode :: Expr ByteString -> Expr Text -> Expr Text-encode a b = function "encode" (a, b)----- | Corresponds to the @initcap@ function.-initcap :: Expr Text -> Expr Text-initcap = function "initcap"----- | Corresponds to the @left@ function.-left :: Expr Text -> Expr Int32 -> Expr Text-left a b = function "left" (a, b)----- | Corresponds to the @length@ function.-length :: Expr Text -> Expr Int32-length = function "length"----- | Corresponds to the @length@ function.-lengthEncoding :: Expr ByteString -> Expr Text -> Expr Int32-lengthEncoding a b = function "length" (a, b)----- | Corresponds to the @lpad@ function.-lpad :: Expr Text -> Expr Int32 -> Maybe (Expr Text) -> Expr Text-lpad a b (Just c) = function "lpad" (a, b, c)-lpad a b Nothing = function "lpad" (a, b)----- | Corresponds to the @ltrim@ function.-ltrim :: Expr Text -> Maybe (Expr Text) -> Expr Text-ltrim a (Just b) = function "ltrim" (a, b)-ltrim a Nothing = function "ltrim" a----- | Corresponds to the @md5@ function.-md5 :: Expr Text -> Expr Text-md5 = function "md5"----- | Corresponds to the @pg_client_encoding()@ expression.-pgClientEncoding :: Expr Text-pgClientEncoding = function "pg_client_encoding" ()----- | Corresponds to the @quote_ident@ function.-quoteIdent :: Expr Text -> Expr Text-quoteIdent = function "quote_ident"----- | Corresponds to the @quote_literal@ function.-quoteLiteral :: Expr Text -> Expr Text-quoteLiteral = function "quote_literal"----- | Corresponds to the @quote_nullable@ function.-quoteNullable :: Expr Text -> Expr Text-quoteNullable = function "quote_nullable"----- | Corresponds to the @regexp_replace@ function.-regexpReplace :: ()-  => Expr Text -> Expr Text -> Expr Text -> Maybe (Expr Text) -> Expr Text-regexpReplace a b c (Just d) = function "regexp_replace" (a, b, c, d)-regexpReplace a b c Nothing = function "regexp_replace" (a, b, c)----- | Corresponds to the @regexp_split_to_array@ function.-regexpSplitToArray :: ()-  => Expr Text -> Expr Text -> Maybe (Expr Text) -> Expr [Text]-regexpSplitToArray a b (Just c) = function "regexp_split_to_array" (a, b, c)-regexpSplitToArray a b Nothing = function "regexp_split_to_array" (a, b)----- | Corresponds to the @repeat@ function.-repeat :: Expr Text -> Expr Int32 -> Expr Text-repeat a b = function "repeat" (a, b)----- | Corresponds to the @replace@ function.-replace :: Expr Text -> Expr Text -> Expr Text -> Expr Text-replace a b c = function "replace" (a, b, c)----- | Corresponds to the @reverse@ function.-reverse :: Expr Text -> Expr Text-reverse = function "reverse"----- | Corresponds to the @right@ function.-right :: Expr Text -> Expr Int32 -> Expr Text-right a b = function "right" (a, b)----- | Corresponds to the @rpad@ function.-rpad :: Expr Text -> Expr Int32 -> Maybe (Expr Text) -> Expr Text-rpad a b (Just c) = function "rpad" (a, b, c)-rpad a b Nothing = function "rpad" (a, b)----- | Corresponds to the @rtrim@ function.-rtrim :: Expr Text -> Maybe (Expr Text) -> Expr Text-rtrim a (Just b) = function "rtrim" (a, b)-rtrim a Nothing = function "rtrim" a----- | Corresponds to the @split_part@ function.-splitPart :: Expr Text -> Expr Text -> Expr Int32 -> Expr Text-splitPart a b c = function "split_part" (a, b, c)----- | Corresponds to the @strpos@ function.-strpos :: Expr Text -> Expr Text -> Expr Int32-strpos a b = function "strpos" (a, b)----- | Corresponds to the @substr@ function.-substr :: Expr Text -> Expr Int32 -> Maybe (Expr Int32) -> Expr Text-substr a b (Just c) = function "substr" (a, b, c)-substr a b Nothing = function "substr" (a, b)----- | Corresponds to the @translate@ function.-translate :: Expr Text -> Expr Text -> Expr Text -> Expr Text-translate a b c = function "translate" (a, b, c)----- | @like x y@ corresponds to the expression @y LIKE x@.------ Note that the arguments to @like@ are swapped. This is to aid currying, so--- you can write expressions like--- @filter (like "Rel%" . packageName) =<< each haskellPackages@-like :: Expr Text -> Expr Text -> Expr Bool-like = flip (zipPrimExprsWith (Opaleye.BinExpr Opaleye.OpLike))----- | @ilike x y@ corresponds to the expression @y ILIKE x@.------ Note that the arguments to @ilike@ are swapped. This is to aid currying, so--- you can write expressions like--- @filter (ilike "Rel%" . packageName) =<< each haskellPackages@-ilike :: Expr Text -> Expr Text -> Expr Bool-ilike = flip (zipPrimExprsWith (Opaleye.BinExpr Opaleye.OpILike))+import Rel8.Internal.Expr.Text 
src/Rel8/Expr/Time.hs view
@@ -31,9 +31,9 @@ import Prelude  -- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Function (binaryOperator, function)-import Rel8.Expr.Opaleye ( castExpr, unsafeCastExpr, unsafeLiteral )+import Rel8.Internal.Expr ( Expr )+import Rel8.Internal.Expr.Function (binaryOperator, function)+import Rel8.Internal.Expr.Opaleye ( castExpr, unsafeCastExpr, unsafeLiteral )  -- time import Data.Time.Calendar ( Day )
− src/Rel8/Expr/Window.hs
@@ -1,149 +0,0 @@-module Rel8.Expr.Window-  ( cumulative-  , rowNumber-  , rank-  , denseRank-  , percentRank-  , cumeDist-  , ntile-  , lagExpr, lagExprOn-  , leadExpr, leadExprOn-  , firstValueExpr, firstValueExprOn-  , lastValueExpr, lastValueExprOn-  , nthValueExpr, nthValueExprOn-  )-where---- base-import Data.Int ( Int32, Int64 )-import Prelude---- opaleye-import qualified Opaleye.Internal.Aggregate as Opaleye-import qualified Opaleye.Internal.PackMap as Opaleye-import qualified Opaleye.Internal.Window as Opaleye-import qualified Opaleye.Window as Opaleye---- profunctors-import Data.Profunctor (dimap, lmap)---- rel8-import Rel8.Aggregate (Aggregator' (Aggregator))-import Rel8.Expr ( Expr )-import Rel8.Expr.Opaleye ( fromColumn, fromPrimExpr, toColumn, toPrimExpr )-import Rel8.Schema.Null ( Nullify )-import Rel8.Window ( Window( Window ) )----- | 'cumulative' allows the use of aggregation functions in 'Window'--- expressions. In particular, @'cumulative' 'Rel8.sum'@--- (when combined with 'Rel8.Window.orderPartitionBy') gives a running total,--- also known as a \"cumulative sum\", hence the name @cumulative@.-cumulative :: Aggregator' fold i a -> Window i a-cumulative f =-  fromWindowFunction $ Opaleye.aggregatorWindowFunction (fromAggregate f) id----- | [@row_number()@](https://www.postgresql.org/docs/current/functions-window.html)-rowNumber :: Window i (Expr Int64)-rowNumber = fromWindowFunction $ fromPrimExpr . fromColumn <$> Opaleye.rowNumber----- | [@rank()@](https://www.postgresql.org/docs/current/functions-window.html)-rank :: Window i (Expr Int64)-rank = fromWindowFunction $ fromPrimExpr . fromColumn <$> Opaleye.rank----- | [@dense_rank()@](https://www.postgresql.org/docs/current/functions-window.html)-denseRank :: Window i (Expr Int64)-denseRank = fromWindowFunction $ fromPrimExpr . fromColumn <$> Opaleye.denseRank----- | [@percent_rank()@](https://www.postgresql.org/docs/current/functions-window.html)-percentRank :: Window i (Expr Double)-percentRank = fromWindowFunction $ fromPrimExpr . fromColumn <$> Opaleye.percentRank----- | [@cume_dist()@](https://www.postgresql.org/docs/current/functions-window.html)-cumeDist :: Window i (Expr Double)-cumeDist = fromWindowFunction $ fromPrimExpr . fromColumn <$> Opaleye.cumeDist----- | [@ntile(num_buckets)@](https://www.postgresql.org/docs/current/functions-window.html)-ntile :: Expr Int32 -> Window i (Expr Int32)-ntile buckets = fromWindowFunction $ fromPrimExpr . fromColumn <$>-  Opaleye.ntile (toColumn (toPrimExpr buckets))----- | [@lag(value, offset, default)@](https://www.postgresql.org/docs/current/functions-window.html)-lagExpr :: Expr Int32 -> Expr a -> Window (Expr a) (Expr a)-lagExpr offset def =-  fromWindowFunction $-    dimap (toColumn . toPrimExpr) (fromPrimExpr . fromColumn) $-      Opaleye.lag (toColumn (toPrimExpr offset)) (toColumn (toPrimExpr def))----- | Applies 'lag' to the column selected by the given function.-lagExprOn :: Expr Int32 -> Expr a -> (i -> Expr a) -> Window i (Expr a)-lagExprOn offset def f = lmap f (lagExpr offset def)----- | [@lead(value, offset, default)@](https://www.postgresql.org/docs/current/functions-window.html)-leadExpr :: Expr Int32 -> Expr a -> Window (Expr a) (Expr a)-leadExpr offset def =-  fromWindowFunction $-    dimap (toColumn . toPrimExpr) (fromPrimExpr . fromColumn) $-      Opaleye.lead (toColumn (toPrimExpr offset)) (toColumn (toPrimExpr def))----- | Applies 'lead' to the column selected by the given function.-leadExprOn :: Expr Int32 -> Expr a -> (i -> Expr a) -> Window i (Expr a)-leadExprOn offset def f = lmap f (leadExpr offset def)----- | [@first_value(value)@](https://www.postgresql.org/docs/current/functions-window.html)-firstValueExpr :: Window (Expr a) (Expr a)-firstValueExpr =-  fromWindowFunction $-    dimap (toColumn . toPrimExpr) (fromPrimExpr . fromColumn)-      Opaleye.firstValue----- | Applies 'firstValue' to the column selected by the given function.-firstValueExprOn :: (i -> Expr a) -> Window i (Expr a)-firstValueExprOn f = lmap f firstValueExpr----- | [@last_value(value)@](https://www.postgresql.org/docs/current/functions-window.html)-lastValueExpr :: Window (Expr a) (Expr a)-lastValueExpr =-  fromWindowFunction $-    dimap (toColumn . toPrimExpr) (fromPrimExpr . fromColumn)-      Opaleye.lastValue----- | Applies 'lastValue' to the column selected by the given function.-lastValueExprOn :: (i -> Expr a) -> Window i (Expr a)-lastValueExprOn f = lmap f lastValueExpr----- | [@nth_value(value, n)@](https://www.postgresql.org/docs/current/functions-window.html)-nthValueExpr :: Expr Int32 -> Window (Expr a) (Expr (Nullify a))-nthValueExpr n =-  fromWindowFunction $-    dimap (toColumn . toPrimExpr) (fromPrimExpr . fromColumn) $-      Opaleye.nthValue (toColumn (toPrimExpr n))----- | [@nth_value(value, n)@](https://www.postgresql.org/docs/current/functions-window.html)-nthValueExprOn :: Expr Int32 -> (i -> Expr a) -> Window i (Expr (Nullify a))-nthValueExprOn n f = lmap f (nthValueExpr n)---fromAggregate :: Aggregator' fold i a -> Opaleye.Aggregator i a-fromAggregate (Aggregator _ a) = a---fromWindowFunction :: Opaleye.WindowFunction i a -> Window i a-fromWindowFunction (Opaleye.WindowFunction (Opaleye.PackMap w)) =-  Window $ Opaleye.Windows $ Opaleye.PackMap $ \f -> w $ \o -> f (o, mempty)
− src/Rel8/FCF.hs
@@ -1,26 +0,0 @@-{-# language DataKinds #-}-{-# language PolyKinds #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}--module Rel8.FCF-  ( Exp, Eval-  , Id-  )-where---- base-import Data.Kind ( Type )-import Prelude ()---type Exp :: Type -> Type-type Exp e = e -> Type---type Eval :: Exp e -> e-type family Eval a---data Id :: a -> Exp a-type instance Eval (Id a) = a
− src/Rel8/Generic/Construction.hs
@@ -1,316 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language ConstraintKinds #-}-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}-{-# language ViewPatterns #-}--module Rel8.Generic.Construction-  ( GGBuildable-  , GGBuild, ggbuild-  , GGConstructable-  , GGConstruct, ggconstruct-  , GGDeconstruct, ggdeconstruct, ggdeconstructA-  , GGName, ggname-  )-where---- base-import Data.Bifunctor ( first )-import Data.Functor ((<&>))-import Data.Kind ( Constraint, Type )-import Data.List.NonEmpty ( NonEmpty( (:|) ) )-import GHC.TypeLits ( Symbol )-import Prelude---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Eq ( (==.) )-import Rel8.Expr.Null ( nullify, snull, unsafeUnnullify )-import Rel8.Expr.Serialize ( litExpr )-import Rel8.FCF ( Eval, Exp, Id )-import Rel8.Generic.Construction.ADT-  ( GConstructorADT, GMakeableADT, gmakeADT-  , GConstructableADT-  , GBuildADT, gbuildADT-  , GConstructADT, gconstructADT, gdeconstructADT-  , RepresentableConstructors, GConstructors, gcindex, gctabulate-  , RepresentableFields, gftabulate-  )-import Rel8.Generic.Construction.Record-  ( GConstructor-  , GConstructable, GConstruct, gconstruct, gdeconstruct-  , Representable, gindex, gtabulate-  )-import Rel8.Generic.Table ( GGColumns )-import Rel8.Kind.Algebra-  ( SAlgebra( SProduct, SSum )-  , KnownAlgebra, algebraSing-  )-import qualified Rel8.Kind.Algebra as K-import Rel8.Schema.HTable ( HTable )-import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Name ( Name( Name ) )-import Rel8.Schema.Null ( Nullity( Null, NotNull ) )-import Rel8.Schema.Spec ( Spec( Spec, nullity, info ) )-import Rel8.Table-  ( TTable, TColumns-  , Table, fromColumns, toColumns-  )-import Rel8.Table.Bool ( case_ )-import Rel8.Type.Tag ( Tag )---- semigroupoids-import Data.Functor.Apply (Apply)-import Data.Semigroup.Traversable (sequence1, traverse1)---type GGBuildable :: K.Algebra -> Symbol -> (K.Context -> Exp (Type -> Type)) -> Constraint-type GGBuildable algebra name rep =-  ( KnownAlgebra algebra-  , Eval (GGColumns algebra TColumns (Eval (rep Expr))) ~ Eval (GGColumns algebra TColumns (Eval (rep Expr)))-  , Eval (GGColumns algebra TColumns (Eval (rep Name))) ~ Eval (GGColumns algebra TColumns (Eval (rep Expr)))-  , HTable (Eval (GGColumns algebra TColumns (Eval (rep Expr))))-  , GGBuildable' algebra name rep-  )---type GGBuildable' :: K.Algebra -> Symbol -> (K.Context -> Exp (Type -> Type)) -> Constraint-type family GGBuildable' algebra name rep where-  GGBuildable' 'K.Product name rep =-    ( name ~ GConstructor (Eval (rep Expr))-    , Representable Id (Eval (rep Expr))-    , GConstructable (TTable Expr) TColumns Id Expr (Eval (rep Expr))-    )-  GGBuildable' 'K.Sum name rep =-    ( Representable Id (GConstructorADT name (Eval (rep Expr)))-    , GMakeableADT (TTable Expr) TColumns Id Expr name (Eval (rep Expr))-    )---type GGBuild :: K.Algebra -> Symbol -> (K.Context -> Exp (Type -> Type)) -> Type -> Type-type family GGBuild algebra name rep r where-  GGBuild 'K.Product _name rep r =-    GConstruct Id (Eval (rep Expr)) r-  GGBuild 'K.Sum name rep r =-    GConstruct Id (GConstructorADT name (Eval (rep Expr))) r---ggbuild :: forall algebra name rep a. GGBuildable algebra name rep-  => (Eval (GGColumns algebra TColumns (Eval (rep Expr))) Expr -> a)-  -> GGBuild algebra name rep a-ggbuild gfromColumns = case algebraSing @algebra of-  SProduct ->-    gtabulate @Id @(Eval (rep Expr)) @a $-    gfromColumns .-    gconstruct-      @(TTable Expr)-      @TColumns-      @Id-      @Expr-      @(Eval (rep Expr))-      (const toColumns)-  SSum ->-    gtabulate @Id @(GConstructorADT name (Eval (rep Expr))) @a $-    gfromColumns .-    gmakeADT-      @(TTable Expr)-      @TColumns-      @Id-      @Expr-      @name-      @(Eval (rep Expr))-      (const toColumns)-      (\Spec {info} -> snull info)-      (\Spec {nullity} -> case nullity of-        Null -> id-        NotNull -> nullify)-      (HIdentity . litExpr)---type GGConstructable :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Constraint-type GGConstructable algebra rep =-  ( KnownAlgebra algebra-  , Eval (GGColumns algebra TColumns (Eval (rep Expr))) ~ Eval (GGColumns algebra TColumns (Eval (rep Expr)))-  , Eval (GGColumns algebra TColumns (Eval (rep Name))) ~ Eval (GGColumns algebra TColumns (Eval (rep Expr)))-  , HTable (Eval (GGColumns algebra TColumns (Eval (rep Expr))))-  , GGConstructable' algebra rep-  )---type GGConstructable' :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Constraint-type family GGConstructable' algebra rep where-  GGConstructable' 'K.Product rep =-    ( Representable Id (Eval (rep Expr))-    , Representable Id (Eval (rep Name))-    , GConstructable (TTable Expr) TColumns Id Expr (Eval (rep Expr))-    , GConstructable (TTable Name) TColumns Id Name (Eval (rep Name))-    )-  GGConstructable' 'K.Sum rep =-    ( RepresentableConstructors Id (Eval (rep Expr))-    , RepresentableFields Id (Eval (rep Expr))-    , RepresentableFields Id (Eval (rep Name))-    , Functor (GConstructors Id (Eval (rep Expr)))-    , GConstructableADT (TTable Expr) TColumns Id Expr (Eval (rep Expr))-    , GConstructableADT (TTable Name) TColumns Id Name (Eval (rep Name))-    )---type GGConstruct :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Type -> Type-type family GGConstruct algebra rep r where-  GGConstruct 'K.Product rep r = GConstruct Id (Eval (rep Expr)) r -> r-  GGConstruct 'K.Sum rep r = GConstructADT Id (Eval (rep Expr)) r r---ggconstruct :: forall algebra rep a. GGConstructable algebra rep-  => (Eval (GGColumns algebra TColumns (Eval (rep Expr))) Expr -> a)-  -> GGConstruct algebra rep a -> a-ggconstruct gfromColumns f = case algebraSing @algebra of-  SProduct ->-    f $-    gtabulate @Id @(Eval (rep Expr)) @a $-    gfromColumns .-    gconstruct-      @(TTable Expr)-      @TColumns-      @Id-      @Expr-      @(Eval (rep Expr))-      (const toColumns)-  SSum ->-    gcindex @Id @(Eval (rep Expr)) @a f $-    fmap gfromColumns $-    gconstructADT-      @(TTable Expr)-      @TColumns-      @Id-      @Expr-      @(Eval (rep Expr))-      (const toColumns)-      (\Spec {info} -> snull info)-      (\Spec {nullity} -> case nullity of-        Null -> id-        NotNull -> nullify)-      (HIdentity . litExpr)---type GGDeconstruct :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Type -> Type -> Type-type family GGDeconstruct algebra rep a r where-  GGDeconstruct 'K.Product rep a r =-    GConstruct Id (Eval (rep Expr)) r -> a -> r-  GGDeconstruct 'K.Sum rep a r =-    GConstructADT Id (Eval (rep Expr)) r (a -> r)---ggdeconstruct :: forall algebra rep a r. (GGConstructable algebra rep, Table Expr r)-  => (a -> Eval (GGColumns algebra TColumns (Eval (rep Expr))) Expr)-  -> GGDeconstruct algebra rep a r-ggdeconstruct gtoColumns = case algebraSing @algebra of-  SProduct -> \build ->-    gindex @Id @(Eval (rep Expr)) @r build .-    gdeconstruct-      @(TTable Expr)-      @TColumns-      @Id-      @Expr-      @(Eval (rep Expr))-      (const fromColumns) .-    gtoColumns-  SSum ->-    gctabulate @Id @(Eval (rep Expr)) @r @(a -> r) $ \constructors as ->-      let-        (HIdentity tag, cases) =-          gdeconstructADT-            @(TTable Expr)-            @TColumns-            @Id-            @Expr-            @(Eval (rep Expr))-            (const fromColumns)-            (\Spec {nullity} -> case nullity of-              Null -> id-              NotNull -> unsafeUnnullify)-            constructors $-          gtoColumns as-      in-        case cases of-          ((_, r) :| (map (first ((tag ==.) . litExpr)) -> cases')) ->-            case_ cases' r---ggdeconstructA :: forall algebra rep a f r. (GGConstructable algebra rep, Apply f, Table Expr r)-  => (a -> Eval (GGColumns algebra TColumns (Eval (rep Expr))) Expr)-  -> GGDeconstruct algebra rep a (f r)-ggdeconstructA gtoColumns = case algebraSing @algebra of-  SProduct -> \build ->-    gindex @Id @(Eval (rep Expr)) @(f r) build .-    gdeconstruct-      @(TTable Expr)-      @TColumns-      @Id-      @Expr-      @(Eval (rep Expr))-      (const fromColumns) .-    gtoColumns-  SSum ->-    gctabulate @Id @(Eval (rep Expr)) @(f r) @(a -> f r) $ \constructors as ->-      let-        (HIdentity tag, cases) =-          gdeconstructADT-            @(TTable Expr)-            @TColumns-            @Id-            @Expr-            @(Eval (rep Expr))-            (const fromColumns)-            (\Spec {nullity} -> case nullity of-              Null -> id-              NotNull -> unsafeUnnullify)-            constructors $-          gtoColumns as-        fcases = traverse1 sequence1 cases-      in-        fcases-          <&> \((_, r) :| (map (first ((tag ==.) . litExpr)) -> cases')) ->-            case_ cases' r---type GGName :: K.Algebra -> (K.Context -> Exp (Type -> Type)) -> Type -> Type-type family GGName algebra rep a where-  GGName 'K.Product rep a = GConstruct Id (Eval (rep Name)) a-  GGName 'K.Sum rep a = Name Tag -> GBuildADT Id (Eval (rep Name)) a---ggname :: forall algebra rep a. GGConstructable algebra rep-  => (Eval (GGColumns algebra TColumns (Eval (rep Expr))) Name -> a)-  -> GGName algebra rep a-ggname gfromColumns = case algebraSing @algebra of-  SProduct ->-    gtabulate @Id @(Eval (rep Name)) @a $-    gfromColumns .-    gconstruct-      @(TTable Name)-      @TColumns-      @Id-      @Name-      @(Eval (rep Name))-      (const toColumns)-  SSum -> \tag ->-    gftabulate @Id @(Eval (rep Name)) @a $-    gfromColumns .-    gbuildADT-      @(TTable Name)-      @TColumns-      @Id-      @Name-      @(Eval (rep Name))-      (const toColumns)-      (\_ _ (Name a) -> Name a)-      (HIdentity tag)
− src/Rel8/Generic/Construction/ADT.hs
@@ -1,478 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language BlockArguments #-}-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language RankNTypes #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TupleSections #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Generic.Construction.ADT-  ( GConstructableADT-  , GBuildADT, gbuildADT, gunbuildADT-  , GConstructADT, gconstructADT, gdeconstructADT-  , GFields, RepresentableFields, gftabulate, gfindex-  , GConstructors, RepresentableConstructors, gctabulate, gcindex-  , GConstructorADT, GMakeableADT, gmakeADT-  )-where---- base-import Data.Bifunctor ( first )-import Data.Functor.Identity ( runIdentity )-import Data.Kind ( Constraint, Type )-import Data.List.NonEmpty ( NonEmpty )-import Data.Proxy ( Proxy( Proxy ) )-import GHC.Generics-  ( (:+:), (:*:)( (:*:) ), M1, U1-  , C, D-  , Meta( MetaData, MetaCons )-  )-import GHC.TypeLits-  ( ErrorMessage( (:<>:), Text ), TypeError-  , Symbol, KnownSymbol, symbolVal-  )-import Prelude hiding ( null )---- rel8-import Rel8.FCF ( Exp )-import Rel8.Generic.Construction.Record-  ( GConstruct, GConstructable, gconstruct, gdeconstruct-  , GFields, Representable, gtabulate, gindex-  , FromColumns, ToColumns-  )-import Rel8.Generic.Table.ADT ( GColumnsADT, GColumnsADT' )-import Rel8.Generic.Table.Record ( GColumns )-import Rel8.Schema.HTable ( HTable )-import Rel8.Schema.HTable.Identity ( HIdentity )-import Rel8.Schema.HTable.Label ( HLabel, hlabel, hunlabel )-import Rel8.Schema.HTable.Nullify ( HNullify, hnulls, hnullify, hunnullify )-import Rel8.Schema.HTable.Product ( HProduct( HProduct ) )-import Rel8.Schema.Null ( Nullify )-import Rel8.Schema.Spec ( Spec )-import qualified Rel8.Schema.Kind as K-import Rel8.Type.Tag ( Tag( Tag ) )---- text-import Data.Text ( pack )---type Null :: K.Context -> Type-type Null context = forall a. Spec a -> context (Nullify a)---type Nullifier :: K.Context -> Type-type Nullifier context = forall a. Spec a -> context a -> context (Nullify a)---type Unnullifier :: K.Context -> Type-type Unnullifier context = forall a. Spec a -> context (Nullify a) -> context a---type NoConstructor :: Symbol -> Symbol -> ErrorMessage-type NoConstructor datatype constructor =-  ( 'Text "The type `" ' :<>:-    'Text datatype ' :<>:-    'Text "` has no constructor `" ' :<>:-    'Text constructor ' :<>:-    'Text "`."-  )---type GConstructorADT :: Symbol -> (Type -> Type) -> Type -> Type-type family GConstructorADT name rep where-  GConstructorADT name (M1 D ('MetaData datatype _ _ _) rep) =-    GConstructorADT' name rep (TypeError (NoConstructor datatype name))---type GConstructorADT' :: Symbol -> (Type -> Type) -> (Type -> Type) -> Type -> Type-type family GConstructorADT' name rep fallback where-  GConstructorADT' name (M1 D _ rep) fallback =-    GConstructorADT' name rep fallback-  GConstructorADT' name (a :+: b) fallback =-    GConstructorADT' name a (GConstructorADT' name b fallback)-  GConstructorADT' name (M1 C ('MetaCons name _ _) rep) _ = rep-  GConstructorADT' _ _ fallback = fallback---type GConstructADT-  :: (Type -> Exp Type)-  -> (Type -> Type) -> Type -> Type -> Type-type family GConstructADT f rep r x where-  GConstructADT f (M1 D _ rep) r x = GConstructADT f rep r x-  GConstructADT f (a :+: b) r x = GConstructADT f a r (GConstructADT f b r x)-  GConstructADT f (M1 C _ rep) r x = GConstruct f rep r -> x---type GConstructors :: (Type -> Exp Type) -> (Type -> Type) -> Type -> Type-type family GConstructors f rep where-  GConstructors f (M1 D _ rep) = GConstructors f rep-  GConstructors f (a :+: b) = GConstructors f a :*: GConstructors f b-  GConstructors f (M1 C _ rep) = (->) (GFields f rep)---type RepresentableConstructors :: (Type -> Exp Type) -> (Type -> Type) -> Constraint-class RepresentableConstructors f rep where-  gctabulate :: (GConstructors f rep r -> a) -> GConstructADT f rep r a-  gcindex :: GConstructADT f rep r a -> GConstructors f rep r -> a---instance RepresentableConstructors f rep => RepresentableConstructors f (M1 D meta rep) where-  gctabulate = gctabulate @f @rep-  gcindex = gcindex @f @rep---instance (RepresentableConstructors f a, RepresentableConstructors f b) =>-  RepresentableConstructors f (a :+: b)- where-  gctabulate f =-    gctabulate @f @a \a -> gctabulate @f @b \b -> f (a :*: b)-  gcindex f (a :*: b) = gcindex @f @b (gcindex @f @a f a) b---instance Representable f rep => RepresentableConstructors f (M1 C meta rep) where-  gctabulate f = f . gindex @f @rep-  gcindex f = f . gtabulate @f @rep---type GBuildADT :: (Type -> Exp Type) -> (Type -> Type) -> Type -> Type-type family GBuildADT f rep r where-  GBuildADT f (M1 D _ rep) r = GBuildADT f rep r-  GBuildADT f (a :+: b) r = GBuildADT f a (GBuildADT f b r)-  GBuildADT f (M1 C _ rep) r = GConstruct f rep r---type GFieldsADT :: (Type -> Exp Type) -> (Type -> Type) -> Type-type family GFieldsADT f rep where-  GFieldsADT f (M1 D _ rep) = GFieldsADT f rep-  GFieldsADT f (a :+: b) = (GFieldsADT f a, GFieldsADT f b)-  GFieldsADT f (M1 C _ rep) = GFields f rep---type RepresentableFields :: (Type -> Exp Type) -> (Type -> Type) -> Constraint-class RepresentableFields f rep where-  gftabulate :: (GFieldsADT f rep -> a) -> GBuildADT f rep a-  gfindex :: GBuildADT f rep a -> GFieldsADT f rep -> a---instance RepresentableFields f rep => RepresentableFields f (M1 D meta rep) where-  gftabulate = gftabulate @f @rep-  gfindex = gfindex @f @rep---instance (RepresentableFields f a, RepresentableFields f b) => RepresentableFields f (a :+: b) where-  gftabulate f =-    gftabulate @f @a \a -> gftabulate @f @b \b -> f (a, b)-  gfindex f (a, b) = gfindex @f @b (gfindex @f @a f a) b---instance Representable f rep => RepresentableFields f (M1 C meta rep) where-  gftabulate = gtabulate @f @rep-  gfindex = gindex @f @rep---type GConstructableADT-  :: (Type -> Exp Constraint)-  -> (Type -> Exp K.HTable)-  -> (Type -> Exp Type)-  -> K.Context -> (Type -> Type) -> Constraint-class GConstructableADT _Table _Columns f context rep where-  gbuildADT :: ()-    => ToColumns _Table _Columns f context-    -> (Tag -> Nullifier context)-    -> HIdentity Tag context-    -> GFieldsADT f rep-    -> GColumnsADT _Columns rep context--  gunbuildADT :: ()-    => FromColumns _Table _Columns f context-    -> Unnullifier context-    -> GColumnsADT _Columns rep context-    -> (HIdentity Tag context, GFieldsADT f rep)--  gconstructADT :: ()-    => ToColumns _Table _Columns f context-    -> Null context-    -> Nullifier context-    -> (Tag -> HIdentity Tag context)-    -> GConstructors f rep (GColumnsADT _Columns rep context)--  gdeconstructADT :: ()-    => FromColumns _Table _Columns f context-    -> Unnullifier context-    -> GConstructors f rep r-    -> GColumnsADT _Columns rep context-    -> (HIdentity Tag context, NonEmpty (Tag, r))---instance-  ( htable ~ HLabel "tag" (HIdentity Tag)-  , GConstructableADT' _Table _Columns f context htable rep-  )-  => GConstructableADT _Table _Columns f context (M1 D meta rep)- where-  gbuildADT toColumns nullifier =-    gbuildADT' @_Table @_Columns @f @context @htable @rep toColumns nullifier .-    hlabel--  gunbuildADT fromColumns unnullifier =-    first hunlabel .-    gunbuildADT' @_Table @_Columns @f @context @htable @rep fromColumns unnullifier--  gconstructADT toColumns null nullifier mk =-    gconstructADT' @_Table @_Columns @f @context @htable @rep toColumns null nullifier-      (hlabel . mk)--  gdeconstructADT fromColumns unnullifier cases =-    first hunlabel .-    gdeconstructADT' @_Table @_Columns @f @context @htable @rep fromColumns unnullifier cases---type GConstructableADT'-  :: (Type -> Exp Constraint)-  -> (Type -> Exp K.HTable)-  -> (Type -> Exp Type)-  -> K.Context -> K.HTable -> (Type -> Type) -> Constraint-class GConstructableADT' _Table _Columns f context htable rep where-  gbuildADT' :: ()-    => ToColumns _Table _Columns f context-    -> (Tag -> Nullifier context)-    -> htable context-    -> GFieldsADT f rep-    -> GColumnsADT' _Columns htable rep context--  gunbuildADT' :: ()-    => FromColumns _Table _Columns f context-    -> Unnullifier context-    -> GColumnsADT' _Columns htable rep context-    -> (htable context, GFieldsADT f rep)--  gconstructADT' :: ()-    => ToColumns _Table _Columns f context-    -> Null context-    -> Nullifier context-    -> (Tag -> htable context)-    -> GConstructors f rep (GColumnsADT' _Columns htable rep context)--  gdeconstructADT' :: ()-    => FromColumns _Table _Columns f context-    -> Unnullifier context-    -> GConstructors f rep r-    -> GColumnsADT' _Columns htable rep context-    -> (htable context, NonEmpty (Tag, r))--  gfill :: ()-    => Null context-    -> htable context-    -> GColumnsADT' _Columns htable rep context---instance-  ( htable' ~ GColumnsADT' _Columns htable a-  , Functor (GConstructors f a)-  , GConstructableADT' _Table _Columns f context htable a-  , GConstructableADT' _Table _Columns f context htable' b-  )-  => GConstructableADT' _Table _Columns f context htable (a :+: b)- where-  gbuildADT' toColumns nullifier htable (a, b) =-    gbuildADT' @_Table @_Columns @f @context @htable' @b toColumns nullifier-      (gbuildADT' @_Table @_Columns @f @context @htable @a toColumns nullifier htable a)-      b--  gunbuildADT' fromColumns unnullifier columns =-    case gunbuildADT' @_Table @_Columns @f @context @htable' @b fromColumns unnullifier columns of-      (htable', b) ->-        case gunbuildADT' @_Table @_Columns @f @context @htable @a fromColumns unnullifier htable' of-          (htable, a) -> (htable, (a, b))--  gconstructADT' toColumns null nullifier mk =-    fmap (gfill @_Table @_Columns @f @context @htable' @b null) (gconstructADT' @_Table @_Columns @f @context @htable @a toColumns null nullifier mk) :*:-    gconstructADT' @_Table @_Columns @f @context @htable' @b toColumns null nullifier (gfill @_Table @_Columns @f @context @htable @a null . mk)--  gdeconstructADT' fromColumns unnullifier (a :*: b) columns =-    case gdeconstructADT' @_Table @_Columns @f @context @htable' @b fromColumns unnullifier b columns of-      (htable', cases) ->-        case gdeconstructADT' @_Table @_Columns @f @context @htable @a fromColumns unnullifier a htable' of-          (htable, cases') -> (htable, cases' <> cases)--  gfill null =-    gfill @_Table @_Columns @f @context @htable' @b null .-    gfill @_Table @_Columns @f @context @htable @a null---instance (meta ~ 'MetaCons label _fixity _isRecord, KnownSymbol label) =>-  GConstructableADT' _Table _Columns f context htable (M1 C meta U1)- where-  gbuildADT' _ _ = const-  gunbuildADT' _ _ = (, ())-  gconstructADT' _ _ _ f _ = f tag-    where-      tag = Tag $ pack $ symbolVal (Proxy @label)-  gdeconstructADT' _ _ r htable = (htable, pure (tag, r ()))-    where-      tag = Tag $ pack $ symbolVal (Proxy @label)-  gfill _ = id---instance {-# OVERLAPPABLE #-}-  ( HTable (GColumns _Columns rep)-  , KnownSymbol label-  , meta ~ 'MetaCons label _fixity _isRecord-  , GConstructable _Table _Columns f context rep-  , GColumnsADT' _Columns htable (M1 C meta rep) ~-      HProduct htable (HLabel label (HNullify (GColumns _Columns rep)))-  )-  => GConstructableADT' _Table _Columns f context htable (M1 C meta rep)- where-  gbuildADT' toColumns nullifier htable =-    HProduct htable .-    hlabel .-    hnullify (nullifier tag) .-    gconstruct @_Table @_Columns @f @context @rep toColumns-    where-      tag = Tag $ pack $ symbolVal (Proxy @label)--  gunbuildADT' fromColumns unnullifier (HProduct htable a) =-    ( htable-    , gdeconstruct @_Table @_Columns @f @context @rep fromColumns $-        runIdentity $-        hunnullify (\spec -> pure . unnullifier spec) $-        hunlabel-        a-    )--  gconstructADT' toColumns _ nullifier mk =-    HProduct htable .-    hlabel .-    hnullify nullifier .-    gconstruct @_Table @_Columns @f @context @rep toColumns-    where-      tag = Tag $ pack $ symbolVal (Proxy @label)-      htable = mk tag--  gdeconstructADT' fromColumns unnullifier r (HProduct htable columns) =-    ( htable-    , pure (tag, r a)-    )-    where-      a = gdeconstruct @_Table @_Columns @f @context @rep fromColumns $-        runIdentity $-        hunnullify (\spec -> pure . unnullifier spec) $-        hunlabel-        columns-      tag = Tag $ pack $ symbolVal (Proxy @label)--  gfill null htable = HProduct htable (hlabel (hnulls null))---type GMakeableADT-  :: (Type -> Exp Constraint)-  -> (Type -> Exp K.HTable)-  -> (Type -> Exp Type)-  -> K.Context -> Symbol -> (Type -> Type) -> Constraint-class GMakeableADT _Table _Columns f context name rep where-  gmakeADT :: ()-    => ToColumns _Table _Columns f context-    -> Null context-    -> Nullifier context-    -> (Tag -> HIdentity Tag context)-    -> GFields f (GConstructorADT name rep)-    -> GColumnsADT _Columns rep context---instance-  ( htable ~ HLabel "tag" (HIdentity Tag)-  , meta ~ 'MetaData datatype _module _package _newtype-  , fallback ~ TypeError (NoConstructor datatype name)-  , fields ~ GFields f (GConstructorADT' name rep fallback)-  , GMakeableADT' _Table _Columns f context htable name rep fields-  , KnownSymbol name-  )-  => GMakeableADT _Table _Columns f context name (M1 D meta rep)- where-  gmakeADT toColumns null nullifier wrap =-    gmakeADT'-      @_Table @_Columns @f @context @htable @name @rep @fields-      toColumns null nullifier htable-    where-      tag = Tag $ pack $ symbolVal (Proxy @name)-      htable = hlabel (wrap tag)---type GMakeableADT'-  :: (Type -> Exp Constraint)-  -> (Type -> Exp K.HTable)-  -> (Type -> Exp Type)-  -> K.Context -> K.HTable -> Symbol -> (Type -> Type) -> Type -> Constraint-class GMakeableADT' _Table _Columns f context htable name rep fields where-  gmakeADT' :: ()-    => ToColumns _Table _Columns f context-    -> Null context-    -> Nullifier context-    -> htable context-    -> fields-    -> GColumnsADT' _Columns htable rep context---instance-  ( htable' ~ GColumnsADT' _Columns htable a-  , GMakeableADT' _Table _Columns f context htable name a fields-  , GMakeableADT' _Table _Columns f context htable' name b fields-  )-  => GMakeableADT' _Table _Columns f context htable name (a :+: b) fields- where-  gmakeADT' toColumns null nullifier htable x =-    gmakeADT' @_Table @_Columns @f @context @htable' @name @b @fields-      toColumns null nullifier-      (gmakeADT'-         @_Table @_Columns @f @context @htable @name @a @fields toColumns-         null nullifier htable x)-      x---instance {-# OVERLAPPING #-}-  GMakeableADT' _Table _Columns f context htable name (M1 C ('MetaCons name _fixity _isRecord) U1) fields- where-  gmakeADT' _ _ _ = const---instance {-# OVERLAPS #-}-  GMakeableADT' _Table _Columns f context htable name (M1 C ('MetaCons label _fixity _isRecord) U1) fields- where-  gmakeADT' _ _ _ = const---instance {-# OVERLAPS #-}-  ( HTable (GColumns _Columns rep)-  , GConstructable _Table _Columns f context rep-  , fields ~ GFields f rep-  , GColumnsADT' _Columns htable (M1 C ('MetaCons name _fixity _isRecord) rep) ~-      HProduct htable (HLabel name (HNullify (GColumns _Columns rep)))-  )-  => GMakeableADT' _Table _Columns f context htable name (M1 C ('MetaCons name _fixity _isRecord) rep) fields- where-  gmakeADT' toColumns _ nullifier htable =-    HProduct htable .-    hlabel .-    hnullify nullifier .-    gconstruct @_Table @_Columns @f @context @rep toColumns---instance {-# OVERLAPPABLE #-}-  ( HTable (GColumns _Columns rep)-  , GColumnsADT' _Columns htable (M1 C ('MetaCons label _fixity _isRecord) rep) ~-      HProduct htable (HLabel label (HNullify (GColumns _Columns rep)))-  )-  => GMakeableADT' _Table _Columns f context htable name (M1 C ('MetaCons label _fixity _isRecord) rep) fields- where-  gmakeADT' _ null _ htable _ =-    HProduct htable $-    hlabel $-    hnulls null
− src/Rel8/Generic/Construction/Record.hs
@@ -1,168 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language BlockArguments #-}-{-# language DataKinds #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language RankNTypes #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Generic.Construction.Record-  ( GConstructor, GConstruct, GConstructable, gconstruct, gdeconstruct-  , GFields, Representable, gtabulate, gindex-  , FromColumns, ToColumns-  )-where---- base-import Data.Kind ( Constraint, Type )-import Data.Proxy ( Proxy( Proxy ) )-import GHC.Generics-  ( (:*:), K1, M1, U1-  , D, C, S, Meta( MetaData, MetaCons, MetaSel )-  )-import GHC.TypeLits-  ( ErrorMessage( (:<>:), Text ), TypeError-  , Symbol-  )-import Prelude---- rel8-import Rel8.FCF ( Eval, Exp )-import Rel8.Generic.Table.Record ( GColumns )-import Rel8.Schema.HTable.Label ( hlabel, hunlabel )-import Rel8.Schema.HTable.Product ( HProduct( HProduct ) )-import qualified Rel8.Schema.Kind as K---type FromColumns-  :: (Type -> Exp Constraint)-  -> (Type -> Exp K.HTable)-  -> (Type -> Exp Type)-  -> K.Context-  -> Type-type FromColumns _Table _Columns f context = forall proxy x.-  Eval (_Table x) => proxy x -> Eval (_Columns x) context -> Eval (f x)---type ToColumns-  :: (Type -> Exp Constraint)-  -> (Type -> Exp K.HTable)-  -> (Type -> Exp Type)-  -> K.Context-  -> Type-type ToColumns _Table _Columns f context = forall proxy x.-  Eval (_Table x) => proxy x -> Eval (f x) -> Eval (_Columns x) context---type GConstructor :: (Type -> Type) -> Symbol-type family GConstructor rep where-  GConstructor (M1 D _ (M1 C ('MetaCons name _ _) _)) = name-  GConstructor (M1 D ('MetaData name _ _ _) _) = TypeError (-    'Text "`" ' :<>:-    'Text name ' :<>:-    'Text "` does not appear to have exactly 1 constructor"-   )---type GConstruct :: (Type -> Exp Type) -> (Type -> Type) -> Type -> Type-type family GConstruct f rep r where-  GConstruct f (M1 _ _ rep) r = GConstruct f rep r-  GConstruct f (a :*: b) r = GConstruct f a (GConstruct f b r)-  GConstruct _ U1 r = r-  GConstruct f (K1 _ a) r = Eval (f a) -> r---type GFields :: (Type -> Exp Type) -> (Type -> Type) -> Type-type family GFields f rep where-  GFields f (M1 _ _ rep) = GFields f rep-  GFields f (a :*: b) = (GFields f a, GFields f b)-  GFields _ U1 = ()-  GFields f (K1 _ a) = Eval (f a)---type Representable :: (Type -> Exp Type) -> (Type -> Type) -> Constraint-class Representable f rep where-  gtabulate :: (GFields f rep -> a) -> GConstruct f rep a-  gindex :: GConstruct f rep a -> GFields f rep -> a---instance Representable f rep => Representable f (M1 i meta rep) where-  gtabulate = gtabulate @f @rep-  gindex = gindex @f @rep---instance (Representable f a, Representable f b) =>-  Representable f (a :*: b)- where-  gtabulate f = gtabulate @f @a \a -> gtabulate @f @b \b -> f (a, b)-  gindex f (a, b) = gindex @f @b (gindex @f @a f a) b---instance Representable f U1 where-  gtabulate = ($ ())-  gindex = const---instance Representable f (K1 i a) where-  gtabulate = id-  gindex = id---type GConstructable-  :: (Type -> Exp Constraint)-  -> (Type -> Exp K.HTable)-  -> (Type -> Exp Type)-  -> K.Context -> (Type -> Type) -> Constraint-class GConstructable _Table _Columns f context rep where-  gconstruct :: ()-    => ToColumns _Table _Columns f context-    -> GFields f rep-    -> GColumns _Columns rep context-  gdeconstruct :: ()-    => FromColumns _Table _Columns f context-    -> GColumns _Columns rep context-    -> GFields f rep---instance (GConstructable _Table _Columns f context rep) =>-  GConstructable _Table _Columns f context (M1 D meta rep)- where-  gconstruct = gconstruct @_Table @_Columns @f @context @rep-  gdeconstruct = gdeconstruct @_Table @_Columns @f @context @rep---instance (GConstructable _Table _Columns f context rep) =>-  GConstructable _Table _Columns f context (M1 C meta rep)- where-  gconstruct = gconstruct @_Table @_Columns @f @context @rep-  gdeconstruct = gdeconstruct @_Table @_Columns @f @context @rep---instance-  ( GConstructable _Table _Columns f context a-  , GConstructable _Table _Columns f context b-  )-  => GConstructable _Table _Columns f context (a :*: b)- where-  gconstruct toColumns (a, b) = HProduct-    (gconstruct @_Table @_Columns @f @context @a toColumns a)-    (gconstruct @_Table @_Columns @f @context @b toColumns b)-  gdeconstruct fromColumns (HProduct a b) =-    ( gdeconstruct @_Table @_Columns @f @context @a fromColumns a-    , gdeconstruct @_Table @_Columns @f @context @b fromColumns b-    )---instance-  ( Eval (_Table a)-  , meta ~ 'MetaSel ('Just label) _su _ss _ds-  )-  => GConstructable _Table _Columns f context (M1 S meta (K1 i a))- where-  gconstruct toColumns = hlabel . toColumns (Proxy @a)-  gdeconstruct fromColumns = fromColumns (Proxy @a) . hunlabel
− src/Rel8/Generic/Map.hs
@@ -1,49 +0,0 @@-{-# language DataKinds #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Generic.Map-  ( GMap-  , Map-  )-where---- base-import Data.Kind ( Type )-import GHC.Generics-  ( (:+:), (:*:), K1, M1, U1, V1-  )-import Prelude ()---- rel8-import Rel8.FCF ( Eval, Exp )---type GMap :: (Type -> Exp Type) -> (Type -> Type) -> Type -> Type-type family GMap f rep where-  GMap f (M1 i c rep) = M1 i c (GMap f rep)-  GMap _ V1 = V1-  GMap f (rep1 :+: rep2) = GMap f rep1 :+: GMap f rep2-  GMap _ U1 = U1-  GMap f (rep1 :*: rep2) = GMap f rep1 :*: GMap f rep2-  GMap f (K1 i a) = K1 i (Eval (f a))----- | Map a @Type -> Type@ function over the @Type@-kinded type variables in--- of a type constructor.-type Map :: (Type -> Exp Type) -> Type -> Type-type family Map f a where-  Map p (t a b c d e f g) =-    t (Eval (p a)) (Eval (p b)) (Eval (p c)) (Eval (p d)) (Eval (p e))-      (Eval (p f)) (Eval (p g))-  Map p (t a b c d e f) =-    t (Eval (p a)) (Eval (p b)) (Eval (p c)) (Eval (p d)) (Eval (p e))-      (Eval (p f))-  Map p (t a b c d e) =-    t (Eval (p a)) (Eval (p b)) (Eval (p c)) (Eval (p d)) (Eval (p e))-  Map p (t a b c d) = t (Eval (p a)) (Eval (p b)) (Eval (p c)) (Eval (p d))-  Map p (t a b c) = t (Eval (p a)) (Eval (p b)) (Eval (p c))-  Map p (t a b) = t (Eval (p a)) (Eval (p b))-  Map p (t a) = t (Eval (p a))
− src/Rel8/Generic/Record.hs
@@ -1,155 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language PolyKinds #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Generic.Record-  ( Record(..)-  , GRecordable, GRecord, grecord, gunrecord-  )-where---- base-import Data.Kind ( Constraint, Type )-import GHC.Generics-  ( Generic, Rep, from, to-  , (:+:)( L1, R1 ), (:*:)( (:*:) ), M1( M1 )-  , Meta( MetaCons, MetaSel ), D, C, S-  )-import GHC.TypeLits ( type (+), AppendSymbol, Div, Mod, Nat, Symbol )-import Prelude hiding ( Show )---type GRecord :: (Type -> Type) -> Type -> Type-type family GRecord rep where-  GRecord (M1 D meta rep) = M1 D meta (GRecord rep)-  GRecord (l :+: r) = GRecord l :+: GRecord r-  GRecord (M1 C ('MetaCons name fixity 'False) rep) =-    M1 C ('MetaCons name fixity 'True) (Snd (Count 0 rep))-  GRecord rep = rep---type Count :: Nat -> (Type -> Type) -> (Nat, Type -> Type)-type family Count n rep where-  Count n (M1 S ('MetaSel _selector su ss ds) rep) =-    '(n + 1, M1 S ('MetaSel ('Just (Show (n + 1))) su ss ds) rep)-  Count n (a :*: b) = CountHelper1 (Count n a) b-  Count n rep = '(n, rep)---type CountHelper1 :: (Nat, Type -> Type) -> (Type -> Type) -> (Nat, Type -> Type)-type family CountHelper1 tuple b where-  CountHelper1 '(n, a) b = CountHelper2 a (Count n b)---type CountHelper2 :: (Type -> Type) -> (Nat, Type -> Type) -> (Nat, Type -> Type)-type family CountHelper2 a tuple where-  CountHelper2 a '(n, b) = '(n, a :*: b)---type Show :: Nat -> Symbol-type Show n =-  AppendSymbol "_" (AppendSymbol (Show' (Div n 10)) (ShowDigit (Mod n 10)))---type Show' :: Nat -> Symbol-type family Show' n where-  Show' 0 = ""-  Show' n = AppendSymbol (Show' (Div n 10)) (ShowDigit (Mod n 10))---type ShowDigit :: Nat -> Symbol-type family ShowDigit n where-  ShowDigit 0 = "0"-  ShowDigit 1 = "1"-  ShowDigit 2 = "2"-  ShowDigit 3 = "3"-  ShowDigit 4 = "4"-  ShowDigit 5 = "5"-  ShowDigit 6 = "6"-  ShowDigit 7 = "7"-  ShowDigit 8 = "8"-  ShowDigit 9 = "9"---type Snd :: (a, b) -> b-type family Snd tuple where-  Snd '(_a, b) = b---type GRecordable :: (Type -> Type) -> Constraint-class GRecordable rep where-  grecord :: rep x -> GRecord rep x-  gunrecord :: GRecord rep x -> rep x---instance GRecordable rep => GRecordable (M1 D meta rep) where-  grecord (M1 a) = M1 (grecord a)-  gunrecord (M1 a) = M1 (gunrecord a)---instance (GRecordable l, GRecordable r) => GRecordable (l :+: r) where-  grecord (L1 a) = L1 (grecord a)-  grecord (R1 a) = R1 (grecord a)-  gunrecord (L1 a) = L1 (gunrecord a)-  gunrecord (R1 a) = R1 (gunrecord a)---instance Countable 0 rep =>-  GRecordable (M1 C ('MetaCons name fixity 'False) rep)- where-  grecord (M1 a) = M1 (count @0 a)-  gunrecord (M1 a) = M1 (uncount @0 a)---instance {-# OVERLAPPABLE #-} GRecord rep ~ rep => GRecordable rep where-  grecord = id-  gunrecord = id---type Countable :: Nat -> (Type -> Type) -> Constraint-class Countable n rep where-  count :: rep x -> Snd (Count n rep) x-  uncount :: Snd (Count n rep) x -> rep x---instance Countable n (M1 S ('MetaSel selector su ss ds) rep) where-  count (M1 a) = M1 a-  uncount (M1 a) = M1 a---instance-  ( Countable n a, Countable n' b-  , '(n', a') ~ Count n a-  , Snd (CountHelper2 a' (Count n' b)) ~ (a' :*: Snd (Count n' b))-  )-  => Countable n (a :*: b)- where-  count (a :*: b) = count @n a :*: count @n' b-  uncount (a :*: b) = uncount @n a :*: uncount @n' b---instance {-# OVERLAPPABLE #-} Snd (Count n rep) ~ rep => Countable n rep where-  count = id-  uncount = id---type Record :: Type -> Type-newtype Record a = Record-  { unrecord :: a-  }---instance (Generic a, GRecordable (Rep a)) => Generic (Record a) where-  type Rep (Record a) = GRecord (Rep a)--  from (Record a) = grecord (from a)-  to = Record . to . gunrecord
− src/Rel8/Generic/Rel8able.hs
@@ -1,288 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language ConstraintKinds #-}-{-# language DataKinds #-}-{-# language DefaultSignatures #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language LambdaCase #-}-{-# language MultiParamTypeClasses #-}-{-# language PolyKinds #-}-{-# language QuantifiedConstraints #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilyDependencies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Generic.Rel8able-  ( KRel8able, Rel8able-  , Algebra-  , GRep-  , GColumns, gfromColumns, gtoColumns-  , GFromExprs, gfromResult, gtoResult-  , TSerialize, serialize, deserialize-  )-where---- base-import Data.Functor.Identity ( Identity )-import Data.Kind ( Constraint, Type )-import Data.Type.Bool ( type (&&) )-import GHC.Generics ( Generic, Rep, from, to )-import Prelude---- rel8-import Rel8.Expr ( Expr )-import Rel8.FCF ( Exp, Eval )-import Rel8.Generic.Record ( Record(..) )-import Rel8.Generic.Table ( GAlgebra )-import qualified Rel8.Generic.Table.Record as G-import qualified Rel8.Kind.Algebra as K ( Algebra(..) )-import Rel8.Kind.Context ( SContext(..) )-import Rel8.Schema.Field ( Field )-import Rel8.Schema.HTable ( HTable )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Name ( Name )-import Rel8.Schema.Result ( Result )-import Rel8.Table-  ( Table, Columns, Context, fromColumns, toColumns-  , FromExprs, fromResult, toResult-  , Transpose-  , TTable, TColumns-  )-import Rel8.Table.Transpose ( Transposes )----- | The kind of 'Rel8able' types-type KRel8able :: Type-type KRel8able = K.Rel8able----- This is almost 'Data.Type.Equality.==', but we add an extra case.-type (==) :: k -> k -> Bool-type family a == b where-  -- This extra case is needed to solve the equation "a == a" (where a is a-  -- KRel8able), which occurs when we have polymorphic Rel8ables-  -- (e.g., newtype T t f = T { x :: t a })-  (a :: KRel8able) == (a :: KRel8able) = 'True--  -- This extra case is needed to solve the equation "a == Identity a", -  -- which occurs when we have polymorphic Rel8ables -  -- (e.g., newtype T a f = T { x :: Column f a })-  a == Identity a = 'False-  -  -- These cases are exactly the same as those in 'Data.Type.Equality.==.-  f a == g b = f == g && a == b-  a == a = 'True-  _ == _ = 'False---type Serialize :: Bool -> Type -> Type -> Constraint-class transposition ~ (a == Transpose Result expr) =>-  Serialize transposition expr a- where-  serialize :: a -> Columns expr Result-  deserialize :: Columns expr Result -> a---instance-  ( (a == Transpose Result expr) ~ 'True-  , Transposes Expr Result expr a-  )-  => Serialize 'True expr a- where-  serialize = toColumns-  deserialize = fromColumns---instance-  ( (a == Transpose Result expr) ~ 'False-  , Table (Context expr) expr-  , FromExprs expr ~ a-  )-  => Serialize 'False expr a- where-  serialize = toResult @_ @expr-  deserialize = fromResult @_ @expr---data TSerialize :: Type -> Type -> Exp Constraint-type instance Eval (TSerialize expr a) =-  Serialize (a == Transpose Result expr) expr a----- | This type class allows you to define custom 'Table's using higher-kinded--- data types. Higher-kinded data types are data types of the pattern:------ @--- data MyType f =---   MyType { field1 :: Column f T1 OR HK1 f---          , field2 :: Column f T2 OR HK2 f---          , ...---          , fieldN :: Column f Tn OR HKn f---          }--- @------ where @Tn@ is any Haskell type, and @HKn@ is any higher-kinded type.------ That is, higher-kinded data are records where all fields in the record are--- all either of the type @Column f T@ (for any @T@), or are themselves--- higher-kinded data:------ [Nested]------ @--- data Nested f =---   Nested { nested1 :: MyType f---          , nested2 :: MyType f---          }--- @------ The @Rel8able@ type class is used to give us a special mapping operation--- that lets us change the type parameter @f@.------ [Supplying @Rel8able@ instances]------ This type class should be derived generically for all table types in your--- project. To do this, enable the @DeriveAnyClass@ and @DeriveGeneric@ language--- extensions:------ @--- \{\-\# LANGUAGE DeriveAnyClass, DeriveGeneric #-\}------ data MyType f = MyType { fieldA :: Column f T }---   deriving ( GHC.Generics.Generic, Rel8able )--- @-type Rel8able :: K.Rel8able -> Constraint-class HTable (GColumns t) => Rel8able t where-  type GColumns t :: K.HTable-  type GFromExprs t :: Type--  gfromColumns :: SContext context -> GColumns t context -> t context-  gtoColumns :: SContext context -> t context -> GColumns t context--  gfromResult :: GColumns t Result -> GFromExprs t-  gtoResult :: GFromExprs t -> GColumns t Result--  type GColumns t = G.GColumns TColumns (GRep t Expr)-  type GFromExprs t = t Result--  {-# NOINLINE gfromColumns #-} -- See Note [Generics and Inlining]-  default gfromColumns :: forall context.-    ( SRel8able t Expr-    , forall table. SRel8able t (Field table)-    , SRel8able t Name-    , SSerialize t-    )-    => SContext context -> GColumns t context -> t context-  gfromColumns = \case-    SExpr -> sfromColumns-    SField -> sfromColumns-    SName -> sfromColumns-    SResult -> sfromResult--  {-# NOINLINE gtoColumns #-} -- See Note [Generics and Inlining]-  default gtoColumns :: forall context.-    ( SRel8able t Expr-    , forall table. SRel8able t (Field table)-    , SRel8able t Name-    , SSerialize t-    )-    => SContext context -> t context -> GColumns t context-  gtoColumns = \case-    SExpr -> stoColumns-    SField -> stoColumns-    SName -> stoColumns-    SResult -> stoResult--  {-# NOINLINE gfromResult #-} -- See Note [Generics and Inlining]-  default gfromResult :: (SSerialize t, GFromExprs t ~ t Result)-    => GColumns t Result -> GFromExprs t-  gfromResult = sfromResult--  {-# NOINLINE gtoResult #-} -- See Note [Generics and Inlining]-  default gtoResult :: (SSerialize t, GFromExprs t ~ t Result)-    => GFromExprs t -> GColumns t Result-  gtoResult = stoResult---type Algebra :: K.Rel8able -> K.Algebra-type Algebra t = GAlgebra (GRep t Expr)---type GRep :: K.Rel8able -> K.Context -> Type -> Type-type GRep t context = Rep (Record (t context))---type SRel8able :: K.Rel8able -> K.Context -> Constraint-class-  ( Generic (Record (t context))-  , G.GTable (TTable context) TColumns (GRep t context)-  , G.GColumns TColumns (GRep t context) ~ GColumns t-  )-  => SRel8able t context-instance-  ( Generic (Record (t context))-  , G.GTable (TTable context) TColumns (GRep t context)-  , G.GColumns TColumns (GRep t context) ~ GColumns t-  )-  => SRel8able t context---type SSerialize :: K.Rel8able -> Constraint-type SSerialize t =-  ( Generic (Record (t Result))-  , G.GSerialize TSerialize TColumns (GRep t Expr) (GRep t Result)-  , G.GColumns TColumns (GRep t Expr) ~ GColumns t-  )---sfromColumns :: forall t context. SRel8able t context-  => GColumns t context -> t context-sfromColumns =-  unrecord .-  to .-  G.gfromColumns @(TTable context) @TColumns fromColumns---stoColumns :: forall t context. SRel8able t context-  => t context -> GColumns t context-stoColumns =-  G.gtoColumns @(TTable context) @TColumns toColumns .-  from .-  Record---sfromResult :: forall t. SSerialize t-  => GColumns t Result -> t Result-sfromResult =-  unrecord .-  to .-  G.gfromResult-    @TSerialize-    @TColumns-    @(GRep t Expr)-    @(GRep t Result)-    (\(_ :: proxy x) -> deserialize @_ @x)---stoResult :: forall t. SSerialize t-  => t Result -> GColumns t Result-stoResult =-  G.gtoResult-    @TSerialize-    @TColumns-    @(GRep t Expr)-    @(GRep t Result)-    (\(_ :: proxy x) -> serialize @_ @x) .-  from .-  Record---- Note [Generics and Inlining]--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~--- We want to make sure that Generics derived functions (by default)--- do not expose their unfoldings. These are always unoptimised code and can--- therefore be quite large, and bloat our interfaces.--- By marking these as NOINLINE we can considerably speed up our compile times.--- If users do want these INLINEd, they can locally override the default using a pragma.
− src/Rel8/Generic/Table.hs
@@ -1,103 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language RankNTypes #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Generic.Table-  ( GGSerialize, GGColumns, ggfromResult, ggtoResult-  , GAlgebra-  )-where---- base-import Data.Kind ( Constraint, Type )-import GHC.Generics ( (:+:), (:*:), K1, M1, U1, V1 )-import Prelude ()---- rel8-import Rel8.FCF ( Eval, Exp )-import Rel8.Generic.Table.ADT-  ( GSerializeADT, GColumnsADT, gtoResultADT, gfromResultADT-  )-import Rel8.Generic.Table.Record ( GSerialize, GColumns, gtoResult, gfromResult )-import Rel8.Kind.Algebra-  ( Algebra( Product, Sum )-  , SAlgebra( SProduct, SSum )-  , KnownAlgebra, algebraSing-  )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Result ( Result )---data GGSerialize-  :: Algebra-  -> (Type -> Type -> Exp Constraint)-  -> (Type -> Exp K.HTable)-  -> (Type -> Type)-  -> (Type -> Type)-  -> Exp Constraint---type instance Eval (GGSerialize 'Product _Serialize _Columns exprs rep) =-  GSerialize _Serialize _Columns exprs rep---type instance Eval (GGSerialize 'Sum _Serialize _Columns exprs rep) =-  GSerializeADT _Serialize _Columns exprs rep---data GGColumns-  :: Algebra-  -> (Type -> Exp K.HTable)-  -> (Type -> Type)-  -> Exp K.HTable---type instance Eval (GGColumns 'Product _Columns rep) = GColumns _Columns rep---type instance Eval (GGColumns 'Sum _Columns rep) = GColumnsADT _Columns rep---type GAlgebra :: (Type -> Type) -> Algebra-type family GAlgebra rep where-  GAlgebra (M1 _ _ rep) = GAlgebra rep-  GAlgebra V1 = 'Sum-  GAlgebra (_ :+: _) = 'Sum-  GAlgebra U1 = 'Sum-  GAlgebra (_ :*: _) = 'Product-  GAlgebra (K1 _ _) = 'Product---ggfromResult :: forall algebra _Serialize _Columns exprs rep x.-  ( KnownAlgebra algebra-  , Eval (GGSerialize algebra _Serialize _Columns exprs rep)-  )-  => (forall expr a proxy. Eval (_Serialize expr a)-      => proxy expr -> Eval (_Columns expr) Result -> a)-  -> Eval (GGColumns algebra _Columns exprs) Result-  -> rep x-ggfromResult f x = case algebraSing @algebra of-  SProduct -> gfromResult @_Serialize @_Columns @exprs @rep f x-  SSum -> gfromResultADT @_Serialize @_Columns @exprs @rep f x---ggtoResult :: forall algebra _Serialize _Columns exprs rep x.-  ( KnownAlgebra algebra-  , Eval (GGSerialize algebra _Serialize _Columns exprs rep)-  )-  => (forall expr a proxy. Eval (_Serialize expr a)-      => proxy expr -> a -> Eval (_Columns expr) Result)-  -> rep x-  -> Eval (GGColumns algebra _Columns exprs) Result-ggtoResult f x = case algebraSing @algebra of-  SProduct -> gtoResult @_Serialize @_Columns @exprs @rep f x-  SSum -> gtoResultADT @_Serialize @_Columns @exprs @rep f x
− src/Rel8/Generic/Table/ADT.hs
@@ -1,221 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language LambdaCase #-}-{-# language MultiParamTypeClasses #-}-{-# language RankNTypes #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Generic.Table.ADT-  ( GSerializeADT, GColumnsADT, gfromResultADT, gtoResultADT-  , GSerializeADT', GColumnsADT'-  )-where---- base-import Data.Functor.Identity ( Identity( Identity ) )-import Data.Kind ( Constraint, Type )-import Data.Proxy ( Proxy( Proxy ) )-import GHC.Generics-  ( (:+:)( L1, R1 ), M1( M1 ), U1( U1 )-  , C, D-  , Meta( MetaCons )-  )-import GHC.TypeLits ( KnownSymbol, symbolVal )-import Prelude hiding ( null )---- rel8-import Rel8.FCF ( Eval, Exp )-import Rel8.Generic.Table.Record ( GSerialize, GColumns, gfromResult, gtoResult )-import Rel8.Schema.HTable ( HTable )-import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )-import Rel8.Schema.HTable.Label ( HLabel, hlabel, hunlabel )-import Rel8.Schema.HTable.Nullify ( HNullify, hnulls, hnullify, hunnullify )-import Rel8.Schema.HTable.Product ( HProduct( HProduct ) )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Result ( Result, null, nullifier, unnullifier )-import Rel8.Type.Tag ( Tag( Tag ) )---- text-import Data.Text ( pack )---type GColumnsADT-  :: (Type -> Exp K.HTable)-  -> (Type -> Type) -> K.HTable-type family GColumnsADT _Columns rep where-  GColumnsADT _Columns (M1 D _ rep) =-    GColumnsADT' _Columns (HLabel "tag" (HIdentity Tag)) rep---type GColumnsADT'-  :: (Type -> Exp K.HTable)-  -> K.HTable -> (Type -> Type) -> K.HTable-type family GColumnsADT' _Columns htable rep  where-  GColumnsADT' _Columns htable (a :+: b) =-    GColumnsADT' _Columns (GColumnsADT' _Columns htable a) b-  GColumnsADT' _Columns htable (M1 C ('MetaCons _ _ _) U1) = htable-  GColumnsADT' _Columns htable (M1 C ('MetaCons label _ _) rep) =-    HProduct htable (HLabel label (HNullify (GColumns _Columns rep)))---type GSerializeADT-  :: (Type -> Type -> Exp Constraint)-  -> (Type -> Exp K.HTable)-  -> (Type -> Type) -> (Type -> Type) -> Constraint-class GSerializeADT _Serialize _Columns exprs rep where-  gfromResultADT :: ()-    => (forall expr a proxy. Eval (_Serialize expr a)-        => proxy expr -> Eval (_Columns expr) Result -> a)-    -> GColumnsADT _Columns exprs Result-    -> rep x--  gtoResultADT :: ()-    => (forall expr a proxy. Eval (_Serialize expr a)-        => proxy expr -> a -> Eval (_Columns expr) Result)-    -> rep x-    -> GColumnsADT _Columns exprs Result---instance-  ( htable ~ HLabel "tag" (HIdentity Tag)-  , GSerializeADT' _Serialize _Columns htable exprs rep-  )-  => GSerializeADT _Serialize _Columns (M1 D meta exprs) (M1 D meta rep)- where-  gfromResultADT fromResult columns =-    case gfromResultADT' @_Serialize @_Columns @htable @exprs @rep fromResult tag columns of-      Just rep -> M1 rep-      _ -> error "ADT.fromColumns: mismatch between tag and data"-    where-      tag = (\(HIdentity (Identity a)) -> a) . hunlabel @"tag"--  gtoResultADT toResult (M1 rep) =-    gtoResultADT' @_Serialize @_Columns @htable @exprs @rep toResult tag (Just rep)-    where-      tag = hlabel @"tag" . HIdentity . Identity---type GSerializeADT'-  :: (Type -> Type -> Exp Constraint)-  -> (Type -> Exp K.HTable)-  -> K.HTable -> (Type -> Type) -> (Type -> Type) -> Constraint-class GSerializeADT' _Serialize _Columns htable exprs rep where-  gfromResultADT' :: context ~ Result-    => (forall expr a proxy. Eval (_Serialize expr a)-        => proxy expr -> Eval (_Columns expr) context -> a)-    -> (htable Result -> Tag)-    -> GColumnsADT' _Columns htable exprs context-    -> Maybe (rep x)--  gtoResultADT' :: context ~ Result-    => (forall expr a proxy. Eval (_Serialize expr a)-        => proxy expr -> a -> Eval (_Columns expr) context)-    -> (Tag -> htable Result)-    -> Maybe (rep x)-    -> GColumnsADT' _Columns htable exprs context--  extract :: GColumnsADT' _Columns htable exprs context -> htable context---instance-  ( htable' ~ GColumnsADT' _Columns htable exprs1-  , GSerializeADT' _Serialize _Columns htable exprs1 a-  , GSerializeADT' _Serialize _Columns htable' exprs2 b-  )-  => GSerializeADT' _Serialize _Columns htable (exprs1 :+: exprs2) (a :+: b)- where-  gfromResultADT' fromResult f columns =-    case ma of-      Just a -> Just (L1 a)-      Nothing -> R1 <$>-        gfromResultADT' @_Serialize @_Columns @_ @exprs2 @b-          fromResult-          (f . extract @_Serialize @_Columns @_ @exprs1 @a)-          columns-    where-      ma =-        gfromResultADT' @_Serialize @_Columns @_ @exprs1 @a-          fromResult-          f-          (extract @_Serialize @_Columns @_ @exprs2 @b columns)--  gtoResultADT' toResult tag = \case-    Just (L1 a) ->-      gtoResultADT' @_Serialize @_Columns @_ @exprs2 @b-        toResult-        (\_ -> gtoResultADT' @_Serialize @_Columns @_ @exprs1 @a-          toResult-          tag-          (Just a))-        Nothing-    Just (R1 b) ->-      gtoResultADT' @_Serialize @_Columns @_ @exprs2 @b-        toResult-        (\tag' ->-          gtoResultADT' @_Serialize @_Columns @_ @exprs1 @a-            toResult-            (\_ -> tag tag')-            Nothing)-        (Just b)-    Nothing ->-      gtoResultADT' @_Serialize @_Columns @_ @exprs2 @b-        toResult-        (\_ -> gtoResultADT' @_Serialize @_Columns @_ @exprs1 @a toResult tag Nothing)-        Nothing--  extract =-    extract @_Serialize @_Columns @_ @exprs1 @a .-    extract @_Serialize @_Columns @_ @exprs2 @b---instance (meta ~ 'MetaCons label _fixity _isRecord, KnownSymbol label) =>-  GSerializeADT' _Serialize _Columns _htable (M1 C meta U1) (M1 C meta U1)- where-  gfromResultADT' _ tag columns-    | tag columns == tag' = Just (M1 U1)-    | otherwise = Nothing-    where-      tag' = Tag $ pack $ symbolVal (Proxy @label)--  gtoResultADT' _ tag _ = tag tag'-    where-      tag' = Tag $ pack $ symbolVal (Proxy @label)--  extract = id---instance {-# OVERLAPPABLE #-}-  ( HTable (GColumns _Columns exprs)-  , GSerialize _Serialize _Columns exprs rep-  , meta ~ 'MetaCons label _fixity _isRecord-  , KnownSymbol label-  , GColumnsADT' _Columns htable (M1 C ('MetaCons label _fixity _isRecord) exprs) ~-      HProduct htable (HLabel label (HNullify (GColumns _Columns exprs)))-  )-  => GSerializeADT' _Serialize _Columns htable (M1 C meta exprs) (M1 C meta rep)- where-  gfromResultADT' fromResult tag (HProduct a b)-    | tag a == tag' =-        M1 . gfromResult @_Serialize @_Columns @exprs @rep fromResult <$>-          hunnullify unnullifier (hunlabel b)-    | otherwise = Nothing-    where-      tag' = Tag $ pack $ symbolVal (Proxy @label)--  gtoResultADT' toResult tag = \case-    Nothing -> HProduct (tag tag') (hlabel (hnulls (const null)))-    Just (M1 rep) -> HProduct (tag tag') $-      hlabel $-      hnullify nullifier $-      gtoResult @_Serialize @_Columns @exprs @rep toResult rep-    where-      tag' = Tag $ pack $ symbolVal (Proxy @label)--  extract (HProduct a _) = a
− src/Rel8/Generic/Table/Record.hs
@@ -1,181 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language PolyKinds #-}-{-# language RankNTypes #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Generic.Table.Record-  ( GTable, GColumns, GContext, gfromColumns, gtoColumns, gtable-  , GSerialize, gfromResult, gtoResult-  )-where---- base-import Data.Kind ( Constraint, Type )-import Data.Proxy ( Proxy( Proxy ) )-import GHC.Generics-  ( (:*:)( (:*:) ), K1( K1 ), M1( M1 )-  , C, D, S-  , Meta( MetaSel )-  )-import Prelude hiding ( null )---- rel8-import Rel8.FCF ( Eval, Exp )-import Rel8.Schema.HTable.Label ( HLabel, hlabel, hunlabel )-import Rel8.Schema.HTable.Product ( HProduct(..) )-import qualified Rel8.Schema.Kind as K---type GColumns :: (Type -> Exp K.HTable) -> (Type -> Type) -> K.HTable-type family GColumns _Columns rep where-  GColumns _Columns (M1 D _ rep) = GColumns _Columns rep-  GColumns _Columns (M1 C _ rep) = GColumns _Columns rep-  GColumns _Columns (rep1 :*: rep2) =-    HProduct (GColumns _Columns rep1) (GColumns _Columns rep2)-  GColumns _Columns (M1 S ('MetaSel ('Just label) _ _ _) (K1 _ a)) =-    HLabel label (Eval (_Columns a))---type GContext :: (Type -> Exp K.Context) -> (Type -> Type) -> K.Context-type family GContext _Context rep where-  GContext _Context (M1 _ _ rep) = GContext _Context rep-  GContext _Context (rep1 :*: _rep2) = GContext _Context rep1-  GContext _Context (K1 _ a) = Eval (_Context a)---type GTable-  :: (Type -> Exp Constraint)-  -> (Type -> Exp K.HTable)-  -> (Type -> Type) -> Constraint-class GTable _Table _Columns rep- where-  gfromColumns :: ()-    => (forall a. Eval (_Table a) => Eval (_Columns a) context -> a)-    -> GColumns _Columns rep context-    -> rep x--  gtoColumns :: ()-    => (forall a. Eval (_Table a) => a -> Eval (_Columns a) context)-    -> rep x-    -> GColumns _Columns rep context--  gtable :: ()-    => (forall a proxy. Eval (_Table a) => proxy a -> Eval (_Columns a) context)-    -> GColumns _Columns rep context---type GSerialize-  :: (Type -> Type -> Exp Constraint)-  -> (Type -> Exp K.HTable)-  -> (Type -> Type) -> (Type -> Type) -> Constraint-class GSerialize _Serialize _Columns exprs rep- where-  gfromResult :: ()-    => (forall expr a proxy. Eval (_Serialize expr a)-        => proxy expr -> Eval (_Columns expr) context -> a)-    -> GColumns _Columns exprs context-    -> rep x--  gtoResult :: ()-    => (forall expr a proxy. Eval (_Serialize expr a)-        => proxy expr -> a -> Eval (_Columns expr) context)-    -> rep x-    -> GColumns _Columns exprs context---instance GTable _Table _Columns rep => GTable _Table _Columns (M1 D c rep)- where-  gfromColumns fromColumns =-    M1 . gfromColumns @_Table @_Columns @rep fromColumns-  gtoColumns toColumns (M1 a) =-    gtoColumns @_Table @_Columns @rep toColumns a-  gtable = gtable @_Table @_Columns @rep---instance GSerialize _Serialize _Columns exprs rep =>-  GSerialize _Serialize _Columns (M1 D c exprs) (M1 D c rep)- where-  gfromResult fromResult =-    M1 . gfromResult @_Serialize @_Columns @exprs @rep fromResult-  gtoResult toResult (M1 a) =-    gtoResult @_Serialize @_Columns @exprs @rep toResult a---instance GTable _Table _Columns rep => GTable _Table _Columns (M1 C c rep)- where-  gfromColumns fromColumns =-    M1 . gfromColumns @_Table @_Columns @rep fromColumns-  gtoColumns toColumns (M1 a) =-    gtoColumns @_Table @_Columns @rep toColumns a-  gtable = gtable @_Table @_Columns @rep---instance GSerialize _Serialize _Columns exprs rep =>-  GSerialize _Serialize _Columns (M1 C c exprs) (M1 C c rep)- where-  gfromResult fromResult =-    M1 . gfromResult @_Serialize @_Columns @exprs @rep fromResult-  gtoResult toResult (M1 a) =-    gtoResult @_Serialize @_Columns @exprs @rep toResult a---instance (GTable _Table _Columns rep1, GTable _Table _Columns rep2) =>-  GTable _Table _Columns (rep1 :*: rep2)- where-  gfromColumns fromColumns (HProduct a b) =-    gfromColumns @_Table @_Columns @rep1 fromColumns a :*:-    gfromColumns @_Table @_Columns @rep2 fromColumns b-  gtoColumns toColumns (a :*: b) = HProduct-    (gtoColumns @_Table @_Columns @rep1 toColumns a)-    (gtoColumns @_Table @_Columns @rep2 toColumns b)-  gtable table = HProduct-    (gtable @_Table @_Columns @rep1 table)-    (gtable @_Table @_Columns @rep2 table)---instance-  ( GSerialize _Serialize _Columns expr1 rep1-  , GSerialize _Serialize _Columns expr2 rep2-  )-  => GSerialize _Serialize _Columns (expr1 :*: expr2) (rep1 :*: rep2)- where-  gfromResult fromResult (HProduct a b) =-    gfromResult @_Serialize @_Columns @expr1 @rep1 fromResult a :*:-    gfromResult @_Serialize @_Columns @expr2 @rep2 fromResult b-  gtoResult toResult (a :*: b) =-    HProduct-      (gtoResult @_Serialize @_Columns @expr1 @rep1 toResult a)-      (gtoResult @_Serialize @_Columns @expr2 @rep2 toResult b)---instance-  ( Eval (_Table a)-  , meta ~ 'MetaSel ('Just label) _su _ss _ds-  , k1 ~ K1 i a-  )-  => GTable _Table _Columns (M1 S meta k1)- where-  gfromColumns fromColumns = M1 . K1 . fromColumns . hunlabel-  gtoColumns toColumns (M1 (K1 a)) = hlabel (toColumns a)-  gtable table = hlabel (table (Proxy @a))---instance-  ( Eval (_Serialize expr a)-  , meta ~ 'MetaSel ('Just label) _su _ss _ds-  , k1 ~ K1 i expr-  , k1' ~ K1 i a-  )-  => GSerialize _Serialize _Columns (M1 S meta k1) (M1 S meta k1')- where-  gfromResult fromResult = M1 . K1 . fromResult (Proxy @expr) . hunlabel-  gtoResult toResult (M1 (K1 a)) = hlabel (toResult (Proxy @expr) a)
− src/Rel8/Kind/Algebra.hs
@@ -1,38 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language GADTs #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Kind.Algebra-  ( Algebra( Product, Sum )-  , SAlgebra( SProduct, SSum )-  , KnownAlgebra( algebraSing )-  )-where---- base-import Data.Kind ( Constraint, Type )-import Prelude ()---type Algebra :: Type-data Algebra = Product | Sum---type SAlgebra :: Algebra -> Type-data SAlgebra algebra where-  SProduct :: SAlgebra 'Product-  SSum :: SAlgebra 'Sum---type KnownAlgebra :: Algebra -> Constraint-class KnownAlgebra algebra where-  algebraSing :: SAlgebra algebra---instance KnownAlgebra 'Product where-  algebraSing = SProduct---instance KnownAlgebra 'Sum where-  algebraSing = SSum
− src/Rel8/Kind/Context.hs
@@ -1,50 +0,0 @@-{-# language DataKinds #-}-{-# language GADTs #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeSynonymInstances #-}--module Rel8.Kind.Context-  ( Reifiable( contextSing )-  , SContext(..)-  )-where---- base-import Data.Kind ( Constraint, Type )-import Prelude ()---- rel8-import Rel8.Expr ( Expr )-import Rel8.Schema.Field ( Field )-import Rel8.Schema.Kind ( Context )-import Rel8.Schema.Name ( Name )-import Rel8.Schema.Result ( Result )---type SContext :: Context -> Type-data SContext context where-  SExpr :: SContext Expr-  SField :: SContext (Field table)-  SName :: SContext Name-  SResult :: SContext Result---type Reifiable :: Context -> Constraint-class Reifiable context where-  contextSing :: SContext context---instance Reifiable Expr where-  contextSing = SExpr---instance Reifiable (Field table) where-  contextSing = SField---instance Reifiable Result where-  contextSing = SResult---instance Reifiable Name where-  contextSing = SName
− src/Rel8/Order.hs
@@ -1,30 +0,0 @@-{-# language DerivingStrategies #-}-{-# language GeneralizedNewtypeDeriving #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Order-  ( Order(..)-  )-where---- base-import Data.Functor.Contravariant ( Contravariant )-import Data.Kind ( Type )-import Prelude---- contravariant-import Data.Functor.Contravariant.Divisible ( Decidable, Divisible )---- opaleye-import qualified Opaleye.Order as Opaleye----- | An ordering expression for @a@. Primitive orderings are defined with--- 'Rel8.asc' and 'Rel8.desc', and you can combine @Order@ via its various--- instances.------ A common pattern is to use '<>' to combine multiple orderings in sequence,--- and 'Data.Functor.Contravariant.>$<' to select individual columns.-type Order :: Type -> Type-newtype Order a = Order (Opaleye.Order a)-  deriving newtype (Contravariant, Divisible, Decidable, Semigroup, Monoid)
− src/Rel8/Query.hs
@@ -1,223 +0,0 @@-{-# language FlexibleContexts #-}-{-# language StandaloneKindSignatures #-}-{-# language UndecidableInstances #-}--module Rel8.Query-  ( Query( Query )-  )-where---- base-import Control.Applicative ( liftA2 )-import Control.Monad ( liftM2 )-import Data.Kind ( Type )-import Data.Monoid ( Any( Any ) )-import Prelude---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye-import qualified Opaleye.Internal.PackMap as Opaleye-import qualified Opaleye.Internal.PrimQuery as Opaleye hiding (lateral)-import qualified Opaleye.Internal.QueryArr as Opaleye-import qualified Opaleye.Internal.Tag as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Query.Set ( unionAll )-import Rel8.Query.Opaleye ( fromOpaleye )-import Rel8.Query.Values ( values )-import Rel8.Table ( Table, fromColumns, toColumns )-import Rel8.Table.Alternative-  ( AltTable, (<|>:)-  , AlternativeTable, emptyTable-  )-import Rel8.Table.Projection ( Projectable, apply, project )---- semigroupoids-import Data.Functor.Apply ( Apply, (<.>) )-import Data.Functor.Bind ( Bind, (>>-) )----- | The @Query@ monad allows you to compose a @SELECT@ query. This monad has--- semantics similar to the list (@[]@) monad.-type Query :: Type -> Type-newtype Query a =-  Query (-    -- This is based on Opaleye's Select monad, but with two addtions. We-    -- maintain a stack of PrimExprs from parent previous subselects. In-    -- practice, these are always the results of dummy calls to random().-    ---    -- We also return a Bool that indicates to the parent subselect whether-    -- or not that stack of PrimExprs were used at any point. If they weren't,-    -- then the call to random() is never added to the query.-    ---    -- This is all needed to implement evaluate. Consider the following code:-    ---    -- do-    --   x <- values [lit 'a', lit 'b', lit 'c']-    --   y <- evaluate $ nextval "user_id_seq"-    --   pure (x, y)-    ---    -- If we just used Opaleye's Select monad directly, the SQL would come out-    -- like this:-    ---    -- SELECT-    --   a, b-    -- FROM-    --   (VALUES ('a'), ('b'), ('c')) Q1(a),-    --   LATERAL (SELECT nextval('user_id_seq')) Q2(b);-    ---    -- From the Haskell code, you would intuitively expect to get back the-    -- results of three different calls to nextval(), but from Postgres' point-    -- of view, because the Q2 subquery doesn't reference anything from the Q1-    -- query, it thinks it only needs to call nextval() once. This is actually-    -- exactly the same problem you get with the deprecated ListT IO monad from-    -- the transformers package — *> behaves differently to >>=, so-    -- using ApplicativeDo can change the results of a program. ApplicativeDo-    -- is exactly the optimisation Postgres does on a "LATERAL" query that-    -- doesn't make any references to previous subselects.-    ---    -- Rel8's solution is generate the following SQL instead:-    ---    -- SELECT-    --   a, b-    -- FROM-    --   (SELECT-    --      random() AS dummy,-    --      *-    --    FROM-    --      (VALUES ('a'), ('b'), ('c')) Q1(a)) Q1,-    --   LATERAL (SELECT-    --     CASE-    --       WHEN dummy IS NOT NULL-    --       THEN nextval('user_id_seq')-    --     END) Q2(b);-    ---    -- We use random() here as the dummy value (and not some constant) because-    -- Postgres will again optimize if it sees that a value is constant-    -- (and thus only call nextval() once), but because random() is marked as-    -- VOLATILE, this inhibits Postgres from doing that optimisation.-    ---    -- Why not just reference the a column from the previous query directly-    -- instead of adding a dummy value? Basically, even if we extract out all-    -- the bindings introduced in a PrimQuery, we can't always be sure which-    -- ones refer to constant values, so if we end up laterally referencing a-    -- constant value, then all of this would be for nothing.-    ---    -- Why not just add the call to the previous subselect directly, like so:-    ---    -- SELECT-    --   a, b-    -- FROM-    --   (SELECT-    --      nextval('user_id_seq') AS eval,-    --      *-    --    FROM-    --      (VALUES ('a'), ('b'), ('c')) Q1(a)) Q1,-    --   LATERAL (SELECT eval) Q2(b);-    ---    -- That would work in this case. But consider the following Rel8 code:-    ---    -- do-    --   x <- values [lit 'a', lit 'b', lit 'c']-    --   y <- values [lit 'd', lit 'e', lit 'f']-    --   z <- evaluate $ nextval "user_id_seq"-    --   pure (x, y, z)-    ---    -- How many calls to nextval should there be? Our Haskell intuition says-    -- nine. But that's not what you would get if you used the above-    -- technique. The problem is, which VALUES query should the nextval be-    -- added to? You can choose one or the other to get three calls to-    -- nextval, but you still need to make a superfluous LATERAL references to-    -- the other if you want nine calls. So for the above Rel8 code we generate-    -- the following SQL:-    ---    -- SELECT-    --   a, b, c-    -- FROM-    --   (SELECT-    --      random() AS dummy,-    --      *-    --    FROM-    --      (VALUES ('a'), ('b'), ('c')) Q1(a)) Q1,-    --   (SELECT-    --      random() AS dummy,-    --      *-    --    FROM-    --      (VALUES ('d'), ('e'), ('f')) Q2(b)) Q2,-    --   LATERAL (SELECT-    --     CASE-    --       WHEN Q1.dummy IS NOT NULL AND Q2.dummy IS NOT NULL-    --       THEN nextval('user_id_seq')-    --     END) Q3(c);-    ---    -- This gives nine calls to nextval() as we would expect.-    [Opaleye.PrimExpr] -> Opaleye.Select (Any, a)-  )---instance Projectable Query where-  project f = fmap (fromColumns . apply f . toColumns)---instance Functor Query where-  fmap f (Query a) = Query (fmap (fmap (fmap f)) a)---instance Apply Query where-  (<.>) = (<*>)---instance Applicative Query where-  pure = fromOpaleye . pure-  liftA2 = liftM2---instance Bind Query where-  (>>-) = (>>=)---instance Monad Query where-  Query q >>= f = Query $ \dummies -> Opaleye.stateQueryArr $ \_ tag ->-    let-      qa = q dummies-      ((m, a), query, tag') = Opaleye.runStateQueryArr qa () tag-      Query q' = f a-      (dummies', query', tag'') =-        ( dummy : dummies-        , query <> Opaleye.aRebind bindings-        , Opaleye.next tag'-        )-        where-          (dummy, bindings) = Opaleye.run $ name random-            where-              random = Opaleye.FunExpr "random" []-              name = Opaleye.extractAttr "dummy" tag'-      qa' = Opaleye.lateral $ \_ -> q' dummies'-      ((m'@(Any needsDummies), b), query'', tag''') = Opaleye.runStateQueryArr qa' () tag''-      query'''-        | needsDummies = query' <> query''-        | otherwise = query <> query''-      m'' = m <> m'-    in-      ((m'', b), query''', tag''')----- | '<|>:' = 'unionAll'.-instance AltTable Query where-  (<|>:) = unionAll----- | 'emptyTable' = 'values' @[]@.-instance AlternativeTable Query where-  emptyTable = values []----- | '<>' = 'unionAll'.-instance Table Expr a => Semigroup (Query a) where-  (<>) = (<|>:)----- | 'mempty' = @'values' []@.-instance Table Expr a => Monoid (Query a) where-  mempty = emptyTable
− src/Rel8/Query.hs-boot
@@ -1,19 +0,0 @@-{-# language StandaloneKindSignatures #-}--module Rel8.Query-  ( Query( Query )-  )-where---- base-import Data.Kind ( Type )-import Data.Monoid ( Any )-import Prelude ()---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye-import qualified Opaleye.Select as Opaleye---type Query :: Type -> Type-newtype Query a = Query ([Opaleye.PrimExpr] -> Opaleye.Select (Any, a))
− src/Rel8/Query/Aggregate.hs
@@ -1,59 +0,0 @@-{-# language FlexibleContexts #-}-{-# language MonoLocalBinds #-}-{-# language ScopedTypeVariables #-}--module Rel8.Query.Aggregate-  ( aggregate-  , aggregate1-  , aggregateU-  , countRows-  )-where---- base-import Control.Applicative (liftA2)-import Data.Int ( Int64 )-import Prelude---- opaleye-import qualified Opaleye.Adaptors as Opaleye-import qualified Opaleye.Aggregate as Opaleye---- rel8-import Rel8.Aggregate (Aggregator' (Aggregator), Aggregator)-import Rel8.Aggregate.Fold (Fallback (Fallback))-import Rel8.Expr ( Expr )-import Rel8.Expr.Aggregate ( countStar )-import Rel8.Expr.Bool (true)-import Rel8.Query ( Query )-import Rel8.Query.Maybe ( optional )-import Rel8.Query.Opaleye ( mapOpaleye )-import Rel8.Table (Table)-import Rel8.Table.Maybe (fromMaybeTable)-import Rel8.Table.Opaleye (unpackspec)----- | Apply an 'Aggregator' to all rows returned by a 'Query'. If the 'Query'--- is empty, then a single \"fallback\" row is returned, composed of the--- identity elements of the constituent aggregation functions.-aggregate :: (Table Expr i, Table Expr a) => Aggregator i a -> Query i -> Query a-aggregate aggregator@(Aggregator (Fallback fallback) _) =-  fmap (fromMaybeTable fallback) . optional . aggregate1 aggregator----- | Apply an 'Rel8.Aggregator1' to all rows returned by a 'Query'. If--- the 'Query' is empty, then zero rows are returned.-aggregate1 :: Table Expr i => Aggregator' fold i a -> Query i -> Query a-aggregate1 = aggregateU unpackspec---aggregateU :: Opaleye.Unpackspec i i -> Aggregator' fold i a -> Query i -> Query a-aggregateU unpack (Aggregator _ aggregator) =-  mapOpaleye (Opaleye.aggregateExplicit unpack aggregator)----- | Count the number of rows returned by a query. Note that this is different--- from @countStar@, as even if the given query yields no rows, @countRows@--- will return @0@.-countRows :: Query a -> Query (Expr Int64)-countRows = aggregate countStar . (true <$)
− src/Rel8/Query/Distinct.hs
@@ -1,40 +0,0 @@-module Rel8.Query.Distinct-  ( distinct-  , distinctOn-  , distinctOnBy-  )-where---- base-import Prelude ()---- opaleye-import qualified Opaleye.Distinct as Opaleye-import qualified Opaleye.Order as Opaleye---- rel8-import Rel8.Order ( Order( Order ) )-import Rel8.Query ( Query )-import Rel8.Query.Opaleye ( mapOpaleye )-import Rel8.Table.Eq ( EqTable )-import Rel8.Table.Opaleye (distinctspec, unpackspec)----- | Select all distinct rows from a query, removing duplicates.  @distinct q@--- is equivalent to the SQL statement @SELECT DISTINCT q@.-distinct :: EqTable a => Query a -> Query a-distinct = mapOpaleye (Opaleye.distinctExplicit unpackspec distinctspec)----- | Select all distinct rows from a query, where rows are equivalent according--- to a projection. If multiple rows have the same projection, it is--- unspecified which row will be returned. If this matters, use 'distinctOnBy'.-distinctOn :: EqTable b => (a -> b) -> Query a -> Query a-distinctOn proj = mapOpaleye (Opaleye.distinctOnExplicit unpackspec proj)----- | Select all distinct rows from a query, where rows are equivalent according--- to a projection. If there are multiple rows with the same projection, the--- first row according to the specified 'Order' will be returned.-distinctOnBy :: EqTable b => (a -> b) -> Order a -> Query a -> Query a-distinctOnBy proj (Order order) = mapOpaleye (Opaleye.distinctOnByExplicit unpackspec proj order)
− src/Rel8/Query/Each.hs
@@ -1,32 +0,0 @@-{-# language FlexibleContexts #-}-{-# language MonoLocalBinds #-}--module Rel8.Query.Each-  ( each-  )-where---- base-import Prelude---- opaleye-import qualified Opaleye.Table as Opaleye---- rel8-import Rel8.Query ( Query )-import Rel8.Query.Opaleye ( fromOpaleye )-import Rel8.Schema.Name ( Selects )-import Rel8.Schema.Table ( TableSchema )-import Rel8.Table.Cols ( fromCols, toCols )-import Rel8.Table.Opaleye ( table, unpackspec )----- | Select each row from a table definition. This is equivalent to @FROM--- table@.-each :: Selects names exprs => TableSchema names -> Query exprs-each =-  fmap fromCols .-  fromOpaleye .-  Opaleye.selectTableExplicit unpackspec .-  table .-  fmap toCols
− src/Rel8/Query/Either.hs
@@ -1,69 +0,0 @@-{-# language FlexibleContexts #-}--module Rel8.Query.Either-  ( keepLeftTable-  , keepRightTable-  , bitraverseEitherTable-  )-where---- base-import Prelude---- comonad-import Control.Comonad ( extract )---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Eq ( (==.) )-import Rel8.Query ( Query )-import Rel8.Query.Filter ( where_ )-import Rel8.Query.Maybe ( optional )-import Rel8.Table.Either-  ( EitherTable( EitherTable )-  , isLeftTable, isRightTable-  )-import Rel8.Table.Maybe ( MaybeTable( MaybeTable ), isJustTable )----- | Filter 'EitherTable's, keeping only 'leftTable's.-keepLeftTable :: EitherTable Expr a b -> Query a-keepLeftTable e@(EitherTable _ a _) = do-  where_ $ isLeftTable e-  pure (extract a)----- | Filter 'EitherTable's, keeping only 'rightTable's.-keepRightTable :: EitherTable Expr a b -> Query b-keepRightTable e@(EitherTable _ _ b) = do-  where_ $ isRightTable e-  pure (extract b)----- | @bitraverseEitherTable f g x@ will pass all @leftTable@s through @f@ and--- all @rightTable@s through @g@. The results are then lifted back into--- @leftTable@ and @rightTable@, respectively. This is similar to 'bitraverse'--- for 'Either'.------ For example,------ >>> :{--- select do---   x <- values (map lit [ Left True, Right (42 :: Int32) ])---   bitraverseEitherTable (\y -> values [y, not_ y]) (\y -> pure (y * 100)) x--- :}--- [ Left True--- , Left False--- , Right 4200--- ]-bitraverseEitherTable :: ()-  => (a -> Query c)-  -> (b -> Query d)-  -> EitherTable Expr a b-  -> Query (EitherTable Expr c d)-bitraverseEitherTable f g e@(EitherTable tag _ _) = do-  mc@(MaybeTable _ c) <- optional (f =<< keepLeftTable e)-  md@(MaybeTable _ d) <- optional (g =<< keepRightTable e)-  where_ $ isJustTable mc ==. isLeftTable e-  where_ $ isJustTable md ==. isRightTable e-  pure $ EitherTable tag c d
− src/Rel8/Query/Evaluate.hs
@@ -1,49 +0,0 @@-{-# language FlexibleContexts #-}-{-# language TupleSections #-}--module Rel8.Query.Evaluate-  ( evaluate-  )-where---- base-import Control.Monad ( (>=>) )-import Data.Foldable ( foldl' )-import Data.List.NonEmpty ( NonEmpty( (:|) ), nonEmpty )-import Data.Monoid ( Any( Any ) )-import Prelude hiding ( undefined )---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Bool ( (&&.) )-import Rel8.Expr.Opaleye ( fromPrimExpr )-import Rel8.Query ( Query( Query ) )-import Rel8.Query.Rebind ( rebind )-import Rel8.Table ( Table )-import Rel8.Table.Bool ( case_ )-import Rel8.Table.Undefined ( undefined )----- | 'evaluate' takes expressions that could potentially have side effects and--- \"runs\" them in the 'Query' monad. The returned expressions have no side--- effects and can safely be reused.-evaluate :: Table Expr a => a -> Query a-evaluate = laterally >=> rebind "eval"---laterally :: Table Expr a => a -> Query a-laterally a = Query $ \bindings -> pure $ (Any True,) $-  case nonEmpty bindings of-    Nothing -> a-    Just bindings' -> case_ [(condition, a)] undefined-      where-        condition = foldl1' (&&.) (fmap go bindings')-          where-            go = fromPrimExpr . Opaleye.UnExpr Opaleye.OpIsNotNull---foldl1' :: (a -> a -> a) -> NonEmpty a -> a-foldl1' f (a :| as) = foldl' f a as
− src/Rel8/Query/Exists.hs
@@ -1,66 +0,0 @@-{-# language DataKinds #-}--module Rel8.Query.Exists-  ( exists, inQuery-  , present, with, withBy-  , absent, without, withoutBy-  )-where---- base-import Prelude hiding ( filter )---- opaleye-import qualified Opaleye.Exists as Opaleye-import qualified Opaleye.Operators as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Opaleye ( fromColumn, fromPrimExpr )-import Rel8.Query ( Query )-import Rel8.Query.Filter ( filter )-import Rel8.Query.Opaleye ( mapOpaleye )-import Rel8.Table.Eq ( EqTable, (==:) )----- | Checks if a query returns at least one row.-exists :: Query a -> Query (Expr Bool)-exists = fmap (fromPrimExpr . fromColumn) . mapOpaleye Opaleye.exists---inQuery :: EqTable a => a -> Query a -> Query (Expr Bool)-inQuery a = exists . (>>= filter (a ==:))----- | Produce the empty query if the given query returns no rows. @present@--- is equivalent to @WHERE EXISTS@ in SQL.-present :: Query a -> Query ()-present = mapOpaleye Opaleye.restrictExists----- | Produce the empty query if the given query returns rows. @absent@--- is equivalent to @WHERE NOT EXISTS@ in SQL.-absent :: Query a -> Query ()-absent = mapOpaleye Opaleye.restrictNotExists----- | @with@ is similar to 'filter', but allows the predicate to be a full query.------ @with f a = a <$ present (f a)@, but this form matches 'filter'.-with :: (a -> Query b) -> a -> Query a-with f a = a <$ present (f a)----- | Like @with@, but with a custom membership test.-withBy :: (a -> b -> Expr Bool) -> Query b -> a -> Query a-withBy predicate bs = with $ \a -> bs >>= filter (predicate a)----- | Filter rows where @a -> Query b@ yields no rows.-without :: (a -> Query b) -> a -> Query a-without f a = a <$ absent (f a)----- | Like @without@, but with a custom membership test.-withoutBy :: (a -> b -> Expr Bool) -> Query b -> a -> Query a-withoutBy predicate bs = without $ \a -> bs >>= filter (predicate a)
− src/Rel8/Query/Filter.hs
@@ -1,35 +0,0 @@-module Rel8.Query.Filter-  ( filter-  , where_-  )-where---- base-import Prelude hiding ( filter )---- opaleye-import qualified Opaleye.Operators as Opaleye---- profunctors-import Data.Profunctor ( lmap )---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Opaleye ( toColumn, toPrimExpr )-import Rel8.Query ( Query )-import Rel8.Query.Opaleye ( fromOpaleye )----- | @filter f x@ will be a zero-row query when @f x@ is @False@, and will--- return @x@ unchanged when @f x@ is @True@. This is similar to--- 'Control.Monad.guard', but as the predicate is separate from the argument,--- it is easy to use in a pipeline of 'Query' transformations.-filter :: (a -> Expr Bool) -> a -> Query a-filter f a = a <$ where_ (f a)----- | Drop any rows that don't match a predicate.  @where_ expr@ is equivalent--- to the SQL @WHERE expr@.-where_ :: Expr Bool -> Query ()-where_ condition =-  fromOpaleye $ lmap (\_ -> toColumn $ toPrimExpr condition) Opaleye.restrict
− src/Rel8/Query/Function.hs
@@ -1,32 +0,0 @@-{-# language FlexibleContexts #-}-{-# language MonoLocalBinds #-}--module Rel8.Query.Function-  ( queryFunction-  )-where---- base-import Prelude---- opaleye-import qualified Opaleye.Internal.Operators as Opaleye---- rel8-import Rel8.Expr (Expr)-import Rel8.Expr.Function (Arguments, primFunction)-import Rel8.Query (Query)-import Rel8.Query.Opaleye (fromOpaleye)-import Rel8.Schema.QualifiedName (QualifiedName)-import Rel8.Table (Table)-import Rel8.Table.Opaleye (castTable, relExprPP)----- | Select each row from a function that returns a relation. This is--- equivalent to @FROM function(input)@.-queryFunction :: (Arguments input, Table Expr output)-  => QualifiedName -> input -> Query output-queryFunction name input = fmap castTable $ fromOpaleye $-  Opaleye.relationValuedExprExplicit relExprPP (const expr)-  where-    expr = primFunction name input
− src/Rel8/Query/Indexed.hs
@@ -1,21 +0,0 @@-module Rel8.Query.Indexed-  ( indexed-  )-where---- base-import Control.Applicative ( liftA2 )-import Data.Int ( Int64 )-import Prelude---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Window ( rowNumber )-import Rel8.Query ( Query )-import Rel8.Query.Window ( window )-import Rel8.Table.Window ( currentRow )----- | Pair each row of a query with its index within the query.-indexed :: Query a -> Query (Expr Int64, a)-indexed = window (liftA2 (,) (subtract 1 <$> rowNumber) currentRow)
− src/Rel8/Query/Limit.hs
@@ -1,27 +0,0 @@-module Rel8.Query.Limit-  ( limit-  , offset-  )-where---- base-import Prelude---- opaleye-import qualified Opaleye---- rel8-import Rel8.Query ( Query )-import Rel8.Query.Opaleye ( mapOpaleye )----- | @limit n@ select at most @n@ rows from a query.  @limit n@ is equivalent--- to the SQL @LIMIT n@.-limit :: Word -> Query a -> Query a-limit = mapOpaleye . Opaleye.limit . fromIntegral----- | @offset n@ drops the first @n@ rows from a query. @offset n@ is equivalent--- to the SQL @OFFSET n@.-offset :: Word -> Query a -> Query a-offset = mapOpaleye . Opaleye.offset . fromIntegral
− src/Rel8/Query/List.hs
@@ -1,124 +0,0 @@-{-# language FlexibleContexts #-}-{-# language GADTs #-}-{-# language NamedFieldPuns #-}--module Rel8.Query.List-  ( many, some-  , manyExpr, someExpr-  , catListTable, catNonEmptyTable-  , catList, catNonEmpty-  )-where---- base-import Control.Monad ((>=>))-import Data.Functor.Identity ( runIdentity )-import Data.List.NonEmpty ( NonEmpty )-import Prelude---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Aggregate ( listAggExpr, nonEmptyAggExpr )-import Rel8.Expr.Opaleye ( mapPrimExpr )-import Rel8.Query ( Query )-import Rel8.Query.Aggregate (aggregate, aggregate1)-import Rel8.Query.Rebind (hrebind, rebind)-import Rel8.Schema.HTable (HTable, hfield, hspecs, htabulate)-import Rel8.Schema.HTable.Vectorize ( hunvectorize )-import Rel8.Schema.Null ( Sql )-import Rel8.Schema.Spec ( Spec( Spec, info ) )-import Rel8.Table (Table, fromColumns, toColumns)-import Rel8.Table.Aggregate ( listAgg, nonEmptyAgg )-import Rel8.Table.List ( ListTable( ListTable ) )-import Rel8.Table.NonEmpty ( NonEmptyTable( NonEmptyTable ) )-import Rel8.Type ( DBType )-import Rel8.Type.Array ( extractArrayElement )----- | Aggregate a 'Query' into a 'ListTable'. If the supplied query returns 0--- rows, this function will produce a 'Query' that returns one row containing--- the empty @ListTable@. If the supplied @Query@ does return rows, @many@ will--- return exactly one row, with a @ListTable@ collecting all returned rows.------ @many@ is analogous to 'Control.Applicative.many' from--- @Control.Applicative@.-many :: Table Expr a => Query a -> Query (ListTable Expr a)-many = aggregate listAgg----- | Aggregate a 'Query' into a 'NonEmptyTable'. If the supplied query returns--- 0 rows, this function will produce a 'Query' that is empty - that is, will--- produce zero @NonEmptyTable@s. If the supplied @Query@ does return rows,--- @some@ will return exactly one row, with a @NonEmptyTable@ collecting all--- returned rows.------ @some@ is analogous to 'Control.Applicative.some' from--- @Control.Applicative@.-some :: Table Expr a => Query a -> Query (NonEmptyTable Expr a)-some = aggregate1 nonEmptyAgg----- | A version of 'many' specialised to single expressions.-manyExpr :: Sql DBType a => Query (Expr a) -> Query (Expr [a])-manyExpr = aggregate listAggExpr----- | A version of 'many' specialised to single expressions.-someExpr :: Sql DBType a => Query (Expr a) -> Query (Expr (NonEmpty a))-someExpr = aggregate1 nonEmptyAggExpr----- | Expand a 'ListTable' into a 'Query', where each row in the query is an--- element of the given @ListTable@.------ @catListTable@ is an inverse to 'many'.-catListTable :: Table Expr a => ListTable Expr a -> Query a-catListTable (ListTable as) =-  fmap fromColumns $ (hrebind "unnest" >=> hextract) $ runIdentity $-    hunvectorize (\_ -> pure . unnest) as----- | Expand a 'NonEmptyTable' into a 'Query', where each row in the query is an--- element of the given @NonEmptyTable@.------ @catNonEmptyTable@ is an inverse to 'some'.-catNonEmptyTable :: Table Expr a => NonEmptyTable Expr a -> Query a-catNonEmptyTable (NonEmptyTable as) =-  fmap fromColumns $ (hrebind "unnest" >=> hextract) $ runIdentity $-    hunvectorize (\_ -> pure . unnest) as----- | Expand an expression that contains a list into a 'Query', where each row--- in the query is an element of the given list.------ @catList@ is an inverse to 'manyExpr'.-catList :: Sql DBType a => Expr [a] -> Query (Expr a)-catList = rebind "unnest" . unnest >=> extract----- | Expand an expression that contains a non-empty list into a 'Query', where--- each row in the query is an element of the given list.------ @catNonEmpty@ is an inverse to 'someExpr'.-catNonEmpty :: Sql DBType a => Expr (NonEmpty a) -> Query (Expr a)-catNonEmpty = rebind "unnest" . unnest >=> extract---unnest :: Expr (list a) -> Expr a-unnest = mapPrimExpr $ Opaleye.UnExpr (Opaleye.UnOpOther "UNNEST")---extract :: Table Expr a => a -> Query a-extract = fmap fromColumns . hextract . toColumns---hextract :: HTable t => t Expr -> Query (t Expr)-hextract = hrebind "extract" . go-  where-    go as = htabulate $ \field ->-      case hfield as field of-        a -> case hfield hspecs field of-          Spec {info} -> mapPrimExpr (extractArrayElement info) a
− src/Rel8/Query/Loop.hs
@@ -1,73 +0,0 @@-{-# language FlexibleContexts #-}--module Rel8.Query.Loop-  ( loop-  , loopDistinct-  ) where---- base-import Prelude---- opaleye-import Opaleye.With (withRecursiveExplicit, withRecursiveDistinctExplicit)---- rel8-import Rel8.Expr ( Expr )-import Rel8.Query ( Query )-import Rel8.Query.Opaleye ( fromOpaleye, toOpaleye )-import Rel8.Table ( Table )-import Rel8.Table.Opaleye ( binaryspec )----- | 'loop' allows the construction of recursive queries, using Postgres'--- [@WITH RECURSIVE@](https://www.postgresql.org/docs/current/queries-with.html#QUERIES-WITH-RECURSIVE)--- under the hood. The first argument to 'loop' is what the Postgres--- documentation refers to as the \"non-recursive term\" and the second--- argument is the \"recursive term\", which is defined in terms of the result--- of the \"non-recursive term\". 'loop' uses @UNION ALL@ to combine the--- recursive and non-recursive terms.------ Denotionally, @'loop' s f@ is the smallest set of rows @r@ such--- that------ @--- r == s \`'Rel8.unionAll'\` (r >>= f)--- @------ Operationally, @'loop' s f@ takes each row in an initial set @s@ and--- supplies it to @f@, resulting in a new generation of rows which are added--- to the result set. Each row from this new generation is then fed back to--- @f@, and this process is repeated until a generation comes along for which--- @f@ returns an empty set for each row therein.-loop :: Table Expr a => Query a -> (a -> Query a) -> Query a-loop base recurse =-  fromOpaleye $ withRecursiveExplicit binaryspec base' recurse'-  where-    base' = toOpaleye base-    recurse' = toOpaleye . recurse----- | 'loopDistinct' is like 'loop' but uses @UNION@ instead of @UNION ALL@ to--- combine the recursive and non-recursive terms.------ Denotationally, @'loopDistinct' s f@ is the smallest set of rows--- @r@ such that------ @--- r == s \`'Rel8.union'\` (r >>= f)--- @------ Operationally, @'loopDistinct' s f@ takes each /distinct/ row in an--- initial set @s@ and supplies it to @f@, resulting in a new generation of--- rows. Any rows returned by @f@ that already exist in the result set are not--- considered part of this new generation by 'loopDistinct' (in contrast to--- 'loop'). This new generation is then added to the result set, and each row--- therein is then fed back to @f@, and this process is repeated until a--- generation comes along for which @f@ returns no rows that don't already--- exist in the result set.-loopDistinct :: Table Expr a => Query a -> (a -> Query a) -> Query a-loopDistinct base recurse =-  fromOpaleye $ withRecursiveDistinctExplicit binaryspec base' recurse'-  where-    base' = toOpaleye base-    recurse' = toOpaleye . recurse
− src/Rel8/Query/Materialize.hs
@@ -1,40 +0,0 @@-{-# language FlexibleContexts #-}--module Rel8.Query.Materialize-  ( materialize-  )-where---- base-import Prelude---- opaleye-import Opaleye.With ( withMaterializedExplicit )---- rel8-import Rel8.Expr ( Expr )-import Rel8.Query ( Query )-import Rel8.Query.Opaleye ( fromOpaleye, toOpaleye )-import Rel8.Table ( Table )-import Rel8.Table.Opaleye ( unpackspec )----- | 'materialize' takes a 'Query' and fully evaluates it and caches the--- results thereof, and passes to a continuation a new 'Query' that simply--- looks up these cached results. It's usually best not to use this and to let--- the Postgres optimizer decide for itself what's best, but if you know what--- you're doing this can sometimes help to nudge it in a particular direction.------ 'materialize' is currently implemented in terms of Postgres'--- [@WITH](https://www.postgresql.org/docs/current/queries-with.html) syntax,--- specifically the @WITH _ AS MATERIALIZED (_)@ form introduced in PostgreSQL--- 12. This means that 'materialize' can only be used with PostgreSQL 12 or--- newer.-materialize :: Table Expr a => Query a -> (Query a -> Query b) -> Query b-materialize query f =-  fromOpaleye $-    withMaterializedExplicit unpackspec-      (toOpaleye query')-      (toOpaleye . f . fromOpaleye)-  where-    query' = query
− src/Rel8/Query/Maybe.hs
@@ -1,64 +0,0 @@-{-# language GADTs #-}-{-# language LambdaCase #-}-{-# language NamedFieldPuns #-}--module Rel8.Query.Maybe-  ( optional-  , catMaybeTable-  , traverseMaybeTable-  )-where---- base-import Prelude---- comonad-import Control.Comonad ( extract )---- opaleye-import qualified Opaleye.Internal.MaybeFields as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Eq ( (==.) )-import Rel8.Query ( Query )-import Rel8.Query.Filter ( where_ )-import Rel8.Query.Opaleye ( mapOpaleye )-import Rel8.Table.Maybe (MaybeTable(..), isJustTable, makeMaybeTable)----- | Convert a query that might return zero rows to a query that always returns--- at least one row.------ To speak in more concrete terms, 'optional' is most useful to write @LEFT--- JOIN@s.-optional :: Query a -> Query (MaybeTable Expr a)-optional = mapOpaleye $ Opaleye.optionalInternal makeMaybeTable----- | Filter out 'MaybeTable's, returning only the tables that are not-null.------ This operation can be used to "undo" the effect of 'optional', which--- operationally is like turning a @LEFT JOIN@ back into a full @JOIN@.  You--- can think of this as analogous to 'Data.Maybe.catMaybes'.-catMaybeTable :: MaybeTable Expr a -> Query a-catMaybeTable ma@(MaybeTable _ a) = do-  where_ $ isJustTable ma-  pure (extract a)----- | Extend an optional query with another query.  This is useful if you want--- to step through multiple @LEFT JOINs@.------ Note that @traverseMaybeTable@ takes a @a -> Query b@ function, which means--- you also have the ability to "expand" one row into multiple rows.  If the--- @a -> Query b@ function returns no rows, then the resulting query will also--- have no rows. However, regardless of the given @a -> Query b@ function, if--- the input is @nothingTable@, you will always get exactly one @nothingTable@--- back.-traverseMaybeTable :: (a -> Query b) -> MaybeTable Expr  a -> Query (MaybeTable Expr b)-traverseMaybeTable query ma@(MaybeTable input _) = do-  optional (query =<< catMaybeTable ma) >>= \case-    MaybeTable output b -> do-      where_ $ output ==. input-      pure $ MaybeTable input b
− src/Rel8/Query/Null.hs
@@ -1,38 +0,0 @@-{-# language FlexibleContexts #-}--module Rel8.Query.Null-  ( catNull-  , catNullTable-  )-where---- base-import Prelude---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Null ( isNonNull, unsafeUnnullify )-import Rel8.Table ( Table )-import Rel8.Table.Null ( NullTable, isNonNullTable, unsafeUnnullifyTable )-import Rel8.Query ( Query )-import Rel8.Query.Filter ( where_ )----- | Filter a 'Query' that might return @null@ to a 'Query' without any--- @null@s.------ Corresponds to 'Data.Maybe.catMaybes'.-catNull :: Expr (Maybe a) -> Query (Expr a)-catNull a = do-  where_ $ isNonNull a-  pure $ unsafeUnnullify a----- | Filter a 'Query' that might return @nullTable@ to a 'Query' without any--- @nullTable@s.------ Corresponds to 'Data.Maybe.catMaybes'.-catNullTable :: Table Expr a => NullTable Expr a -> Query a-catNullTable a = do-  where_ $ isNonNullTable a-  pure $ unsafeUnnullifyTable a
− src/Rel8/Query/Opaleye.hs
@@ -1,70 +0,0 @@-{-# language TupleSections #-}--module Rel8.Query.Opaleye-  ( fromOpaleye-  , toOpaleye-  , mapOpaleye-  , zipOpaleyeWith-  , unsafePeekQuery-  )-where---- base-import Control.Applicative ( liftA2 )-import Prelude---- opaleye-import qualified Opaleye.Internal.QueryArr as Opaleye-import qualified Opaleye.Internal.Tag as Opaleye---- rel8-import {-# SOURCE #-} Rel8.Query ( Query( Query ) )---fromOpaleye :: Opaleye.Select a -> Query a-fromOpaleye = Query . pure . fmap pure---toOpaleye :: Query a -> Opaleye.Select a-toOpaleye (Query a) = snd <$> a mempty---mapOpaleye :: (Opaleye.Select a -> Opaleye.Select b) -> Query a -> Query b-mapOpaleye f (Query a) = Query (fmap (mapping f) a)---zipOpaleyeWith :: ()-  => (Opaleye.Select a -> Opaleye.Select b -> Opaleye.Select c)-  -> Query a -> Query b -> Query c-zipOpaleyeWith f (Query a) (Query b) = Query $ liftA2 (zipping f) a b---unsafePeekQuery :: Query a -> a-unsafePeekQuery (Query q) = case q mempty of-  f -> case Opaleye.runStateQueryArr f () Opaleye.start of-    ((_, a), _, _) -> a---mapping :: ()-  => (Opaleye.Select a -> Opaleye.Select b)-  -> Opaleye.Select (m, a) -> Opaleye.Select (m, b)-mapping f q = Opaleye.stateQueryArr $ \_ tag ->-  let-    ((m, _), _, _) = Opaleye.runStateQueryArr q () tag-    q' = (m,) <$> f (snd <$> q)-  in-    Opaleye.runStateQueryArr q' () tag---zipping :: Semigroup m-  => (Opaleye.Select a -> Opaleye.Select b -> Opaleye.Select c)-  -> Opaleye.Select (m, a) -> Opaleye.Select (m, b) -> Opaleye.Select (m, c)-zipping f q q' =-  Opaleye.stateQueryArr $ \_ tag ->-    let-      ((m, _), _, _) = Opaleye.runStateQueryArr q () tag-      ((m', _), _, _) = Opaleye.runStateQueryArr q' () tag-      m'' = m <> m'-      q'' = (m'',) <$> f (snd <$> q) (snd <$> q')-    in-      Opaleye.runStateQueryArr q'' () tag
− src/Rel8/Query/Order.hs
@@ -1,20 +0,0 @@-module Rel8.Query.Order-  ( orderBy-  )-where---- base-import Prelude ()---- opaleye-import qualified Opaleye.Order as Opaleye ( orderBy )---- rel8-import Rel8.Order ( Order( Order ) )-import Rel8.Query ( Query )-import Rel8.Query.Opaleye ( mapOpaleye )----- | Order the rows returned by a query.-orderBy :: Order a -> Query a -> Query a-orderBy (Order o) = mapOpaleye (Opaleye.orderBy o)
− src/Rel8/Query/Rebind.hs
@@ -1,36 +0,0 @@-{-# language FlexibleContexts #-}--module Rel8.Query.Rebind-  ( rebind-  , hrebind-  )-where---- base-import Prelude-import Control.Arrow ((<<<))---- opaleye-import qualified Opaleye.Internal.Rebind as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Query ( Query )-import Rel8.Query.Limit (offset)-import Rel8.Schema.HTable (HTable)-import Rel8.Table ( Table )-import Rel8.Table.Cols (Cols (Cols))-import Rel8.Table.Opaleye ( unpackspec )-import Rel8.Query.Opaleye (fromOpaleye)----- | 'rebind' takes a variable name, some expressions, and binds each of them--- to a new variable in the SQL. The @a@ returned consists only of these--- variables. It's essentially a @let@ binding for Postgres expressions.-rebind :: Table Expr a => String -> a -> Query a-rebind prefix a = offset 0 $-  fromOpaleye (Opaleye.rebindExplicitPrefix prefix unpackspec <<< pure a)---hrebind :: HTable t => String -> t Expr -> Query (t Expr)-hrebind prefix = fmap (\(Cols a) -> a) . rebind prefix . Cols
− src/Rel8/Query/SQL.hs
@@ -1,27 +0,0 @@-{-# language FlexibleContexts #-}-{-# language MonoLocalBinds #-}--module Rel8.Query.SQL-  ( showQuery-  )-where---- base-import Prelude---- opaleye-import qualified Opaleye.Internal.Tag as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Query ( Query )-import Rel8.Statement.Select ( ppSelect )-import Rel8.Table ( Table )---- transformers-import Control.Monad.Trans.State.Strict (evalState)----- | Convert a 'Query' to a 'String' containing a @SELECT@ statement.-showQuery :: Table Expr a => Query a -> String-showQuery = show . (`evalState` Opaleye.start) . ppSelect
− src/Rel8/Query/Set.hs
@@ -1,58 +0,0 @@-{-# language FlexibleContexts #-}--module Rel8.Query.Set-  ( union, unionAll-  , intersect, intersectAll-  , except, exceptAll-  )-where---- base-import Prelude ()---- opaleye-import qualified Opaleye.Binary as Opaleye---- rel8-import Rel8.Expr ( Expr )-import {-# SOURCE #-} Rel8.Query ( Query )-import Rel8.Query.Opaleye ( zipOpaleyeWith )-import Rel8.Table ( Table  )-import Rel8.Table.Eq ( EqTable )-import Rel8.Table.Opaleye ( binaryspec )----- | Combine the results of two queries of the same type, collapsing--- duplicates.  @union a b@ is the same as the SQL statement @a UNION b@.-union :: EqTable a => Query a -> Query a -> Query a-union = zipOpaleyeWith (Opaleye.unionExplicit binaryspec)----- | Combine the results of two queries of the same type, retaining duplicates.--- @unionAll a b@ is the same as the SQL statement @a UNION ALL b@.-unionAll :: Table Expr a => Query a -> Query a -> Query a-unionAll = zipOpaleyeWith (Opaleye.unionAllExplicit binaryspec)----- | Find the intersection of two queries, collapsing duplicates.  @intersect a--- b@ is the same as the SQL statement @a INTERSECT b@.-intersect :: EqTable a => Query a -> Query a -> Query a-intersect = zipOpaleyeWith (Opaleye.intersectExplicit binaryspec)----- | Find the intersection of two queries, retaining duplicates.  @intersectAll--- a b@ is the same as the SQL statement @a INTERSECT ALL b@.-intersectAll :: EqTable a => Query a -> Query a -> Query a-intersectAll = zipOpaleyeWith (Opaleye.intersectAllExplicit binaryspec)----- | Find the difference of two queries, collapsing duplicates @except a b@ is--- the same as the SQL statement @a EXCEPT b@.-except :: EqTable a => Query a -> Query a -> Query a-except = zipOpaleyeWith (Opaleye.exceptExplicit binaryspec)----- | Find the difference of two queries, retaining duplicates.  @exceptAll a b@--- is the same as the SQL statement @a EXCEPT ALL b@.-exceptAll :: EqTable a => Query a -> Query a -> Query a-exceptAll = zipOpaleyeWith (Opaleye.exceptAllExplicit binaryspec)
− src/Rel8/Query/These.hs
@@ -1,138 +0,0 @@-{-# language FlexibleContexts #-}-{-# language GADTs #-}--module Rel8.Query.These-  ( alignBy-  , keepHereTable, loseHereTable-  , keepThereTable, loseThereTable-  , keepThisTable, loseThisTable-  , keepThatTable, loseThatTable-  , keepThoseTable, loseThoseTable-  , bitraverseTheseTable-  )-where---- base-import Prelude---- comonad-import Control.Comonad ( extract )---- opaleye-import qualified Opaleye.Internal.PackMap as Opaleye-import qualified Opaleye.Internal.PrimQuery as Opaleye-import qualified Opaleye.Internal.QueryArr as Opaleye-import qualified Opaleye.Internal.Tag as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Bool ( boolExpr, not_ )-import Rel8.Expr.Eq ( (==.) )-import Rel8.Expr.Opaleye ( toPrimExpr, traversePrimExpr )-import Rel8.Expr.Serialize ( litExpr )-import Rel8.Query ( Query )-import Rel8.Query.Filter ( where_ )-import Rel8.Query.Maybe ( optional )-import Rel8.Query.Opaleye ( zipOpaleyeWith )-import Rel8.Table.Either ( EitherTable( EitherTable ) )-import Rel8.Table.Maybe ( MaybeTable( MaybeTable ), isJustTable )-import Rel8.Table.These-  ( TheseTable( TheseTable, here, there )-  , hasHereTable, hasThereTable-  , isThisTable, isThatTable, isThoseTable-  )-import Rel8.Type.Tag ( EitherTag( IsLeft, IsRight ) )----- | Corresponds to a @FULL OUTER JOIN@ between two queries.-alignBy :: ()-  => (a -> b -> Expr Bool)-  -> Query a -> Query b -> Query (TheseTable Expr a b)-alignBy condition = zipOpaleyeWith $ \left right -> Opaleye.stateQueryArr $ \_ t -> case t of-  tag -> (tab, join', tag''')-    where-      (ma, left', tag') = Opaleye.runStateQueryArr (pure <$> left) () tag-      (mb, right', tag'') = Opaleye.runStateQueryArr (pure <$> right) () tag'-      MaybeTable hasHere a = ma-      MaybeTable hasThere b = mb-      (hasHere', lbindings) = Opaleye.run $ do-        traversePrimExpr (Opaleye.extractAttr "hasHere" tag'') hasHere-      (hasThere', rbindings) = Opaleye.run $ do-        traversePrimExpr (Opaleye.extractAttr "hasThere" tag'') hasThere-      tag''' = Opaleye.next tag''-      join = Opaleye.Join Opaleye.FullJoin on left'' right''-        where-          on = toPrimExpr $ condition (extract a) (extract b)-          left'' = (Opaleye.NonLateral, Opaleye.toPrimQuery (left' <> Opaleye.aRebind lbindings))-          right'' = (Opaleye.NonLateral, Opaleye.toPrimQuery (right' <> Opaleye.aRebind rbindings))-      ma' = MaybeTable hasHere' a-      mb' = MaybeTable hasThere' b-      tab = TheseTable {here = ma', there = mb'}-      join' = Opaleye.aProduct join---keepHereTable :: TheseTable Expr a b -> Query (a, MaybeTable Expr b)-keepHereTable = loseThatTable---loseHereTable :: TheseTable Expr a b -> Query b-loseHereTable = keepThatTable---keepThereTable :: TheseTable Expr a b -> Query (MaybeTable Expr a, b)-keepThereTable = loseThisTable---loseThereTable :: TheseTable Expr a b -> Query a-loseThereTable = keepThisTable---keepThisTable :: TheseTable Expr a b -> Query a-keepThisTable t@(TheseTable (MaybeTable _ a) _) = do-  where_ $ isThisTable t-  pure (extract a)---loseThisTable :: TheseTable Expr a b -> Query (MaybeTable Expr a, b)-loseThisTable t@(TheseTable ma (MaybeTable _ b)) = do-  where_ $ not_ $ isThisTable t-  pure (ma, extract b)---keepThatTable :: TheseTable Expr a b -> Query b-keepThatTable t@(TheseTable _ (MaybeTable _ b)) = do-  where_ $ isThatTable t-  pure (extract b)---loseThatTable :: TheseTable Expr a b -> Query (a, MaybeTable Expr b)-loseThatTable t@(TheseTable (MaybeTable _ a) mb) = do-  where_ $ not_ $ isThatTable t-  pure (extract a, mb)---keepThoseTable :: TheseTable Expr a b -> Query (a, b)-keepThoseTable t@(TheseTable (MaybeTable _ a) (MaybeTable _ b)) = do-  where_ $ isThoseTable t-  pure (extract a, extract b)---loseThoseTable :: TheseTable Expr a b -> Query (EitherTable Expr a b)-loseThoseTable t@(TheseTable (MaybeTable _ a) (MaybeTable _ b)) = do-  where_ $ not_ $ isThoseTable t-  pure $ EitherTable tag a b-  where-    tag = boolExpr (litExpr IsLeft) (litExpr IsRight) (isThatTable t)---bitraverseTheseTable :: ()-  => (a -> Query c)-  -> (b -> Query d)-  -> TheseTable Expr a b-  -> Query (TheseTable Expr c d)-bitraverseTheseTable f g t = do-  mc <- optional (f . fst =<< keepHereTable t)-  md <- optional (g . snd =<< keepThereTable t)-  where_ $ isJustTable mc ==. hasHereTable t-  where_ $ isJustTable md ==. hasThereTable t-  pure $ TheseTable mc md
− src/Rel8/Query/Values.hs
@@ -1,27 +0,0 @@-{-# language FlexibleContexts #-}--module Rel8.Query.Values-  ( values-  )-where---- base-import Data.Foldable ( toList )-import Prelude---- opaleye-import qualified Opaleye.Values as Opaleye---- rel8-import Rel8.Expr ( Expr )-import {-# SOURCE #-} Rel8.Query ( Query )-import Rel8.Query.Opaleye ( fromOpaleye )-import Rel8.Table ( Table )-import Rel8.Table.Opaleye ( valuesspec )----- | Construct a query that returns the given input list of rows. This is like--- folding a list of 'return' statements under 'Rel8.union', but uses the SQL--- @VALUES@ expression for efficiency.-values :: (Table Expr a, Foldable f) => f a -> Query a-values = fromOpaleye . Opaleye.valuesExplicit valuesspec . toList
− src/Rel8/Query/Window.hs
@@ -1,26 +0,0 @@-module Rel8.Query.Window-  ( window-  )-where---- base-import Prelude ()---- opaleye-import qualified Opaleye.Window as Opaleye---- rel8-import Rel8.Query ( Query )-import Rel8.Query.Opaleye ( mapOpaleye )-import Rel8.Window ( Window( Window ) )----- | 'window' runs a query composed of expressions containing--- [window functions](https://www.postgresql.org/docs/current/tutorial-window.html).--- 'window' is similar to 'Rel8.aggregate', with the main difference being--- that in a window query, each input row corresponds to one output row,--- whereas aggregation queries fold the entire input query down into a single--- row. To put this into a Haskell context, 'Rel8.aggregate' is to 'foldl' as--- 'window' is to 'scanl'.-window :: Window a b -> Query a -> Query b-window (Window a) = mapOpaleye (Opaleye.runWindows a)
+ src/Rel8/Range.hs view
@@ -0,0 +1,33 @@+module Rel8.Range (+  -- * Basic range functionality+  Bound (Incl, Excl, Inf),+  Range (Empty, Range),+  Multirange (Multirange),+  range,+  multirange,+  rangeAgg,+ +  -- * Defining new range types+  DBRange (+    rangeTypeName, rangeDecoder, rangeEncoder,+    multirangeTypeName, multirangeDecoder, multirangeEncoder+  )+) where++-- base+import Prelude ()++-- rel8+import Rel8.Internal.Aggregate.Range (rangeAgg)+import Rel8.Internal.Data.Range (+  Bound (Incl, Excl, Inf),+  Range (Empty, Range),+  Multirange (Multirange),+ )+import Rel8.Internal.Expr.Range (range, multirange)+import Rel8.Internal.Type.Range (+  DBRange (+    rangeTypeName, rangeDecoder, rangeEncoder,+    multirangeTypeName, multirangeDecoder, multirangeEncoder+  ),+ )
− src/Rel8/Schema/Context/Nullify.hs
@@ -1,130 +0,0 @@-{-# language DataKinds #-}-{-# language EmptyCase #-}-{-# language FlexibleContexts #-}-{-# language GADTs #-}-{-# language LambdaCase #-}-{-# language NamedFieldPuns #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Schema.Context.Nullify-  ( Nullifiability(..), NonNullifiability(..), nullifiableOrNot, absurd-  , Nullifiable, nullifiability-  , guarder, nullifier, unnullifier-  )-where---- base-import Data.Bool ( bool )-import Data.Functor.Identity ( Identity( Identity ) )-import Data.Kind ( Constraint, Type )-import Prelude hiding ( null )---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Bool ( boolExpr )-import Rel8.Expr.Null ( nullify, unsafeUnnullify )-import Rel8.Expr.Opaleye ( fromPrimExpr )-import Rel8.Kind.Context ( SContext(..) )-import Rel8.Schema.Field ( Field )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Name ( Name( Name ) )-import Rel8.Schema.Null ( Nullify, Nullity( Null, NotNull ) )-import Rel8.Schema.Result ( Result )-import Rel8.Schema.Spec ( Spec(..) )---type Nullifiability :: K.Context -> Type-data Nullifiability context where-  NExpr :: Nullifiability Expr-  NName :: Nullifiability Name---type Nullifiable :: K.Context -> Constraint-class Nullifiable context where-  nullifiability :: Nullifiability context---instance Nullifiable Expr where-  nullifiability = NExpr---instance Nullifiable Name where-  nullifiability = NName---type NonNullifiability :: K.Context -> Type-data NonNullifiability context where-  NField :: NonNullifiability (Field table)-  NResult :: NonNullifiability Result---nullifiableOrNot :: ()-  => SContext context-  -> Either (NonNullifiability context) (Nullifiability context)-nullifiableOrNot = \case-  SExpr -> Right NExpr-  SField -> Left NField-  SName -> Right NName-  SResult -> Left NResult---absurd :: Nullifiability context -> NonNullifiability context -> a-absurd = \case-  NExpr -> \case-  NName -> \case---guarder :: ()-  => SContext context-  -> context tag-  -> (tag -> Bool)-  -> (Expr tag -> Expr Bool)-  -> context (Maybe a)-  -> context (Maybe a)-guarder = \case-  SExpr -> \tag _ isNonNull -> sguard (isNonNull tag)-  SField -> \_ _ _ -> id-  SName -> \_ _ _ -> id-  SResult -> \(Identity tag) isNonNull _ (Identity a) ->-    Identity (bool Nothing a (isNonNull tag))---nullifier :: ()-  => Nullifiability context-  -> Spec a-  -> context a-  -> context (Nullify a)-nullifier = \case-  NExpr -> \Spec {nullity} a -> snullify nullity a-  NName -> \_ (Name a) -> Name a---unnullifier :: ()-  => Nullifiability context-  -> Spec a-  -> context (Nullify a)-  -> context a-unnullifier = \case-  NExpr -> \Spec {nullity} a -> sunnullify nullity a-  NName -> \_ (Name a) -> Name a---sguard :: Expr Bool -> Expr (Maybe a) -> Expr (Maybe a)-sguard condition a = boolExpr null a condition-  where-    null = fromPrimExpr $ Opaleye.ConstExpr Opaleye.NullLit---snullify :: Nullity a -> Expr a -> Expr (Nullify a)-snullify nullity a = case nullity of-  Null -> a-  NotNull -> nullify a---sunnullify :: Nullity a -> Expr (Nullify a) -> Expr a-sunnullify nullity a = case nullity of-  Null -> a-  NotNull -> unsafeUnnullify a
− src/Rel8/Schema/Dict.hs
@@ -1,18 +0,0 @@-{-# language ConstraintKinds #-}-{-# language GADTs #-}-{-# language PolyKinds #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Schema.Dict-  ( Dict( Dict )-  )-where---- base-import Data.Kind ( Constraint, Type )-import Prelude ()---type Dict :: (a -> Constraint) -> a -> Type-data Dict c a where-  Dict :: c a => Dict c a
− src/Rel8/Schema/Escape.hs
@@ -1,20 +0,0 @@-{-# language LambdaCase #-}--module Rel8.Schema.Escape-  ( escape-  )-where---- base-import Prelude---- pretty-import Text.PrettyPrint (Doc, doubleQuotes, text)---escape :: String -> Doc-escape = doubleQuotes . text . concatMap go-  where-    go = \case-      '"' -> "\"\""-      c -> [c]
− src/Rel8/Schema/Field.hs
@@ -1,50 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language MultiParamTypeClasses #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}--module Rel8.Schema.Field-  ( Field(..)-  , fields-  )-where---- base-import Data.Functor.Identity ( Identity( Identity ) )-import Data.Kind ( Type )-import Prelude---- rel8-import Rel8.Schema.HTable ( HField, htabulate )-import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )-import Rel8.Schema.Kind as K-import Rel8.Schema.Null ( Sql )-import Rel8.Table-  ( Table, Columns, Context, fromColumns, toColumns-  , FromExprs, fromResult, toResult-  , Transpose-  )-import Rel8.Table.Transpose ( Transposes )-import Rel8.Type ( DBType )----- | A special context used in the construction of 'Rel8.Projection's.-type Field :: Type -> K.Context-newtype Field table a = Field (HField (Columns table) a)---instance Sql DBType a => Table (Field table) (Field table a) where-  type Columns (Field table a) = HIdentity a-  type Context (Field table a) = Field table-  type FromExprs (Field table a) = a-  type Transpose to (Field table a) = to a--  toColumns = HIdentity-  fromColumns (HIdentity a) = a-  toResult a = HIdentity (Identity a)-  fromResult (HIdentity (Identity a)) = a---fields :: Transposes context (Field table) table fields => fields-fields = fromColumns $ htabulate Field
− src/Rel8/Schema/HTable.hs
@@ -1,236 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language DataKinds #-}-{-# language DefaultSignatures #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language FunctionalDependencies #-}-{-# language LambdaCase #-}-{-# language RankNTypes #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilyDependencies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Schema.HTable-  ( HTable (HField, HConstrainTable)-  , hfield, htabulate, hdicts, hspecs-  , hfoldMap, hmap, htabulateA, htabulateP-  , htraverse, htraverse_, htraverseP, htraversePWithField-  )-where---- base-import Data.Functor (void)-import Data.Functor.Compose ( Compose( Compose ), getCompose )-import Data.Functor.Const ( Const( Const ), getConst )-import Data.Kind ( Constraint, Type )-import Data.Proxy ( Proxy )-import GHC.Generics-  ( (:*:)( (:*:) )-  , Generic (Rep, from, to)-  , K1( K1 )-  , M1( M1 )-  )-import Prelude---- profunctors-import Data.Profunctor ( rmap, Profunctor (lmap) )---- product-profunctors-import Data.Profunctor.Product ( ProductProfunctor ((****)) )---- rel8-import Rel8.Schema.Dict ( Dict )-import Rel8.Schema.Spec ( Spec )-import Rel8.Schema.HTable.Product ( HProduct( HProduct ) )-import qualified Rel8.Schema.Kind as K---- semigroupoids-import Data.Functor.Apply (Apply, (<.>), liftF2)---- | A @HTable@ is a functor-indexed/higher-kinded data type that is--- representable ('htabulate'/'hfield'), constrainable ('hdicts'), and--- specified ('hspecs').------ This is an internal concept for Rel8, and you should not need to define--- instances yourself or specify this constraint.-type HTable :: K.HTable -> Constraint-class HTable t where-  type HField t = (field :: Type -> Type) | field -> t-  type HConstrainTable t (c :: Type -> Constraint) :: Constraint--  hfield :: t context -> HField t a -> context a-  htabulate :: (forall a. HField t a -> context a) -> t context-  htraverse :: Apply m => (forall a. f a -> m (g a)) -> t f -> m (t g)-  hdicts :: HConstrainTable t c => t (Dict c)-  hspecs :: t Spec--  type HField t = GHField t-  type HConstrainTable t c = HConstrainTable (GHColumns (Rep (t Proxy))) c--  default hfield ::-    ( Generic (t context)-    , HField t ~ GHField t-    , HField (GHColumns (Rep (t Proxy))) ~ HField (GHColumns (Rep (t context)))-    , GHTable context (Rep (t context))-    )-    => t context -> HField t a -> context a-  hfield table (GHField field) = hfield (toGHColumns (from table)) field--  default htabulate ::-    ( Generic (t context)-    , HField t ~ GHField t-    , HField (GHColumns (Rep (t Proxy))) ~ HField (GHColumns (Rep (t context)))-    , GHTable context (Rep (t context))-    )-    => (forall a. HField t a -> context a) -> t context-  htabulate f = to $ fromGHColumns $ htabulate (f . GHField)--  default htraverse-    :: forall f g m-     . ( Apply m-       , Generic (t f), GHTable f (Rep (t f))-       , Generic (t g), GHTable g (Rep (t g))-       , GHColumns (Rep (t f)) ~ GHColumns (Rep (t g))-       )-    => (forall a. f a -> m (g a)) -> t f -> m (t g)-  htraverse f = fmap (to . fromGHColumns) . htraverse f . toGHColumns . from--  default hdicts-    :: forall c-     . ( Generic (t (Dict c))-       , GHTable (Dict c) (Rep (t (Dict c)))-       , GHColumns (Rep (t Proxy)) ~ GHColumns (Rep (t (Dict c)))-       , HConstrainTable (GHColumns (Rep (t Proxy))) c-       )-    => t (Dict c)-  hdicts = to $ fromGHColumns (hdicts @(GHColumns (Rep (t Proxy))) @c)--  default hspecs ::-    ( Generic (t Spec)-    , GHTable Spec (Rep (t Spec))-    )-    => t Spec-  hspecs = to $ fromGHColumns hspecs--  {-# INLINABLE hfield #-}-  {-# INLINABLE htabulate #-}-  {-# INLINABLE htraverse #-}-  {-# INLINABLE hdicts #-}-  {-# INLINABLE hspecs #-}---hfoldMap :: (HTable t, Semigroup s)-  => (forall a. context a -> s) -> t context -> s-hfoldMap f a = getConst $ htraverse (Const . f) a---hmap :: HTable t-  => (forall a. context a -> context' a) -> t context -> t context'-hmap f a = htabulate $ \field -> f (hfield a field)---newtype Ap f a = Ap-  { getAp :: f a-  }---instance (Apply f, Semigroup a) => Semigroup (Ap f a) where-  Ap a <> Ap b = Ap (liftF2 (<>) a b)---htraverse_ :: (HTable t, Apply f)-  => (forall a. context a -> f b) -> t context -> f ()-htraverse_ f a = getAp $ hfoldMap (Ap . void . f) a---htabulateA :: (HTable t, Apply m)-  => (forall a. HField t a -> m (context a)) -> m (t context)-htabulateA f = htraverse getCompose $ htabulate $ Compose . f-{-# INLINABLE htabulateA #-}---htabulateP :: (HTable t, ProductProfunctor p)-  => (forall a. HField t a -> p i (context a)) -> p i (t context)-htabulateP f = unApplyP $ htraverse (ApplyP . getCompose) $ htabulate $ Compose . f-{-# INLINABLE htabulateP #-}---newtype ApplyP p a b = ApplyP { unApplyP :: p a b }---instance Profunctor p => Functor (ApplyP p a) where-  fmap f = ApplyP . rmap f . unApplyP---instance ProductProfunctor p => Apply (ApplyP p a) where-  ApplyP f <.> ApplyP x = ApplyP (rmap id f **** x)---htraverseP :: (HTable t, ProductProfunctor p)-  => (forall a. p (f a) (g a)) -> p (t f) (t g)-htraverseP f = htraversePWithField (const f)---htraversePWithField :: (HTable t, ProductProfunctor p)-  => (forall a. HField t a -> p (f a) (g a)) -> p (t f) (t g)-htraversePWithField f =-  htabulateP $ \field -> lmap (flip hfield field) (f field)---type GHField :: K.HTable -> Type -> Type-newtype GHField t a = GHField (HField (GHColumns (Rep (t Proxy))) a)---type GHTable :: K.Context -> (Type -> Type) -> Constraint-class HTable (GHColumns rep) => GHTable context rep | rep -> context where-  type GHColumns rep :: K.HTable-  toGHColumns :: rep x -> GHColumns rep context-  fromGHColumns :: GHColumns rep context -> rep x---instance GHTable context rep => GHTable context (M1 i c rep) where-  type GHColumns (M1 i c rep) = GHColumns rep-  toGHColumns (M1 a) = toGHColumns a-  fromGHColumns = M1 . fromGHColumns---instance HTable table => GHTable context (K1 i (table context)) where-  type GHColumns (K1 i (table context)) = table-  toGHColumns (K1 a) = a-  fromGHColumns = K1---instance (GHTable context a, GHTable context b) => GHTable context (a :*: b) where-  type GHColumns (a :*: b) = HProduct (GHColumns a) (GHColumns b)-  toGHColumns (a :*: b) = HProduct (toGHColumns a) (toGHColumns b)-  fromGHColumns (HProduct a b) = fromGHColumns a :*: fromGHColumns b----- | A HField type for indexing into HProduct.-type HProductField :: K.HTable -> K.HTable -> Type -> Type-data HProductField x y a-  = HFst (HField x a)-  | HSnd (HField y a)---instance (HTable x, HTable y) => HTable (HProduct x y) where-  type HConstrainTable (HProduct x y) c = (HConstrainTable x c, HConstrainTable y c)-  type HField (HProduct x y) = HProductField x y--  hfield (HProduct l r) = \case-    HFst i -> hfield l i-    HSnd i -> hfield r i--  htabulate f = HProduct (htabulate (f . HFst)) (htabulate (f . HSnd))-  htraverse f (HProduct x y) = HProduct <$> htraverse f x <.> htraverse f y-  hdicts = HProduct hdicts hdicts-  hspecs = HProduct hspecs hspecs--  {-# INLINABLE hfield #-}-  {-# INLINABLE htabulate #-}-  {-# INLINABLE htraverse #-}-  {-# INLINABLE hdicts #-}-  {-# INLINABLE hspecs #-}
− src/Rel8/Schema/HTable/Either.hs
@@ -1,32 +0,0 @@-{-# language DataKinds #-}-{-# language DeriveAnyClass #-}-{-# language DeriveGeneric #-}-{-# language DerivingStrategies #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Schema.HTable.Either-  ( HEitherTable(..)-  )-where---- base-import GHC.Generics ( Generic )-import Prelude ()---- rel8-import Rel8.Schema.HTable ( HTable )-import Rel8.Schema.HTable.Identity ( HIdentity )-import Rel8.Schema.HTable.Label ( HLabel )-import Rel8.Schema.HTable.Nullify ( HNullify )-import qualified Rel8.Schema.Kind as K-import Rel8.Type.Tag ( EitherTag )---type HEitherTable :: K.HTable -> K.HTable -> K.HTable-data HEitherTable left right context = HEitherTable-  { htag :: HLabel "isRight" (HIdentity EitherTag) context-  , hleft :: HLabel "Left" (HNullify left) context-  , hright :: HLabel "Right" (HNullify right) context-  }-  deriving stock Generic-  deriving anyclass HTable
− src/Rel8/Schema/HTable/Identity.hs
@@ -1,43 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}-{-# language UndecidableInstances #-}--module Rel8.Schema.HTable.Identity-  ( HIdentity( HIdentity, unHIdentity )-  )-where---- base-import Data.Kind ( Type )-import Data.Type.Equality ( (:~:)( Refl ) )-import Prelude---- rel8-import Rel8.Schema.Dict ( Dict( Dict ) )-import Rel8.Schema.HTable-  ( HTable, HConstrainTable, HField-  , hfield, htabulate, htraverse, hdicts, hspecs-  )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Null ( Sql )-import Rel8.Schema.Spec ( specification )-import Rel8.Type ( DBType )---type HIdentity :: Type -> K.HTable-newtype HIdentity a context = HIdentity-  { unHIdentity :: context a-  }---instance Sql DBType a => HTable (HIdentity a) where-  type HConstrainTable (HIdentity a) constraint = constraint a-  type HField (HIdentity a) = (:~:) a--  hfield (HIdentity a) Refl = a-  htabulate f = HIdentity $ f Refl-  htraverse f (HIdentity a) = HIdentity <$> f a-  hdicts = HIdentity Dict-  hspecs = HIdentity specification
− src/Rel8/Schema/HTable/Label.hs
@@ -1,70 +0,0 @@-{-# language DataKinds #-}-{-# language RankNTypes #-}-{-# language RecordWildCards #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}--module Rel8.Schema.HTable.Label-  ( HLabel, hlabel, hrelabel, hunlabel-  , hproject-  )-where---- base-import Data.Kind ( Type )-import Data.Proxy ( Proxy( Proxy ) )-import GHC.TypeLits ( KnownSymbol, Symbol, symbolVal )-import Prelude---- rel8-import Rel8.Schema.HTable-  ( HTable, HConstrainTable, HField-  , htabulate, hfield, htraverse, hdicts, hspecs-  )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Spec ( Spec(..) )---type HLabel :: Symbol -> K.HTable -> K.HTable-newtype HLabel label table context = HLabel (table context)---type HLabelField :: Symbol -> K.HTable -> Type -> Type-newtype HLabelField label table a = HLabelField (HField table a)---instance (HTable table, KnownSymbol label) => HTable (HLabel label table) where-  type HField (HLabel label table) = HLabelField label table-  type HConstrainTable (HLabel label table) constraint =-    HConstrainTable table constraint--  hfield (HLabel a) (HLabelField field) = hfield a field-  htabulate f = HLabel (htabulate (f . HLabelField))-  htraverse f (HLabel a) = HLabel <$> htraverse f a-  hdicts = HLabel (hdicts @table)-  hspecs = HLabel $ htabulate $ \field -> case hfield (hspecs @table) field of-    Spec {..} -> Spec {labels = symbolVal (Proxy @label) : labels, ..}-  {-# INLINABLE hspecs #-}---hlabel :: forall label t context. t context -> HLabel label t context-hlabel = HLabel-{-# INLINABLE hlabel #-}---hrelabel :: forall label' label t context. HLabel label t context -> HLabel label' t context-hrelabel = hlabel . hunlabel-{-# INLINABLE hrelabel #-}---hunlabel :: forall label t context. HLabel label t context -> t context-hunlabel (HLabel a) = a-{-# INLINABLE hunlabel #-}---hproject :: ()-  => (forall ctx. t ctx -> t' ctx)-  -> HLabel label t context -> HLabel label t' context-hproject f (HLabel a) = HLabel (f a)
− src/Rel8/Schema/HTable/List.hs
@@ -1,18 +0,0 @@-{-# language DataKinds #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Schema.HTable.List-  ( HListTable-  )-where---- base-import Prelude ()---- rel8-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.HTable.Vectorize ( HVectorize )---type HListTable :: K.HTable -> K.HTable-type HListTable = HVectorize []
− src/Rel8/Schema/HTable/MapTable.hs
@@ -1,99 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language BlockArguments #-}-{-# language ConstraintKinds #-}-{-# language DataKinds #-}-{-# language FlexibleInstances #-}-{-# language GADTs #-}-{-# language InstanceSigs #-}-{-# language MultiParamTypeClasses #-}-{-# language RankNTypes #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language UndecidableInstances #-}-{-# language UndecidableSuperClasses #-}--module Rel8.Schema.HTable.MapTable-  ( HMapTable(..)-  , MapSpec(..)-  , Precompose(..)-  , HMapTableField(..)-  , hproject-  )-where---- base-import Data.Kind ( Constraint, Type )-import Prelude---- rel8-import Rel8.FCF ( Exp, Eval )-import Rel8.Schema.HTable-  ( HTable, HConstrainTable, HField-  , hfield, htabulate, htraverse, hdicts, hspecs-  )-import Rel8.Schema.Spec ( Spec )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Dict ( Dict( Dict ) )---type HMapTable :: (Type -> Exp Type) -> K.HTable -> K.HTable-newtype HMapTable f t context = HMapTable-  { unHMapTable :: t (Precompose f context)-  }---type Precompose :: (Type -> Exp Type) -> K.Context -> K.Context-newtype Precompose f g x = Precompose-  { precomposed :: g (Eval (f x))-  }---type HMapTableField :: (Type -> Exp Type) -> K.HTable -> K.Context-data HMapTableField f t x where-  HMapTableField :: HField t a -> HMapTableField f t (Eval (f a))---instance (HTable t, MapSpec f) => HTable (HMapTable f t) where-  type HField (HMapTable f t) = -    HMapTableField f t--  type HConstrainTable (HMapTable f t) c =-    HConstrainTable t (ComposeConstraint f c)--  hfield (HMapTable x) (HMapTableField i) = -    precomposed (hfield x i) --  htabulate f = -    HMapTable $ htabulate (Precompose . f . HMapTableField)--  htraverse f (HMapTable x) = -    HMapTable <$> htraverse (fmap Precompose . f . precomposed) x-  {-# INLINABLE htraverse #-}--  hdicts :: forall c. HConstrainTable (HMapTable f t) c => HMapTable f t (Dict c)-  hdicts = -    htabulate \(HMapTableField j) ->-      case hfield (hdicts @_ @(ComposeConstraint f c)) j of-        Dict -> Dict--  hspecs = -    HMapTable $ htabulate $ Precompose . mapInfo @f . hfield hspecs-  {-# INLINABLE hspecs #-}---type MapSpec :: (Type -> Exp Type) -> Constraint-class MapSpec f where-  mapInfo :: Spec x -> Spec (Eval (f x))---type ComposeConstraint :: (Type -> Exp Type) -> (Type -> Constraint) -> Type -> Constraint-class c (Eval (f a)) => ComposeConstraint f c a-instance c (Eval (f a)) => ComposeConstraint f c a---hproject :: ()-  => (forall ctx. t ctx -> t' ctx)-  -> HMapTable f t context -> HMapTable f t' context-hproject f (HMapTable a) = HMapTable (f a)
− src/Rel8/Schema/HTable/Maybe.hs
@@ -1,31 +0,0 @@-{-# language DataKinds #-}-{-# language DeriveAnyClass #-}-{-# language DeriveGeneric #-}-{-# language DerivingStrategies #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Schema.HTable.Maybe-  ( HMaybeTable(..)-  )-where---- base-import GHC.Generics ( Generic )-import Prelude---- rel8-import Rel8.Schema.HTable ( HTable )-import Rel8.Schema.HTable.Identity ( HIdentity )-import Rel8.Schema.HTable.Label ( HLabel )-import Rel8.Schema.HTable.Nullify ( HNullify )-import qualified Rel8.Schema.Kind as K-import Rel8.Type.Tag ( MaybeTag )---type HMaybeTable :: K.HTable -> K.HTable-data HMaybeTable table context = HMaybeTable-  { htag :: HLabel "isJust" (HIdentity (Maybe MaybeTag)) context-  , hjust :: HLabel "Just" (HNullify table) context-  }-  deriving stock Generic-  deriving anyclass HTable
− src/Rel8/Schema/HTable/NonEmpty.hs
@@ -1,19 +0,0 @@-{-# language DataKinds #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Schema.HTable.NonEmpty-  ( HNonEmptyTable-  )-where---- base-import Data.List.NonEmpty ( NonEmpty )-import Prelude ()---- rel8-import Rel8.Schema.HTable.Vectorize ( HVectorize )-import qualified Rel8.Schema.Kind as K---type HNonEmptyTable :: K.HTable -> K.HTable-type HNonEmptyTable = HVectorize NonEmpty
− src/Rel8/Schema/HTable/Nullify.hs
@@ -1,123 +0,0 @@-{-# language ConstraintKinds #-}-{-# language DataKinds #-}-{-# language DeriveAnyClass #-}-{-# language DerivingStrategies #-}-{-# language DeriveGeneric #-}-{-# language FlexibleInstances #-}-{-# language GADTs #-}-{-# language LambdaCase #-}-{-# language MultiParamTypeClasses #-}-{-# language NamedFieldPuns #-}-{-# language QuantifiedConstraints #-}-{-# language RankNTypes #-}-{-# language RecordWildCards #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}-{-# language UndecidableInstances #-}--module Rel8.Schema.HTable.Nullify-  ( HNullify( HNullify )-  , Nullify-  , hguard-  , hnulls-  , hnullify-  , hunnullify-  , hproject-  )-where---- base-import Data.Kind ( Type )-import GHC.Generics ( Generic )-import Prelude hiding ( null )---- profunctors-import Data.Profunctor (lmap, rmap)---- product-profunctors-import Data.Profunctor.Product (ProductProfunctor)---- rel8-import Rel8.FCF ( Eval, Exp )-import Rel8.Schema.HTable-  ( HTable, hfield, hspecs, htabulate, htabulateA, htabulateP-  )-import Rel8.Schema.HTable.MapTable-  ( HMapTable, HMapTableField( HMapTableField )-  , MapSpec, mapInfo-  )-import qualified Rel8.Schema.HTable.MapTable as HMapTable ( hproject )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Null ( Nullity( Null, NotNull ) )-import qualified Rel8.Schema.Null as Type ( Nullify )-import Rel8.Schema.Spec ( Spec(..) )---- semigroupoids-import Data.Functor.Apply ( Apply )---type HNullify :: K.HTable -> K.HTable-newtype HNullify table context = HNullify (HMapTable Nullify table context)-  deriving stock Generic-  deriving anyclass HTable----- | Transform a 'Type' by allowing it to be @null@.-data Nullify :: Type -> Exp Type-type instance Eval (Nullify a) = Type.Nullify a---instance MapSpec Nullify where-  mapInfo = \case-    Spec {nullity, ..} -> Spec-      { nullity = case nullity of-          Null    -> Null-          NotNull -> Null-      , ..-      }---hguard :: HTable t-  => (forall a. context (Maybe a) -> context (Maybe a))-  -> HNullify t context -> HNullify t context-hguard guarder (HNullify as) = HNullify $ htabulate $ \(HMapTableField field) ->-  case hfield hspecs field of-    Spec {nullity} -> case hfield as (HMapTableField field) of-      a -> case nullity of-        Null -> guarder a-        NotNull -> guarder a---hnulls :: HTable t-  => (forall a. Spec a -> context (Type.Nullify a))-  -> HNullify t context-hnulls null = HNullify $ htabulate $ \(HMapTableField field) ->-  case hfield hspecs field of-    spec@Spec {} -> null spec-{-# INLINABLE hnulls #-}---hnullify :: (HTable t, ProductProfunctor p)-  => (forall a. Spec a -> p (context a) (context (Type.Nullify a)))-  -> p (t context) (HNullify t context)-hnullify nullifier = rmap HNullify $ htabulateP $ \(HMapTableField field) ->-  lmap (`hfield` field) (nullifier (hfield hspecs field))-{-# INLINABLE hnullify #-}---hunnullify :: (HTable t, Apply m)-  => (forall a. Spec a -> context (Type.Nullify a) -> m (context a))-  -> HNullify t context-  -> m (t context)-hunnullify unnullifier (HNullify as) =-  htabulateA $ \field -> case hfield hspecs field of-    spec@Spec {} -> case hfield as (HMapTableField field) of-      a -> unnullifier spec a-{-# INLINABLE hunnullify #-}---hproject :: ()-  => (forall ctx. t ctx -> t' ctx)-  -> HNullify t context -> HNullify t' context-hproject f (HNullify a) = HNullify (HMapTable.hproject f a)
− src/Rel8/Schema/HTable/Product.hs
@@ -1,17 +0,0 @@-{-# language DataKinds #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Schema.HTable.Product-  ( HProduct(..)-  )-where---- base-import Prelude ()---- rel8-import qualified Rel8.Schema.Kind as K---type HProduct :: K.HTable -> K.HTable -> K.HTable-data HProduct a b context = HProduct (a context) (b context)
− src/Rel8/Schema/HTable/These.hs
@@ -1,33 +0,0 @@-{-# language DataKinds #-}-{-# language DeriveAnyClass #-}-{-# language DeriveGeneric #-}-{-# language DerivingStrategies #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Schema.HTable.These-  ( HTheseTable(..)-  )-where---- base-import GHC.Generics ( Generic )-import Prelude---- rel8-import Rel8.Schema.HTable ( HTable )-import Rel8.Schema.HTable.Identity ( HIdentity )-import Rel8.Schema.HTable.Label ( HLabel )-import Rel8.Schema.HTable.Nullify ( HNullify )-import qualified Rel8.Schema.Kind as K-import Rel8.Type.Tag ( MaybeTag )---type HTheseTable :: K.HTable -> K.HTable -> K.HTable-data HTheseTable here there context = HTheseTable-  { hhereTag :: HLabel "hereTag" (HIdentity (Maybe MaybeTag)) context-  , hhere :: HLabel "Here" (HNullify here) context-  , hthereTag :: HLabel "thereTag" (HIdentity (Maybe MaybeTag)) context-  , hthere :: HLabel "There" (HNullify there) context-  }-  deriving stock Generic-  deriving anyclass HTable
− src/Rel8/Schema/HTable/Vectorize.hs
@@ -1,205 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language ConstraintKinds #-}-{-# language DataKinds #-}-{-# language DeriveAnyClass #-}-{-# language DeriveFunctor #-}-{-# language DeriveGeneric #-}-{-# language DerivingVia #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language GADTs #-}-{-# language LambdaCase #-}-{-# language MultiParamTypeClasses #-}-{-# language NamedFieldPuns #-}-{-# language RankNTypes #-}-{-# language RecordWildCards #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language UndecidableInstances #-}--module Rel8.Schema.HTable.Vectorize-  ( HVectorize-  , hvectorize, hvectorizeA, hunvectorize-  , hnullify-  , happend, hempty-  , hproject-  , htraverseVectorP-  , hcolumn-  , First (..)-  )-where---- base-import Data.Kind ( Constraint, Type )-import Data.List.NonEmpty ( NonEmpty )-import qualified Data.Semigroup as Base-import GHC.Generics (Generic)-import Prelude---- product-profunctors-import Data.Profunctor.Product (ProductProfunctor)---- profunctors-import Data.Profunctor (dimap)---- rel8-import Rel8.FCF ( Eval, Exp )-import Rel8.Schema.Dict ( Dict( Dict ) )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.HTable-  ( HField, HTable, hfield, htabulate, htabulateA, hspecs-  , htraversePWithField-  )-import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )-import Rel8.Schema.HTable.MapTable-  ( HMapTable( HMapTable ), HMapTableField( HMapTableField )-  , MapSpec, mapInfo-  , Precompose( Precompose )-  )-import qualified Rel8.Schema.HTable.MapTable as HMapTable ( hproject )-import Rel8.Schema.HTable.Nullify (HNullify (HNullify))-import Rel8.Schema.Null (Nullify, Unnullify, NotNull, Nullity (NotNull))-import Rel8.Schema.Spec ( Spec(..) )-import Rel8.Type.Array ( listTypeInformation, nonEmptyTypeInformation )-import Rel8.Type.Information ( TypeInformation )---- semialign-import Data.Align (Semialign, alignWith)-import Data.Zip (Unzip, Zip, Zippy(..), zipWith)---- semigroupoids-import Data.Functor.Apply (Apply)---type Vector :: (Type -> Type) -> Constraint-class Vector list where-  listNotNull :: proxy a -> Dict NotNull (list a)-  vectorTypeInformation :: ()-    => Nullity a-    -> TypeInformation (Unnullify a)-    -> TypeInformation (list a)---instance Vector [] where-  listNotNull _ = Dict-  vectorTypeInformation = listTypeInformation---instance Vector NonEmpty where-  listNotNull _ = Dict-  vectorTypeInformation = nonEmptyTypeInformation---type HVectorize :: (Type -> Type) -> K.HTable -> K.HTable-newtype HVectorize list table context = HVectorize (HMapTable (Vectorize list) table context)-  deriving stock Generic-  deriving anyclass HTable---data Vectorize :: (Type -> Type) -> Type -> Exp Type---type instance Eval (Vectorize list a) = list a---instance Vector list => MapSpec (Vectorize list) where-  mapInfo = \case-    Spec {..} -> case listNotNull @list nullity of-      Dict -> Spec-        { nullity = NotNull-        , info = vectorTypeInformation nullity info-        , ..-        }---hvectorize :: (HTable t, Unzip f, Vector list)-  => (forall a. Spec a -> f (context a) -> context' (list a))-  -> f (t context)-  -> HVectorize list t context'-hvectorize vectorizer as = HVectorize $ htabulate $ \(HMapTableField field) ->-  case hfield hspecs field of-    spec -> vectorizer spec (fmap (`hfield` field) as)-{-# INLINABLE hvectorize #-}---hvectorizeA :: (HTable t, Apply f, Vector list)-  => (forall a. Spec a -> HField t a -> f (context' (list a)))-  -> f (HVectorize list t context')-hvectorizeA vectorizer = fmap HVectorize $-  htabulateA $ \(HMapTableField field) ->-    case hfield hspecs field of-      spec -> vectorizer spec field-{-# INLINABLE hvectorizeA #-}---hunvectorize :: (HTable t, Zip f, Vector list)-  => (forall a. Spec a -> context (list a) -> f (context' a))-  -> HVectorize list t context-  -> f (t context')-hunvectorize unvectorizer (HVectorize table) =-  getZippy $ htabulateA $ \field -> case hfield hspecs field of-    spec -> case hfield table (HMapTableField field) of-      a -> Zippy (unvectorizer spec a)-{-# INLINABLE hunvectorize #-}---happend :: (HTable t, Vector list)-  => (forall a. Spec a -> context (list a) -> context (list a) -> context (list a))-  -> HVectorize list t context-  -> HVectorize list t context-  -> HVectorize list t context-happend append (HVectorize as) (HVectorize bs) = HVectorize $-  htabulate $ \field@(HMapTableField j) -> case (hfield as field, hfield bs field) of-    (a, b) -> case hfield hspecs j of-      spec -> append spec a b---hempty :: HTable t-  => (forall a. Spec a -> context [a])-  -> HVectorize [] t context-hempty empty = HVectorize $ htabulate $ \(HMapTableField field) ->-  empty (hfield hspecs field)---hproject :: ()-  => (forall ctx. t ctx -> t' ctx)-  -> HVectorize list t context -> HVectorize list t' context-hproject f (HVectorize a) = HVectorize (HMapTable.hproject f a)---htraverseVectorP :: (HTable t, ProductProfunctor p)-  => (forall a. HField t a -> p (f (list a)) (g (list' a)))-  -> p (HVectorize list t f) (HVectorize list' t g)-htraverseVectorP f =-  dimap (\(HVectorize (HMapTable a)) -> a) (HVectorize . HMapTable) $-    htraversePWithField $ \field ->-      dimap (\(Precompose a) -> a) Precompose (f field)---hcolumn :: HVectorize list (HIdentity a) context -> context (list a)-hcolumn (HVectorize (HMapTable (HIdentity (Precompose a)))) = a---hnullify :: forall t list context. (HTable t, Vector list)-  => (forall a. Spec a -> context (list a) -> context (Nullify a))-  -> HVectorize list t context-  -> HNullify t context-hnullify f (HVectorize table) = HNullify $-  htabulate $ \(HMapTableField field) -> case hfield hspecs field of-    spec -> case hfield table (HMapTableField field) of-      a -> f spec a---newtype First a b = First {getFirst :: a}-  deriving stock Functor-  deriving (Semigroup) via (Base.First a)---instance Semialign (First a) where-  alignWith _ (First a) _ = First a---instance Zip (First a) where-  zipWith _ (First a) _ = First a
− src/Rel8/Schema/Kind.hs
@@ -1,24 +0,0 @@-{-# language StandaloneKindSignatures #-}--module Rel8.Schema.Kind-  ( Rel8able-  , Context-  , HTable-  )-where---- base-import Data.Kind ( Type )-import Prelude ()---type Context :: Type-type Context = Type -> Type---type HTable :: Type-type HTable = Context -> Type---type Rel8able :: Type-type Rel8able = Context -> Type
− src/Rel8/Schema/Name.hs
@@ -1,77 +0,0 @@-{-# language DataKinds #-}-{-# language DerivingStrategies #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language GADTs #-}-{-# language GeneralizedNewtypeDeriving #-}-{-# language MultiParamTypeClasses #-}-{-# language RankNTypes #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}-{-# language UndecidableInstances #-}--module Rel8.Schema.Name-  ( Name(..)-  , Selects-  , ppColumn-  )-where---- base-import Data.Functor.Identity ( Identity( Identity ) )-import Data.Kind ( Constraint, Type )-import Data.String ( IsString )-import Prelude---- opaleye-import qualified Opaleye.Internal.HaskellDB.Sql as Opaleye-import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye---- pretty-import Text.PrettyPrint ( Doc )---- rel8-import Rel8.Expr ( Expr )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )-import Rel8.Schema.Null ( Sql )-import Rel8.Table-  ( Table, Columns, Context, fromColumns, toColumns-  , FromExprs, fromResult, toResult-  , Transpose-  )-import Rel8.Table.Transpose ( Transposes )-import Rel8.Type ( DBType )----- | A @Name@ is the name of a column, as it would be defined in a table's--- schema definition. You can construct names by using the @OverloadedStrings@--- extension and writing string literals. This is typically done when providing--- a 'TableSchema' value.-type Name :: K.Context-newtype Name a = Name String-  deriving stock Show-  deriving newtype IsString---instance Sql DBType a => Table Name (Name a) where-  type Columns (Name a) = HIdentity a-  type Context (Name a) = Name-  type FromExprs (Name a) = a-  type Transpose to (Name a) = to a--  toColumns a = HIdentity a-  fromColumns (HIdentity a) = a-  toResult a = HIdentity (Identity a)-  fromResult (HIdentity (Identity a)) = a----- | @Selects a b@ means that @a@ is a schema (i.e., a 'Table' of 'Name's) for--- the 'Expr' columns in @b@.-type Selects :: Type -> Type -> Constraint-class Transposes Name Expr names exprs => Selects names exprs-instance Transposes Name Expr names exprs => Selects names exprs---ppColumn :: String -> Doc-ppColumn = Opaleye.ppSqlExpr . Opaleye.ColumnSqlExpr . Opaleye.SqlColumn
− src/Rel8/Schema/Null.hs
@@ -1,111 +0,0 @@-{-# language ConstraintKinds #-}-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language GADTs #-}-{-# language MultiParamTypeClasses #-}-{-# language RankNTypes #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}-{-# language UndecidableSuperClasses #-}--module Rel8.Schema.Null-  ( Nullify, Unnullify-  , NotNull-  , Homonullable-  , Nullity( Null, NotNull )-  , Nullable, nullable-  , Sql-  )-where---- base-import Data.Kind ( Constraint, Type )-import Prelude---type IsMaybe :: Type -> Bool-type family IsMaybe a where-  IsMaybe (Maybe _) = 'True-  IsMaybe _ = 'False---type Unnullify' :: Bool -> Type -> Type-type family Unnullify' isMaybe ma where-  Unnullify' 'False a = a-  Unnullify' 'True (Maybe a) = a---type Unnullify :: Type -> Type-type Unnullify a = Unnullify' (IsMaybe a) a---type Nullify' :: Bool -> Type -> Type-type family Nullify' isMaybe a where-  Nullify' 'False a = a-  Nullify' 'True a = Maybe a---type Nullify :: Type -> Type-type Nullify a = Maybe (Unnullify a)----- | @nullify a@ means @a@ cannot take @null@ as a value.-type NotNull :: Type -> Constraint-class (Nullable a, IsMaybe a ~ 'False) => NotNull a-instance (Nullable a, IsMaybe a ~ 'False) => NotNull a----- | @Homonullable a b@ means that both @a@ and @b@ can be @null@, or neither--- @a@ or @b@ can be @null@.-type Homonullable :: Type -> Type -> Constraint-class IsMaybe a ~ IsMaybe b => Homonullable a b-instance IsMaybe a ~ IsMaybe b => Homonullable a b---type Nullity :: Type -> Type-data Nullity a where-  NotNull :: NotNull a => Nullity a-  Null :: NotNull a => Nullity (Maybe a)---type Nullable' :: Bool -> Type -> Constraint-class-  ( IsMaybe a ~ isMaybe-  , IsMaybe (Unnullify a) ~ 'False-  , Nullify' isMaybe (Unnullify a) ~ a-  ) => Nullable' isMaybe a- where-  nullable' :: Nullity a---instance IsMaybe a ~ 'False => Nullable' 'False a where-  nullable' = NotNull---instance IsMaybe a ~ 'False => Nullable' 'True (Maybe a) where-  nullable' = Null----- | @Nullable a@ means that @rel8@ is able to check if the type @a@ is a--- type that can take @null@ values or not.-type Nullable :: Type -> Constraint-class Nullable' (IsMaybe a) a => Nullable a-instance Nullable' (IsMaybe a) a => Nullable a---nullable :: Nullable a => Nullity a-nullable = nullable'----- | The @Sql@ type class describes both null and not null database values,--- constrained by a specific class.------ For example, if you see @Sql DBEq a@, this means any database type that--- supports equality, and @a@ can either be exactly an @a@, or it could also be--- @Maybe a@.-type Sql :: (Type -> Constraint) -> Type -> Constraint-class (constraint (Unnullify a), Nullable a) => Sql constraint a-instance (constraint (Unnullify a), Nullable a) => Sql constraint a
− src/Rel8/Schema/QualifiedName.hs
@@ -1,62 +0,0 @@-{-# language DerivingStrategies #-}-{-# language DuplicateRecordFields #-}-{-# language RecordWildCards #-}-{-# language StandaloneKindSignatures #-}-{-# language StrictData #-}--module Rel8.Schema.QualifiedName-  ( QualifiedName (..)-  , ppQualifiedName-  , showQualifiedName-  , showQualifiedOperator-  )-where---- base-import Data.Kind (Type)-import Data.String (IsString, fromString)-import Prelude---- pretty-import Text.PrettyPrint (Doc, parens, text)---- rel8-import Rel8.Schema.Escape (escape)----- | A name of an object (such as a table, view, function or sequence)--- qualified by an optional schema. In the absence of an explicit schema,--- the connection's @search_path@ will be used implicitly.-type QualifiedName :: Type-data QualifiedName = QualifiedName-  { name :: String-    -- ^ The name of the object.-  , schema :: Maybe String-    -- ^ The schema that this object belongs to. If 'Nothing', whatever is on-    -- the connection's @search_path@ will be used.-   }-  deriving stock (Eq, Ord, Show)----- | Constructs 'QualifiedName's with 'schema' set to 'Nothing'.-instance IsString QualifiedName where-  fromString name = QualifiedName {schema = Nothing, ..}---ppQualifiedName :: QualifiedName -> Doc-ppQualifiedName QualifiedName {schema = mschema, ..} = case mschema of-  Nothing -> name'-  Just schema -> escape schema <> text "." <> name'-  where-    name' = escape name---showQualifiedName :: QualifiedName -> String-showQualifiedName = show . ppQualifiedName---showQualifiedOperator :: QualifiedName -> String-showQualifiedOperator QualifiedName {schema = mschema, ..} = case mschema of-  Nothing -> name-  Just schema ->-    show $ text "OPERATOR" <> parens (escape schema <> text "." <> text name)
− src/Rel8/Schema/Result.hs
@@ -1,54 +0,0 @@-{-# language DataKinds #-}-{-# language GADTs #-}-{-# language NamedFieldPuns #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}--module Rel8.Schema.Result-  ( Result-  , null, nullifier, unnullifier-  , vectorizer, unvectorizer-  )-where---- base-import Data.Functor.Identity ( Identity( Identity), runIdentity )-import Prelude hiding ( null )---- rel8-import Rel8.Schema.Kind ( Context )-import Rel8.Schema.Null ( Nullify, Nullity( Null, NotNull ) )-import Rel8.Schema.Spec ( Spec(..) )----- | The @Result@ context is the context used for decoded query results.------ When a query is executed against a PostgreSQL database, Rel8 parses the--- returned rows, decoding each row into the @Result@ context.-type Result :: Context-type Result = Identity---null :: Result (Maybe a)-null = Identity Nothing---nullifier :: Spec a -> Result a -> Result (Nullify a)-nullifier Spec {nullity} (Identity a) = Identity $ case nullity of-  Null -> a-  NotNull -> Just a---unnullifier :: Spec a -> Result (Nullify a) -> Maybe (Result a)-unnullifier Spec {nullity} (Identity a) =-  case nullity of-    Null -> pure $ Identity a-    NotNull -> Identity <$> a---vectorizer :: Functor f => Spec a -> f (Result a) -> Result (f a)-vectorizer _ = Identity . fmap runIdentity---unvectorizer :: Functor f => Spec a -> Result (f a) -> f (Result a)-unvectorizer _ (Identity results) = Identity <$> results
− src/Rel8/Schema/Spec.hs
@@ -1,34 +0,0 @@-{-# language FlexibleContexts #-}-{-# language MonoLocalBinds #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Schema.Spec-  ( Spec( Spec, labels, info, nullity )-  , specification-  )-where---- base-import Data.Kind ( Type )-import Prelude---- rel8-import Rel8.Schema.Null ( Nullity, Sql, Unnullify, nullable )-import Rel8.Type ( DBType, typeInformation )-import Rel8.Type.Information ( TypeInformation )---type Spec :: Type -> Type-data Spec a = Spec-  { labels :: [String]-  , info :: TypeInformation (Unnullify a)-  , nullity :: Nullity a-  }---specification :: Sql DBType a => Spec a-specification = Spec-  { labels = []-  , info = typeInformation-  , nullity = nullable-  }
− src/Rel8/Schema/Table.hs
@@ -1,43 +0,0 @@-{-# language DeriveFunctor #-}-{-# language DerivingStrategies #-}-{-# language DuplicateRecordFields #-}-{-# language NamedFieldPuns #-}-{-# language StandaloneKindSignatures #-}-{-# language StrictData #-}--module Rel8.Schema.Table-  ( TableSchema(..)-  , ppTable-  )-where---- base-import Data.Kind ( Type )-import Prelude---- pretty-import Text.PrettyPrint ( Doc )---- rel8-import Rel8.Schema.QualifiedName (QualifiedName, ppQualifiedName)----- | The schema for a table. This is used to specify the name and schema that a--- table belongs to (the @FROM@ part of a SQL query), along with the schema of--- the columns within this table.--- --- For each selectable table in your database, you should provide a--- @TableSchema@ in order to interact with the table via Rel8.-type TableSchema :: Type -> Type-data TableSchema names = TableSchema-  { name :: QualifiedName-    -- ^ The name of the table.-  , columns :: names-    -- ^ The columns of the table. Typically you would use a 'Rel8.Rel8able'-    -- data type here, parameterized by the 'Rel8.Name' context.-  }-  deriving stock Functor---ppTable :: TableSchema a -> Doc-ppTable TableSchema {name} = ppQualifiedName name
− src/Rel8/Statement.hs
@@ -1,319 +0,0 @@-{-# language DeriveFunctor #-}-{-# language DerivingVia #-}-{-# language FlexibleContexts #-}-{-# language GADTs #-}-{-# language LambdaCase #-}-{-# language NamedFieldPuns #-}-{-# language RankNTypes #-}-{-# language RecordWildCards #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}--module Rel8.Statement-  ( Statement-  , statementReturning-  , statementNoReturning-  , ppDecodeStatement-  )-where---- base-import Control.Applicative (liftA2)-import Control.Monad (ap, liftM2)-import Data.Foldable (fold, toList)-import Data.Int (Int64)-import Data.Kind (Type)-import Data.List.NonEmpty (NonEmpty, intersperse)-import Data.Monoid (Endo (Endo))-import Data.String (fromString)-import Prelude---- hasql-import qualified Hasql.Decoders as Hasql---- opaleye-import qualified Opaleye.Internal.Tag as Opaleye---- pretty-import Text.PrettyPrint-  ( Doc-  , (<+>)-  , ($$)-  , comma-  , hcat-  , parens-  , punctuate-  , text-  , vcat-  )---- rel8-import Rel8.Expr (Expr)-import Rel8.Expr.Bool (false)-import Rel8.Query (Query)-import Rel8.Query.Aggregate (countRows)-import Rel8.Query.Each (each)-import Rel8.Schema.Escape (escape)-import Rel8.Schema.Table (TableSchema (..))-import Rel8.Statement.Rows (Rows (..))-import Rel8.Table (Table)-import Rel8.Table.Cols (fromCols)-import Rel8.Table.Name (namesFromLabelsWithA, showNames)-import Rel8.Table.Serialize (parse)---- semigroupoids-import Data.Functor.Apply (Apply, WrappedApplicative (..))-import Data.Functor.Bind (Bind, (>>-))---- transformers-import Control.Monad.Trans.Class (lift)-import Control.Monad.Trans.State.Strict (State, evalState)-import Control.Monad.Trans.Writer.CPS (WriterT, runWriterT, tell)---type Binding :: Type-data Binding = Binding-  { relation :: !String-  , columns :: !(Maybe (NonEmpty String))-  , doc :: !Doc-  , returning :: !Returning-  }---type Result :: Type -> Type-data Result a = Unmodified !a | Modified !a---instance Functor Result where-  fmap f = \case-    Unmodified a -> Modified (f a)-    Modified a -> Modified (f a)---getResult :: Result a -> a-getResult = \case-  Unmodified a -> a-  Modified a -> a---type Returning :: Type-data Returning where-  NoReturning :: Returning-  Returning :: Query (Expr Int64) -> Returning ----- | 'Statement' represents a single PostgreSQL statement. Most commonly,--- this is constructed using 'Rel8.select', 'Rel8.insert', 'Rel8.update'--- or 'Rel8.delete'.------ However, in addition to @SELECT@, @INSERT@, @UPDATE@ and @DELETE@,--- PostgreSQL also supports compositions thereof via its statement-level--- @WITH@ syntax (with some caveats). Each such \"sub-statement\" can--- reference the results of previous sub-statements. 'Statement' provides a--- 'Monad' instance that captures this \"binding\" pattern.------ The caveat with this is that the [side-effects of these sub-statements--- are not visible to other sub-statements](https://www.postgresql.org/docs/current/queries-with.html#QUERIES-WITH-MODIFYING);--- only the explicit results of previous sub-statements (from @SELECT@s or--- @RETURNING@ clauses) are visible. So, for example, an @INSERT@ into a table--- followed immediately by a @SELECT@ therefrom will not return the inserted--- rows. However, it is possible to return the inserted rows using--- @RETURNING@, 'Rel8.unionAll'ing this with the result of a @SELECT@--- from the same table will produce the desired result.------ An example of where this can be useful is if you want to delete rows from--- a table and simultaneously log their deletion in a log table.------ @--- deleteFoo :: (Foo Expr -> Expr Bool) -> Statement ()--- deleteFoo predicate = do---   foos <----     delete Delete---       { from = fooSchema---       , using = pure ()---       , deleteWhere = \\_ -> predicate---       , returning = Returning id---       }---   insert Insert---     { into = deletedFooSchema---     , rows = do---         Foo {..} <- foos---         let---           deletedAt = 'Rel8.Expr.Time.now'---         pure DeletedFoo {..}---     , onConflict = Abort---     , returning = NoReturning---     }--- @-newtype Statement a =-  Statement (WriterT (Endo [Binding]) (State Opaleye.Tag) (Result a))-  deriving stock (Functor)-  deriving (Apply) via WrappedApplicative Statement---instance Applicative Statement where-  pure = Statement . pure . Modified-  (<*>) = ap-  liftA2 = liftM2---instance Bind Statement where-  Statement m >>- f = Statement $ do-    result <- m-    case f (getResult result) of-      Statement m' -> m'---instance Monad Statement where-  (>>=) = (>>-)---statementNoReturning :: State Opaleye.Tag Doc -> Statement ()-statementNoReturning pp = Statement $ do-  binding <- lift $ do-    doc <- pp-    tag <- Opaleye.fresh-    let-      relation = Opaleye.tagWith tag "statement"-      columns = Nothing-      returning = NoReturning-      binding = Binding {..}-    pure binding-  tell (Endo (binding :))-  pure $ Unmodified ()---statementReturning :: Table Expr a -  => State Opaleye.Tag Doc -> Statement (Query a)-statementReturning pp = Statement $ do-  (binding, query) <- lift $ do-    doc <- pp-    tag <- Opaleye.fresh-    let-      relation = Opaleye.tagWith tag "statement"-      symbol labels = do-        subtag <- Opaleye.fresh-        let-          suffix = Opaleye.tagWith tag (Opaleye.tagWith subtag "")-        pure $ take (63 - length suffix) label ++ suffix-        where-          label = fold (intersperse "/" labels)-      names = namesFromLabelsWithA symbol `evalState` Opaleye.start-      columns = Just $ showNames names-      query =-        fromCols <$> each-          TableSchema-            { name = fromString relation-            , columns = names-            }-      returning = Returning (countRows query)-      binding = Binding {..}-    pure (binding, query)-  tell (Endo (binding :))-  pure $ Unmodified query---ppDecodeStatement :: ()-  => (forall x. Table Expr x => Query x -> State Opaleye.Tag Doc)-  -> Rows exprs a -> Statement exprs -> (Doc, Hasql.Result a)-ppDecodeStatement ppSelect rows (Statement m) = evalState go Opaleye.start-  where-    go = do-      (result, Endo dlist) <- runWriterT m-      let-        bindings' = dlist []-      case unsnoc bindings' of-        Nothing -> case rows of-          Void -> do-            doc <- ppSelect (pure false)-            pure (doc, Hasql.noResult)-          RowsAffected -> do-            doc <- ppSelect (pure false)-            pure (doc, 0 <$ Hasql.noResult)-          Single @exprs @a -> do-            doc <- ppSelect (getResult result)-            pure (doc, Hasql.singleRow (parse @exprs @a))-          Maybe @exprs @a -> do-            doc <- ppSelect (getResult result)-            pure (doc, Hasql.rowMaybe (parse @exprs @a))-          List @exprs @a -> do-            doc <- ppSelect (getResult result)-            pure (doc, Hasql.rowList (parse @exprs @a))-          Vector @exprs @a -> do-            doc <- ppSelect (getResult result)-            pure (doc, Hasql.rowVector (parse @exprs @a))-        Just (bindings, binding@Binding {doc = after}) -> case rows of-          Void -> pure (doc, Hasql.noResult)-            where-              doc = ppWith bindings after-          RowsAffected -> do-            case result of-              Unmodified _ -> pure (doc, Hasql.rowsAffected)-                where-                  doc = ppWith bindings after-              Modified _ -> case returning binding of-                NoReturning -> pure (doc, Hasql.rowsAffected)-                  where-                    doc = ppWith bindings after -                Returning query -> do-                  doc <- ppWith bindings' <$> ppSelect query-                  pure (doc, Hasql.singleRow parse)-          Single @exprs @a -> do-            case result of-              Unmodified _ -> pure (doc, Hasql.singleRow (parse @exprs @a))-                where-                  doc = ppWith bindings after-              Modified query -> do-                doc <- ppWith bindings' <$> ppSelect query-                pure (doc, Hasql.singleRow (parse @exprs @a))-          Maybe @exprs @a -> do-            case result of-              Unmodified _ -> pure (doc, Hasql.rowMaybe (parse @exprs @a))-                where-                  doc = ppWith bindings after-              Modified query -> do-                doc <- ppWith bindings' <$> ppSelect query-                pure (doc, Hasql.rowMaybe (parse @exprs @a))-          List @exprs @a -> do-            case result of-              Unmodified _ -> pure (doc, Hasql.rowList (parse @exprs @a))-                where-                  doc = ppWith bindings after-              Modified query -> do-                doc <- ppWith bindings' <$> ppSelect query-                pure (doc, Hasql.rowList (parse @exprs @a))-          Vector @exprs @a -> do-            case result of-              Unmodified _ -> pure (doc, Hasql.rowVector (parse @exprs @a))-                where-                  doc = ppWith bindings after-              Modified query -> do-                doc <- ppWith bindings' <$> ppSelect query-                pure (doc, Hasql.rowVector (parse @exprs @a))---ppWith :: [Binding] -> Doc -> Doc-ppWith bindings after = pre $$ after-  where-    pre = case bindings of-      [] -> mempty-      _ ->-        text "WITH" <+>-        vcat (punctuate comma (map go bindings))-    go binding@Binding {doc = before} =-      ppAlias binding $$-      text "AS" <+>-      parens before---ppAlias :: Binding -> Doc-ppAlias Binding {relation, columns = mcolumns} = case mcolumns of-  Nothing -> escape relation-  Just columns -> -    escape relation <+>-    parens (hcat (punctuate comma (escape <$> toList columns)))---unsnoc :: [a] -> Maybe ([a], a)-unsnoc = foldr (\x -> Just . maybe ([], x) (\(~(a, b)) -> (x : a, b))) Nothing
− src/Rel8/Statement/Delete.hs
@@ -1,74 +0,0 @@-{-# language DuplicateRecordFields #-}-{-# language FlexibleContexts #-}-{-# language GADTs #-}-{-# language NamedFieldPuns #-}-{-# language RecordWildCards #-}-{-# language StandaloneKindSignatures #-}-{-# language StrictData #-}--module Rel8.Statement.Delete-  ( Delete(..)-  , delete-  , ppDelete-  )-where---- base-import Data.Kind ( Type )-import Prelude---- opaleye-import qualified Opaleye.Internal.Tag as Opaleye---- pretty-import Text.PrettyPrint ( Doc, (<+>), ($$), text )---- rel8-import Rel8.Expr ( Expr )-import Rel8.Query ( Query )-import Rel8.Schema.Name ( Selects )-import Rel8.Schema.Table ( TableSchema, ppTable )-import Rel8.Statement (Statement)-import Rel8.Statement.Returning (Returning, ppReturning, runReturning)-import Rel8.Statement.Using ( ppUsing )-import Rel8.Statement.Where ( ppWhere )---- transformers-import Control.Monad.Trans.State.Strict (State)----- | The constituent parts of a @DELETE@ statement.-type Delete :: Type -> Type-data Delete a where-  Delete :: Selects names exprs =>-    { from :: TableSchema names-      -- ^ Which table to delete from.-    , using :: Query using-      -- ^ @USING@ clause — this can be used to join against other tables,-      -- and its results can be referenced in the @WHERE@ clause-    , deleteWhere :: using -> exprs -> Expr Bool-      -- ^ Which rows should be selected for deletion.-    , returning :: Returning names a-      -- ^ What to return from the @DELETE@ statement.-    }-    -> Delete a----- | Build a @DELETE@ 'Statement'.-delete :: Delete a -> Statement a-delete statement@Delete {returning} =-  runReturning (ppDelete statement) returning---ppDelete :: Delete a -> State Opaleye.Tag Doc-ppDelete Delete {..} = do-  musing <- ppUsing using-  pure $ case musing of-    Nothing ->-      text "DELETE FROM" <+> ppTable from $$-      text "WHERE false"-    Just (usingDoc, i) ->-      text "DELETE FROM" <+> ppTable from $$-      usingDoc $$-      ppWhere from (deleteWhere i) $$-      ppReturning from returning
− src/Rel8/Statement/Insert.hs
@@ -1,82 +0,0 @@-{-# language DuplicateRecordFields #-}-{-# language FlexibleContexts #-}-{-# language GADTs #-}-{-# language NamedFieldPuns #-}-{-# language RecordWildCards #-}-{-# language StandaloneKindSignatures #-}-{-# language StrictData #-}--module Rel8.Statement.Insert-  ( Insert(..)-  , insert-  , ppInsert-  , ppInto-  )-where---- base-import Data.Foldable ( toList )-import Data.Kind ( Type )-import Prelude---- opaleye-import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye-import qualified Opaleye.Internal.Tag as Opaleye---- pretty-import Text.PrettyPrint ( Doc, (<+>), ($$), parens, text )---- rel8-import Rel8.Query ( Query )-import Rel8.Schema.Name ( Name, Selects, ppColumn )-import Rel8.Schema.Table ( TableSchema(..), ppTable )-import Rel8.Statement (Statement)-import Rel8.Statement.OnConflict ( OnConflict, ppOnConflict )-import Rel8.Statement.Returning (Returning, ppReturning, runReturning)-import Rel8.Statement.Select ( ppRows )-import Rel8.Table ( Table )-import Rel8.Table.Name ( showNames )---- transformers-import Control.Monad.Trans.State.Strict (State)----- | The constituent parts of a SQL @INSERT@ statement.-type Insert :: Type -> Type-data Insert a where-  Insert :: Selects names exprs =>-    { into :: TableSchema names-      -- ^ Which table to insert into.-    , rows :: Query exprs-      -- ^ The rows to insert. This can be an arbitrary query — use-      -- 'Rel8.values' insert a static list of rows.-    , onConflict :: OnConflict names-      -- ^ What to do if the inserted rows conflict with data already in the-      -- table.-    , returning :: Returning names a-      -- ^ What information to return on completion.-    }-    -> Insert a----- | Build an @INSERT@ 'Statement'.-insert :: Insert a -> Statement a-insert statement@Insert {returning} =-  runReturning (ppInsert statement) returning---ppInsert :: Insert a -> State Opaleye.Tag Doc-ppInsert Insert {..} = do-  rows' <- ppRows rows-  pure $-    text "INSERT INTO" <+>-    ppInto into $$-    rows' $$-    ppOnConflict into onConflict $$-    ppReturning into returning---ppInto :: Table Name a => TableSchema a -> Doc-ppInto table@TableSchema {columns} =-  ppTable table <+>-  parens (Opaleye.commaV ppColumn (toList (showNames columns)))
− src/Rel8/Statement/OnConflict.hs
@@ -1,122 +0,0 @@-{-# language DuplicateRecordFields #-}-{-# language FlexibleContexts #-}-{-# language GADTs #-}-{-# language LambdaCase #-}-{-# language NamedFieldPuns #-}-{-# language OverloadedStrings #-}-{-# language RecordWildCards #-}-{-# language StandaloneKindSignatures #-}-{-# language StrictData #-}-{-# language TypeOperators #-}--module Rel8.Statement.OnConflict-  ( OnConflict(..)-  , Upsert(..)-  , ppOnConflict-  )-where---- base-import Data.Foldable ( toList )-import Data.Kind ( Type )-import Prelude---- opaleye-import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye-import qualified Opaleye.Internal.Sql as Opaleye---- pretty-import Text.PrettyPrint ( Doc, (<+>), ($$), parens, text )---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Opaleye (toPrimExpr)-import Rel8.Schema.Name ( Name, Selects, ppColumn )-import Rel8.Schema.Table ( TableSchema(..) )-import Rel8.Statement.Set ( ppSet )-import Rel8.Statement.Where ( ppWhere )-import Rel8.Table ( Table, toColumns )-import Rel8.Table.Cols ( Cols( Cols ) )-import Rel8.Table.Name ( showNames )-import Rel8.Table.Opaleye (attributes, view)-import Rel8.Table.Projection ( Projecting, Projection, apply )----- | 'OnConflict' represents the @ON CONFLICT@ clause of an @INSERT@--- statement. This specifies what ought to happen when one or more of the--- rows proposed for insertion conflict with an existing row in the table.-type OnConflict :: Type -> Type-data OnConflict names-  = Abort-    -- ^ Abort the transaction if there are conflicting rows (Postgres' default)-  | DoNothing-    -- ^ @ON CONFLICT DO NOTHING@-  | DoUpdate (Upsert names)-    -- ^ @ON CONFLICT DO UPDATE@----- | The @ON CONFLICT (...) DO UPDATE@ clause of an @INSERT@ statement, also--- known as \"upsert\".------ When an existing row conflicts with a row proposed for insertion,--- @ON CONFLICT DO UPDATE@ allows you to instead update this existing row. The--- conflicting row proposed for insertion is then \"excluded\", but its values--- can still be referenced from the @SET@ and @WHERE@ clauses of the @UPDATE@--- statement.------ Upsert in Postgres a \"conflict target\" to be specified — this is the--- @UNIQUE@ index from conflicts with which we would like to recover. Indexes--- are specified by listing the columns that comprise them along with an--- optional predicate in the case of partial indexes.-type Upsert :: Type -> Type-data Upsert names where-  Upsert :: (Selects names exprs, Projecting names index, excluded ~ exprs) =>-    { index :: Projection names index-      -- ^ The set of columns comprising the @UNIQUE@ index that forms our-      -- conflict target, projected from the set of columns for the whole-      -- table-    , predicate :: Maybe (exprs -> Expr Bool)-      -- ^ An optional predicate used to specify a-      -- [partial index](https://www.postgresql.org/docs/current/indexes-partial.html).-    , set :: excluded -> exprs -> exprs-      -- ^ How to update each selected row.-    , updateWhere :: excluded -> exprs -> Expr Bool-      -- ^ Which rows to select for update.-    }-    -> Upsert names---ppOnConflict :: TableSchema names -> OnConflict names -> Doc-ppOnConflict schema = \case-  Abort -> mempty-  DoNothing -> text "ON CONFLICT DO NOTHING"-  DoUpdate upsert -> ppUpsert schema upsert---ppUpsert :: TableSchema names -> Upsert names -> Doc-ppUpsert schema@TableSchema {columns} Upsert {..} =-  text "ON CONFLICT" <+>-  ppIndex columns index <+> foldMap (ppPredicate columns) predicate <+>-  text "DO UPDATE" $$-  ppSet schema (set excluded) $$-  ppWhere schema (updateWhere excluded)-  where-    excluded = attributes TableSchema-      { name = "excluded"-      , columns-      }---ppIndex :: (Table Name names, Projecting names index)-  => names -> Projection names index -> Doc-ppIndex columns index =-  parens $ Opaleye.commaV ppColumn $ toList $-    showNames $ Cols $ apply index $ toColumns columns---ppPredicate :: Selects names exprs-  => names -> (exprs -> Expr Bool) -> Doc-ppPredicate schema where_ = text "WHERE" <+> ppExpr condition-  where-    ppExpr = Opaleye.ppSqlExpr . Opaleye.sqlExpr . toPrimExpr-    condition = where_ (view schema)
− src/Rel8/Statement/Prepared.hs
@@ -1,87 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language BlockArguments #-}-{-# language FlexibleContexts #-}-{-# language MonoLocalBinds #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language TypeApplications #-}--module Rel8.Statement.Prepared (-  input,-  prepared,-) where---- base-import Data.Functor.Const (Const (Const), getConst)-import Data.Functor.Contravariant (contramap, (>$<))-import Data.Functor.Identity (runIdentity)-import Prelude---- hasql-import qualified Hasql.Encoders as Hasql-import qualified Hasql.Statement as Hasql---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Expr (Expr)-import Rel8.Expr.Opaleye (fromPrimExpr, scastExpr)-import Rel8.Schema.HTable (hfield, hspecs, htabulateA)-import Rel8.Schema.Null (Nullity (Null, NotNull))-import Rel8.Schema.Spec (Spec (..))-import Rel8.Statement (Statement)-import Rel8.Table (Table, fromColumns, toResult)-import Rel8.Table.Serialize (Serializable)-import Rel8.Type.Encoder (binary)-import Rel8.Type.Information (encode)---- transformers-import Control.Monad.Trans.State.Strict (evalState, state)---{-| Given a 'Rel8.run' function that converts a 'Statement' to a-'Hasql.Statement', return a 'Rel8.run'-like function which instead takes a-/parameterized/ 'Statement' and converts it to a /preparable/-'Hasql.Statement'.--The parameters @i@ are sent to the database directly via PostgreSQL's binary-format. For large amounts of data this can be significantly more efficient-than embedding the values in the statement with 'Rel8.lit'.--}-prepared :: forall a b i o.-  Serializable a i =>-  (Statement b -> Hasql.Statement () o) ->-  (a -> Statement b) ->-  Hasql.Statement i o-prepared run mkStatement = Hasql.Statement sql (encoder @a) decode True-  where-    Hasql.Statement sql _ decode _ = run $ mkStatement input---encoder :: forall a i. Serializable a i => Hasql.Params i-encoder =-  contramap (toResult @_ @a) $-    getConst $-      htabulateA \field ->-        case hfield hspecs field of-          Spec {nullity, info} -> Const $-            runIdentity . (`hfield` field) >$<-              case nullity of-                Null -> Hasql.param $ Hasql.nullable build-                NotNull -> Hasql.param $ Hasql.nonNullable build-              where-                build = binary (encode info)---input :: Table Expr a => a-input =-  fromColumns $-    flip (evalState @Word) 1 do-      htabulateA \field -> do-        n <- state (\n -> (n, n + 1))-        pure-          case hfield hspecs field of-            Spec {info} ->-              scastExpr info $ fromPrimExpr $-                Opaleye.ConstExpr $ Opaleye.OtherLit $ '$' : show n
− src/Rel8/Statement/Returning.hs
@@ -1,83 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language GADTs #-}-{-# language LambdaCase #-}-{-# language NamedFieldPuns #-}-{-# language RankNTypes #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language StrictData #-}-{-# language TypeApplications #-}--module Rel8.Statement.Returning-  ( Returning( NoReturning, Returning )-  , runReturning-  , ppReturning-  )-where---- base-import Data.Foldable ( toList )-import Data.Kind ( Type )-import Data.List.NonEmpty ( NonEmpty )-import Prelude---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye-import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye-import qualified Opaleye.Internal.Sql as Opaleye-import qualified Opaleye.Internal.Tag as Opaleye---- pretty-import Text.PrettyPrint ( Doc, (<+>), text )---- rel8-import Rel8.Expr (Expr)-import Rel8.Query (Query)-import Rel8.Schema.Name ( Selects )-import Rel8.Schema.Table ( TableSchema(..) )-import Rel8.Statement (Statement, statementNoReturning, statementReturning)-import Rel8.Table (Table)-import Rel8.Table.Opaleye ( castTable, exprs, view )---- transformers-import Control.Monad.Trans.State.Strict (State)----- | 'Rel8.Insert', 'Rel8.Update' and 'Rel8.Delete' all support an optional--- @RETURNING@ clause.-type Returning :: Type -> Type -> Type-data Returning names a where-  -- | No @RETURNING@ clause-  NoReturning :: Returning names ()--  -- | 'Returning' allows you to project out of the affected rows, which can-  -- be useful if you want to log exactly which rows were deleted, or to view-  -- a generated id (for example, if using a column with an autoincrementing-  -- counter via 'Rel8.nextval').-  Returning :: (Selects names exprs, Table Expr a) => (exprs -> a) -> Returning names (Query a)---projections :: ()-  => TableSchema names -> Returning names a -> Maybe (NonEmpty Opaleye.PrimExpr)-projections TableSchema {columns} = \case-  NoReturning -> Nothing-  Returning f -> Just (exprs (castTable (f (view columns))))---runReturning ::-  State Opaleye.Tag Doc ->-  Returning names a ->-  Statement a-runReturning pp = \case-  NoReturning -> statementNoReturning pp-  Returning _ -> statementReturning pp---ppReturning :: TableSchema names -> Returning names a -> Doc-ppReturning schema returning = case projections schema returning of-  Nothing -> mempty-  Just columns ->-    text "RETURNING" <+> Opaleye.commaV Opaleye.ppSqlExpr (toList sqlExprs)-    where-      sqlExprs = Opaleye.sqlExpr <$> columns
− src/Rel8/Statement/Rows.hs
@@ -1,30 +0,0 @@-{-# language DataKinds #-}-{-# language GADTs #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Statement.Rows-  ( Rows (..)    -  )-where---- base-import Data.Int (Int64)-import Data.Kind (Type)-import Prelude---- rel8-import Rel8.Query (Query)-import Rel8.Table.Serialize (Serializable)---- vector-import Data.Vector (Vector)---type Rows :: Type -> Type -> Type-data Rows returning result where-  Void :: Rows returning ()-  RowsAffected :: Rows () Int64-  Single :: Serializable exprs a => Rows (Query exprs) a-  Maybe :: Serializable exprs a => Rows (Query exprs) (Maybe a)-  List :: Serializable exprs a => Rows (Query exprs) [a]-  Vector :: Serializable exprs a => Rows (Query exprs) (Vector a)
− src/Rel8/Statement/Run.hs
@@ -1,107 +0,0 @@-module Rel8.Statement.Run-  ( run_-  , runN-  , run1-  , runMaybe-  , run-  , runVector-  )-where---- base-import Data.Int (Int64)-import Prelude---- hasql-import qualified Hasql.Encoders as Hasql-import qualified Hasql.Statement as Hasql---- rel8-import Rel8.Query (Query)-import Rel8.Statement (Statement, ppDecodeStatement)-import Rel8.Statement.Rows (Rows (..))-import Rel8.Statement.Select (ppSelect)-import Rel8.Table.Serialize (Serializable)---- text-import qualified Data.Text as Text-import Data.Text.Encoding (encodeUtf8)---- vector-import Data.Vector (Vector)---makeRun :: Rows exprs a -> Statement exprs -> Hasql.Statement () a-makeRun rows statement = Hasql.Statement bytes params decode prepare-  where-    bytes = encodeUtf8 $ Text.pack sql-    params = Hasql.noParams-    prepare = False-    sql = show doc-    (doc, decode) = ppDecodeStatement ppSelect rows statement----- | Convert a 'Statement' to a runnable 'Hasql.Statement', disregarding the--- results of that statement (if any).------ @--- run_ :: Rel8.'Statement' exprs -> Hasql.'Hasql.Statement' () ()--- @-run_ :: Statement exprs -> Hasql.Statement () ()-run_ = makeRun Void----- | Convert a 'Statement' to a runnable 'Hasql.Statement', returning the--- number of rows affected by that statement (for 'Rel8.insert's,--- 'Rel8.update's or Rel8.delete's with 'Rel8.NoReturning').------ @--- runN :: Rel8.'Statement' () -> Hasql.'Hasql.Statement' () 'Int64'--- @-runN :: Statement () -> Hasql.Statement () Int64-runN = makeRun RowsAffected----- | Convert a 'Statement' to a runnable 'Hasql.Statement', processing the--- result of the statement as a single row. If the statement returns a number--- of rows other than 1, a runtime exception is thrown.------ @--- run1 :: 'Serializable' exprs a => Rel8.'Statement' ('Query' exprs) -> Hasql.'Hasql.Statement' () a--- @-run1 :: Serializable exprs a => Statement (Query exprs) -> Hasql.Statement () a-run1 = makeRun Single----- | Convert a 'Statement' to a runnable 'Hasql.Statement', processing the--- result of the statement as 'Maybe' a single row. If the statement returns--- a number of rows other than 0 or 1, a runtime exception is thrown.------ @--- runMaybe :: 'Serializable' exprs a => Rel8.'Statement' ('Query' exprs) -> Hasql.'Hasql.Statement' () ('Maybe' a)--- @-runMaybe :: Serializable exprs a-  => Statement (Query exprs) -> Hasql.Statement () (Maybe a)-runMaybe = makeRun Maybe----- | Convert a 'Statement' to a runnable 'Hasql.Statement', processing the--- result of the statement as a list of rows.------ @--- run :: 'Serializable' exprs a => Rel8.'Statement' ('Query' exprs) -> Hasql.'Hasql.Statement' () [a]--- @-run :: Serializable exprs a-  => Statement (Query exprs) -> Hasql.Statement () [a]-run = makeRun List----- | Convert a 'Statement' to a runnable 'Hasql.Statement', processing the--- result of the statement as a 'Vector' of rows.------ @--- runVector :: 'Serializable' exprs a => Rel8.'Statement' ('Query' exprs) -> Hasql.'Hasql.Statement' () ('Vector' a)--- @-runVector :: Serializable exprs a-  => Statement (Query exprs) -> Hasql.Statement () (Vector a)-runVector = makeRun Vector
− src/Rel8/Statement/SQL.hs
@@ -1,56 +0,0 @@-{-# language FlexibleContexts #-}--module Rel8.Statement.SQL-  ( showDelete-  , showInsert-  , showUpdate-  , showStatement-  , showPreparedStatement-  )-where---- base-import Prelude---- opaleye-import qualified Opaleye.Internal.Tag as Opaleye---- rel8-import Rel8.Expr (Expr)-import Rel8.Statement (Statement, ppDecodeStatement)-import Rel8.Statement.Delete ( Delete, ppDelete )-import Rel8.Statement.Insert ( Insert, ppInsert )-import Rel8.Statement.Prepared (input)-import Rel8.Statement.Rows (Rows (Void))-import Rel8.Statement.Select (ppSelect)-import Rel8.Statement.Update ( Update, ppUpdate )-import Rel8.Table (Table)---- transformers-import Control.Monad.Trans.State.Strict (evalState)----- | Convert a 'Delete' to a 'String' containing a @DELETE@ statement.-showDelete :: Delete a -> String-showDelete = show . (`evalState` Opaleye.start) . ppDelete----- | Convert an 'Insert' to a 'String' containing an @INSERT@ statement.-showInsert :: Insert a -> String-showInsert = show . (`evalState` Opaleye.start) . ppInsert----- | Convert an 'Update' to a 'String' containing an @UPDATE@ statement.-showUpdate :: Update a -> String-showUpdate = show . (`evalState` Opaleye.start) . ppUpdate----- | Convert a 'Statement' to a 'String' containing an SQL statement.-showStatement :: Statement a -> String-showStatement = show . fst . ppDecodeStatement ppSelect Void----- | Convert a parameterized 'Statement' to a 'String' containing an SQL--- statement.-showPreparedStatement :: Table Expr i => (i -> Statement a) -> String-showPreparedStatement = showStatement . ($ input)
− src/Rel8/Statement/Select.hs
@@ -1,132 +0,0 @@-{-# language DataKinds #-}-{-# language DeriveTraversable #-}-{-# language DerivingStrategies #-}-{-# language FlexibleContexts #-}-{-# language MonoLocalBinds #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}--module Rel8.Statement.Select-  ( select-  , ppSelect-  , Optimized(..)-  , ppPrimSelect-  , ppRows-  )-where---- base-import Data.Foldable ( toList )-import Data.Kind ( Type )-import Data.Void ( Void )-import Prelude hiding ( undefined )---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye-import qualified Opaleye.Internal.HaskellDB.Sql as Opaleye-import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye-import qualified Opaleye.Internal.PrimQuery as Opaleye-import qualified Opaleye.Internal.Print as Opaleye-import qualified Opaleye.Internal.Optimize as Opaleye-import qualified Opaleye.Internal.QueryArr as Opaleye hiding ( Select )-import qualified Opaleye.Internal.Sql as Opaleye hiding ( Values )-import qualified Opaleye.Internal.Tag as Opaleye---- pretty-import Text.PrettyPrint ( Doc )---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Bool ( false )-import Rel8.Expr.Opaleye ( toPrimExpr )-import Rel8.Query ( Query )-import Rel8.Query.Opaleye ( toOpaleye )-import Rel8.Schema.Name ( Selects )-import Rel8.Statement (Statement, statementReturning)-import Rel8.Table ( Table )-import Rel8.Table.Cols ( toCols )-import Rel8.Table.Name ( namesFromLabels )-import Rel8.Table.Opaleye ( castTable, exprsWithNames )-import qualified Rel8.Table.Opaleye as T-import Rel8.Table.Undefined ( undefined )---- transformers-import Control.Monad.Trans.State.Strict (State)----- | Build a @SELECT@ 'Statement'.-select :: Table Expr a => Query a -> Statement (Query a)-select query = statementReturning (ppSelect query)---ppSelect :: Table Expr a => Query a -> State Opaleye.Tag Doc-ppSelect query = do-  (exprs, primQuery) <- Opaleye.runSimpleSelect (toOpaleye query)-  let-    (exprs', primQuery') = case optimize primQuery of-      Empty -> (undefined, Opaleye.Product (pure (pure Opaleye.Unit)) never)-      Unit -> (exprs, Opaleye.Unit)-      Optimized pq -> (exprs, pq)-  pure $ Opaleye.ppSql $ primSelectWith names (toCols exprs') primQuery'-  where-    names = namesFromLabels-    never = pure (toPrimExpr false)---ppRows :: Table Expr a => Query a -> State Opaleye.Tag Doc-ppRows query = case optimize primQuery of-  -- Special case VALUES because we can't use DEFAULT inside a SELECT-  Optimized (Opaleye.Values symbols rows)-    | eqSymbols symbols (toList (T.exprs a)) ->-        pure $ Opaleye.ppValues_ (map Opaleye.sqlExpr <$> toList rows)-  _ -> ppSelect query-  where-    (a, primQuery, _) = Opaleye.runSimpleQueryArrStart (toOpaleye query) ()--    eqSymbols (symbol : symbols) (Opaleye.AttrExpr symbol' : exprs)-      | eqSymbol symbol symbol' = eqSymbols symbols exprs-      | otherwise = False-    eqSymbols [] [] = True-    eqSymbols _ _ = False--    eqSymbol-      (Opaleye.Symbol name (Opaleye.UnsafeTag tag))-      (Opaleye.Symbol name' (Opaleye.UnsafeTag tag'))-      = name == name' && tag == tag'---ppPrimSelect :: Query a -> State Opaleye.Tag (Optimized Doc, a)-ppPrimSelect query = do-  (a, primQuery) <- Opaleye.runSimpleSelect (toOpaleye query)-  pure $ (Opaleye.ppSql . primSelect <$> optimize primQuery, a)---type Optimized :: Type -> Type-data Optimized a = Empty | Unit | Optimized a-  deriving stock (Functor, Foldable, Traversable, Show)---optimize :: Opaleye.PrimQuery' a -> Optimized (Opaleye.PrimQuery' Void)-optimize query = case Opaleye.removeEmpty (Opaleye.optimize query) of-  Nothing -> Empty-  Just Opaleye.Unit -> Unit-  Just query' -> Optimized query'---primSelect :: Opaleye.PrimQuery' Void -> Opaleye.Select-primSelect = Opaleye.foldPrimQuery Opaleye.sqlQueryGenerator---primSelectWith :: Selects names exprs-  => names -> exprs -> Opaleye.PrimQuery' Void -> Opaleye.Select-primSelectWith names exprs query =-  Opaleye.SelectFrom $ Opaleye.newSelect-    { Opaleye.attrs = Opaleye.SelectAttrs attrs-    , Opaleye.tables = Opaleye.oneTable (primSelect query)-    }-  where-    attrs = makeAttr <$> exprsWithNames names (castTable exprs)-      where-        makeAttr (label, expr) =-          (Opaleye.sqlExpr expr, Just (Opaleye.SqlColumn label))
− src/Rel8/Statement/Set.hs
@@ -1,33 +0,0 @@-{-# language MonoLocalBinds #-}-{-# language NamedFieldPuns #-}--module Rel8.Statement.Set-  ( ppSet-  )-where---- base-import Data.Foldable ( toList )-import Prelude ()---- opaleye-import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye-import qualified Opaleye.Internal.Sql as Opaleye---- pretty-import Text.PrettyPrint ( Doc, (<+>), equals, text )---- rel8-import Rel8.Schema.Name ( Selects, ppColumn )-import Rel8.Schema.Table ( TableSchema(..) )-import Rel8.Table.Opaleye ( attributes, exprsWithNames )---ppSet :: Selects names exprs-  => TableSchema names -> (exprs -> exprs) -> Doc-ppSet schema@TableSchema {columns} f =-  text "SET" <+> Opaleye.commaV ppAssign (toList assigns)-  where-    assigns = exprsWithNames columns (f (attributes schema))-    ppAssign (column, expr) =-      ppColumn column <+> equals <+> Opaleye.ppSqlExpr (Opaleye.sqlExpr expr)
− src/Rel8/Statement/Update.hs
@@ -1,79 +0,0 @@-{-# language DuplicateRecordFields #-}-{-# language FlexibleContexts #-}-{-# language GADTs #-}-{-# language NamedFieldPuns #-}-{-# language RecordWildCards #-}-{-# language StandaloneKindSignatures #-}-{-# language StrictData #-}--module Rel8.Statement.Update-  ( Update(..)-  , update-  , ppUpdate-  )-where---- base-import Data.Kind ( Type )-import Prelude---- opaleye-import qualified Opaleye.Internal.Tag as Opaleye---- pretty-import Text.PrettyPrint ( Doc, (<+>), ($$), text )---- rel8-import Rel8.Expr ( Expr )-import Rel8.Query ( Query )-import Rel8.Schema.Name ( Selects )-import Rel8.Schema.Table ( TableSchema(..), ppTable )-import Rel8.Statement (Statement)-import Rel8.Statement.Returning (Returning, ppReturning, runReturning)-import Rel8.Statement.Set ( ppSet )-import Rel8.Statement.Using ( ppFrom )-import Rel8.Statement.Where ( ppWhere )---- transformers-import Control.Monad.Trans.State.Strict (State)----- | The constituent parts of an @UPDATE@ statement.-type Update :: Type -> Type-data Update a where-  Update :: Selects names exprs =>-    { target :: TableSchema names-      -- ^ Which table to update.-    , from :: Query from-      -- ^ @FROM@ clause — this can be used to join against other tables,-      -- and its results can be referenced in the @SET@ and @WHERE@ clauses.-    , set :: from -> exprs -> exprs-      -- ^ How to update each selected row.-    , updateWhere :: from -> exprs -> Expr Bool-      -- ^ Which rows to select for update.-    , returning :: Returning names a-      -- ^ What to return from the @UPDATE@ statement.-    }-    -> Update a----- | Build an @UPDATE@ 'Statement'.-update :: Update a -> Statement a-update statement@Update {returning} =-  runReturning (ppUpdate statement) returning---ppUpdate :: Update a -> State Opaleye.Tag Doc-ppUpdate Update {..} = do-  mfrom <- ppFrom from-  pure $ case mfrom of-    Nothing -> -      text "UPDATE" <+> ppTable target $$-      ppSet target id $$-      text "WHERE false"-    Just (fromDoc, i) ->-      text "UPDATE" <+> ppTable target $$-      ppSet target (set i) $$-      fromDoc $$-      ppWhere target (updateWhere i) $$-      ppReturning target returning
− src/Rel8/Statement/Using.hs
@@ -1,45 +0,0 @@-{-# language OverloadedStrings #-}--module Rel8.Statement.Using-  ( ppFrom-  , ppUsing-  )-where---- base-import Prelude---- opaleye-import qualified Opaleye.Internal.Tag as Opaleye---- pretty-import Text.PrettyPrint ( Doc, (<+>), parens, text )---- rel8-import Rel8.Query ( Query )-import Rel8.Schema.Table ( TableSchema(..), ppTable )-import Rel8.Statement.Select ( Optimized(..), ppPrimSelect )---- transformers-import Control.Monad.Trans.State.Strict (State)---ppFrom :: Query a -> State Opaleye.Tag (Maybe (Doc, a))-ppFrom = ppJoin "FROM"---ppUsing :: Query a -> State Opaleye.Tag (Maybe (Doc, a))-ppUsing = ppJoin "USING"---ppJoin :: String -> Query a -> State Opaleye.Tag (Maybe (Doc, a))-ppJoin clause join = do-  (ofrom, a) <- ppPrimSelect join-  pure $ do-    doc <- case ofrom of-      Empty -> Nothing-      Unit -> Just mempty-      Optimized doc -> Just $ text clause <+> parens doc <+> ppTable alias-    pure (doc, a)-  where-    alias = TableSchema {name = "T1", columns = ()}
− src/Rel8/Statement/View.hs
@@ -1,84 +0,0 @@-{-# language FlexibleContexts #-}-{-# language MonoLocalBinds #-}--module Rel8.Statement.View-  ( createView-  , createOrReplaceView-  )-where---- base-import Prelude---- hasql-import qualified Hasql.Decoders as Hasql-import qualified Hasql.Encoders as Hasql-import qualified Hasql.Statement as Hasql---- opaleye-import qualified Opaleye.Internal.Tag as Opaleye---- pretty-import Text.PrettyPrint ( Doc, (<+>), ($$), text )---- rel8-import Rel8.Query ( Query )-import Rel8.Schema.Name ( Selects )-import Rel8.Schema.Table ( TableSchema )-import Rel8.Statement.Insert ( ppInto )-import Rel8.Statement.Select ( ppSelect )---- text-import qualified Data.Text as Text-import Data.Text.Encoding ( encodeUtf8 )---- transformers-import Control.Monad.Trans.State.Strict (evalState)---data CreateView = Create | CreateOrReplace----- | Given a 'TableSchema' and 'Query', @createView@ runs a @CREATE VIEW@--- statement that will save the given query as a view. This can be useful if--- you want to share Rel8 queries with other applications.-createView :: Selects names exprs-  => TableSchema names -> Query exprs -> Hasql.Statement () ()-createView =-  createViewGeneric Create----- | Given a 'TableSchema' and 'Query', @createOrReplaceView@ runs a--- @CREATE OR REPLACE VIEW@ statement that will save the given query--- as a view, replacing the current view definition if it exists and--- adheres to the restrictions in place for replacing a view in--- PostgreSQL.-createOrReplaceView :: Selects names exprs-  => TableSchema names -> Query exprs -> Hasql.Statement () ()-createOrReplaceView =-  createViewGeneric CreateOrReplace---createViewGeneric :: Selects names exprs-  => CreateView -> TableSchema names -> Query exprs -> Hasql.Statement () ()-createViewGeneric replace schema query =-  Hasql.Statement bytes params decode prepare-  where-    bytes = encodeUtf8 (Text.pack sql)-    params = Hasql.noParams-    decode = Hasql.noResult-    prepare = False-    sql = show doc-    doc = ppCreateView schema query replace---ppCreateView :: Selects names exprs-  => TableSchema names -> Query exprs -> CreateView -> Doc-ppCreateView schema query replace =-  createOrReplace replace <+>-  ppInto schema $$-  text "AS" <+>-  evalState (ppSelect query) Opaleye.start-  where-    createOrReplace Create = text "CREATE VIEW"-    createOrReplace CreateOrReplace = text "CREATE OR REPLACE VIEW"
− src/Rel8/Statement/Where.hs
@@ -1,31 +0,0 @@-{-# language MonoLocalBinds #-}--module Rel8.Statement.Where-  ( ppWhere-  )-where---- base-import Prelude---- opaleye-import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye-import qualified Opaleye.Internal.Sql as Opaleye---- pretty-import Text.PrettyPrint ( Doc, (<+>), text )---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Opaleye ( toPrimExpr )-import Rel8.Schema.Name ( Selects )-import Rel8.Schema.Table ( TableSchema )-import Rel8.Table.Opaleye ( attributes )---ppWhere :: Selects names exprs-  => TableSchema names -> (exprs -> Expr Bool) -> Doc-ppWhere schema where_ = text "WHERE" <+> ppExpr condition-  where-    ppExpr = Opaleye.ppSqlExpr . Opaleye.sqlExpr . toPrimExpr-    condition = where_ (attributes schema)
+ src/Rel8/TH.hs view
@@ -0,0 +1,279 @@+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ViewPatterns #-}++module Rel8.TH+  ( deriveRel8able+  , deriveRel8ables+  ) where++import Control.Monad (zipWithM)+import Data.Foldable (toList)+import Data.Foldable1 (foldr1)+import Data.List (unsnoc)+import Data.List.NonEmpty (NonEmpty ((:|)), nonEmpty)+import qualified Data.Map.Strict as M+import Data.Proxy (Proxy (Proxy))+import Data.Type.Equality (type (==))+import Language.Haskell.TH (Q)+import qualified Language.Haskell.TH as TH+import Language.Haskell.TH.Datatype (ConstructorVariant (RecordConstructor), DatatypeInfo (..), constructorFields, constructorVariant, datatypeCons, reifyDatatype)+import qualified Language.Haskell.TH.Datatype as TH.Datatype+import qualified Language.Haskell.TH.Syntax as TH+import Rel8.Internal.Column (Column)+import Rel8.Internal.Expr (Expr)+import Rel8.Internal.Generic.Rel8able (Rel8able (..), Serialize, deserialize, serialize)+import Rel8.Internal.Kind.Context (SContext (..))+import Rel8.Internal.Schema.HTable.Identity (HIdentity)+import Rel8.Internal.Schema.HTable.Label (HLabel (..))+import Rel8.Internal.Schema.HTable.Product (HProduct (HProduct))+import Rel8.Internal.Schema.Kind (Context)+import Rel8.Internal.Schema.Result (Result)+import Rel8.Internal.Table (Columns, Transpose, fromColumns, toColumns)+import Rel8.Internal.Table.Serialize (ToExprs)+import Prelude hiding (foldr1)++-- | Represent a valid datatype+data ParsedDatatype+    = ParsedDatatype+    { name :: TH.Name+    , conName :: TH.Name+    , fBinder :: TH.Name+    , fields :: NonEmpty ParsedField+    }+    deriving (Show)++-- | Represent a valid field+data ParsedField+    = ParsedField+    { fieldSelector :: Maybe TH.Name+    , fieldType :: TH.Type+    , fieldColumnType :: TH.Type+    , fieldFreshName :: TH.Name+    }+    deriving (Show)++-- | 'fail' but indicate that the failure is coming from our code+prettyFail :: String -> Q a+prettyFail str = fail $ "deriveRel8able: " ++ str++parseDatatype :: DatatypeInfo -> Q ParsedDatatype+parseDatatype datatypeInfo = do+    constructor <-+        -- Check that it only has one constructor+        case datatypeCons datatypeInfo of+            [cons] -> pure cons+            _ -> prettyFail "exepecting a datatype with exactly 1 constructor"+    let conName = TH.Datatype.constructorName constructor+    let name = datatypeName datatypeInfo+    fBinder <- case unsnoc $ datatypeInstTypes datatypeInfo of+        Just (_, candidate) -> parseFBinder candidate+        Nothing -> prettyFail "expecting the datatype to have a context type parameter like `data Foo f = ...`"+    let fieldSelectors = case constructorVariant constructor of+            -- Only record constructors have field names+            RecordConstructor names -> map Just names+            _ -> repeat Nothing+    fieldList <- zipWithM (parseField fBinder) (constructorFields constructor) fieldSelectors+    fields <- maybe (prettyFail "Expected at least one field") pure $ nonEmpty fieldList+    pure ParsedDatatype{..}++parseFBinder :: TH.Type -> Q TH.Name+parseFBinder (TH.SigT x (TH.ConT kind))+    | kind == ''Context = parseFBinder x+    | otherwise = prettyFail $ "expected kind encountered for the context type argument: " ++ show kind+-- type Context = Type -> Type+parseFBinder (TH.SigT x (TH.ArrowT `TH.AppT` TH.StarT `TH.AppT` TH.StarT)) = parseFBinder x+parseFBinder (TH.VarT name) = pure name+parseFBinder typ = prettyFail $ "unexpected type encountered while looking for the context type argument to the datatype: " ++ show typ++parseField :: TH.Name -> TH.Type -> Maybe TH.Name -> Q ParsedField+parseField fBinder fieldType fieldSelector = do+    n <- TH.newName "x"+    let ft = TH.Datatype.applySubstitution (M.fromList [(fBinder, TH.ConT ''Expr)]) $ resolveColumnF fBinder fieldType+    columnType <- case ft of+        -- Without special casing this, we get lots of UndecidableInstance errors+        -- ie, rewrite Expr \phi to HIdentity \phi+        (TH.ConT exprName' `TH.AppT` x) | exprName' == ''Expr -> [t|HIdentity $(pure x)|] --+        _ -> [t|Columns $(pure ft)|]+    pure $ ParsedField{fieldSelector = fieldSelector, fieldType = ft, fieldColumnType = columnType, fieldFreshName = n}++-- | Like foldr1, but we create a mostly balanced binary tree.+-- This makes a big difference for compile times, since we want the depth of the HProduct tree to be minimal.+-- Each layer adds a lot of overhead.+foldr1Tree :: (a -> a -> a ) -> NonEmpty a -> a+foldr1Tree f xs0 = go (toList xs0) size0+  where+    size0 = length xs0+    go [] _ = error "impossible"+    go [x] _ = x+    go [x,y] _ = f x y+    go xs size = f (go left half) (go right (size - half))+      where+        -- Invariants:+        -- half > 0, since size is >2, this will always be the case+        -- size - half > 0+        half = size `div` 2+        (left, right) = splitAt half xs++generateGColumns :: ParsedDatatype -> Q TH.Type+generateGColumns ParsedDatatype{..} =+    foldr1Tree (\x y -> [t|HProduct $x $y|]) $ fmap generateGColumn fields+  where+    generateGColumn ParsedField{..} =+        labelled fieldSelector [t|$(pure fieldColumnType)|]+    labelled Nothing x = x+    labelled (Just (TH.Name (TH.OccName fieldSelector) _)) x = [t|HLabel $(TH.litT $ TH.strTyLit fieldSelector) $x|]++-- | Generate an expression to construct a column value+generateColumnsE :: ParsedDatatype -> (Q TH.Type -> Q TH.Exp -> Q TH.Exp) -> Q TH.Exp+generateColumnsE ParsedDatatype{..} g =+    foldr1Tree (\x y -> TH.conE 'HProduct `TH.appE` x `TH.appE` y) $ fmap generateColumnE fields+  where+    generateColumnE ParsedField{..} =+        labelled fieldSelector $+            g (pure fieldType) $+                TH.varE fieldFreshName+    labelled Nothing x = x+    labelled (Just _) x = TH.conE 'HLabel `TH.appE` x++-- | Generate a pattern to destruct a column+generateColumnsP :: ParsedDatatype -> TH.Pat+generateColumnsP ParsedDatatype{..} =+    foldr1Tree (\x y -> TH.ConP 'HProduct [] [x, y]) $ fmap generateColumnP fields+  where+    generateColumnP ParsedField{..} =+        labelled fieldSelector $+            TH.VarP fieldFreshName+    labelled Nothing x = x+    labelled (Just _) x = TH.ConP 'HLabel [] [x]++-- | Generate an expression to create the constructor+generateConstructorE :: ParsedDatatype -> (Q TH.Type -> Q TH.Exp -> Q TH.Exp) -> Q TH.Exp+generateConstructorE parsedDatatype g =+    foldl' TH.appE (TH.conE (conName parsedDatatype)) . fmap generateFieldE $ fields parsedDatatype+  where+    generateFieldE ParsedField{..} =+        g (pure fieldType) $ TH.varE fieldFreshName++-- | Generate a pattern to destruct the datatype+generateConstructorP :: ParsedDatatype -> Q TH.Pat+generateConstructorP parsedDatatype =+  pure $ TH.ConP (conName parsedDatatype) [] . toList . fmap (TH.VarP . fieldFreshName) $ fields parsedDatatype+++-- These two functions exist solely so we can write the splices without using TypeApplications, which require an extra language extension in client code, and are required here to appease the type checker.+-- Otherwise it gets confused.+deserialize' :: forall transposition expr a. Proxy expr -> (Serialize transposition expr a, transposition ~ (a == Transpose Result expr)) => Columns expr Result -> a+deserialize' _ = deserialize @_ @expr++serialize' :: forall transposition expr a. Proxy expr -> (Serialize transposition expr a, transposition ~ (a == Transpose Result expr)) => a -> Columns expr Result+serialize' _ = serialize @_ @expr++-- | Derive a 'Rel8able' instance using TemplateHaskell.+-- Using TH can be signficantly faster than using Generics.+-- Currently, this doesn't support all of the features of the Generics deriving machinery.+--+-- You might have to enable @UndecidableInstances@ for instances to compile.+--+-- >>> data Foo f  = Foo+-- >>>   { fooId :: Column f Word64+-- >>>   , fooName :: Column f Text+-- >>>   }+-- >>>+-- >>>  deriveRel8able ''Foo+deriveRel8able :: TH.Name -> Q [TH.Dec]+deriveRel8able name = do+    datatypeInfo <- reifyDatatype name+    parsedDatatype <- parseDatatype datatypeInfo+    let gColumns = generateGColumns parsedDatatype+    let constructorE = generateConstructorE parsedDatatype+    let constructorP = generateConstructorP parsedDatatype+    let columnsE = generateColumnsE parsedDatatype+    let columnsP = pure $ generateColumnsP parsedDatatype+    contextName <- TH.newName "context"+    [d|+        -- We already derive ToExprs for Rel8able instances but we assumed they are Generically derived.+        -- So, we need to allow this one to overlap, but this is fine since this instance is always more specific.+        instance {-# OVERLAPPING #-} (x ~ $(TH.conT name) Expr, result ~ Result) => ToExprs x ($(TH.conT name) result)++        instance Rel8able $(TH.conT name) where+            -- Really the Generic code substitutes Expr for f and then does stuff. Maybe we want to move closer to that?+            type+                GColumns $(TH.conT name) =+                    $gColumns++            type+                GFromExprs $(TH.conT name) =+                    $(TH.conT name) Result++            -- the rest of the definition is just a few functions to go back and forth between Columns and the datatype+            gfromColumns $(TH.varP contextName) v =+                case $(TH.varE contextName) of+                    SResult -> case v of $columnsP -> $(constructorE (\ft x -> [|deserialize' (Proxy :: Proxy $ft) $x|]))+                    SExpr -> case v of $columnsP -> $(constructorE (\_ x -> [|fromColumns $x|]))+                    SField -> case v of $columnsP -> $(constructorE (\_ x -> [|fromColumns $x|]))+                    SName -> case v of $columnsP -> $(constructorE (\_ x -> [|fromColumns $x|]))++            gtoColumns $(TH.varP contextName) $constructorP =+                case $(TH.varE contextName) of+                    SExpr -> $(columnsE (\_ x -> [|toColumns $x|]))+                    SField -> $(columnsE (\_ x -> [|toColumns $x|]))+                    SName -> $(columnsE (\_ x -> [|toColumns $x|]))+                    SResult -> $(columnsE (\ft x -> [|serialize' (Proxy :: Proxy $ft) $x|]))++            gfromResult $columnsP =+                $(constructorE (\ft x -> [|deserialize' (Proxy :: Proxy $ft) $x|]))++            gtoResult $constructorP =+                $(columnsE (\ft x -> [|serialize' (Proxy :: Proxy $ft) $x|]))+        |]++-- | Like 'deriveRel8able' but for a list of datatypes.+-- This is helpful as all of the instances live in a single splice.+-- Each TH splice creates a new decleration group, so they cannot see instances later in the file.+-- By deriving the instances in the same splice, we can ensure that they see each other.+-- This is necessary when deriving cyclic instances, but also reduces the amount of splice sorting required.+-- There is also a small performance overhead to each TH splice.+deriveRel8ables :: [TH.Name] -> Q [TH.Dec]+deriveRel8ables xs = concat <$> traverse deriveRel8able xs++-- | Walk 'TH.Type' and replace all occurences of @Column f x@ with @Expr x@.+resolveColumnF :: TH.Name -> TH.Type -> TH.Type+resolveColumnF fBinder (TH.ForallT tvs context t) =+    TH.ForallT tvs context (resolveColumnF fBinder t)+resolveColumnF fBinder (TH.AppT f x)+    | TH.ConT columnName `TH.AppT` (TH.VarT fBinder') <- f+    , columnName == ''Column+    , fBinder == fBinder' =+        TH.AppT (TH.ConT ''Expr) (resolveColumnF fBinder x)+    | otherwise = TH.AppT (resolveColumnF fBinder f) (resolveColumnF fBinder x)+resolveColumnF fBinder (TH.SigT t k) = TH.SigT (resolveColumnF fBinder t) (resolveColumnF fBinder k) -- k could be Kind+resolveColumnF fBinder (TH.InfixT l c r) = TH.InfixT (resolveColumnF fBinder l) c (resolveColumnF fBinder r)+resolveColumnF fBinder (TH.UInfixT l c r) = TH.UInfixT (resolveColumnF fBinder l) c (resolveColumnF fBinder r)+resolveColumnF fBinder (TH.ParensT t) = TH.ParensT (resolveColumnF fBinder t)+#if MIN_VERSION_template_haskell(2,15,0)+resolveColumnF fBinder (TH.AppKindT t k)  = TH.AppKindT (resolveColumnF fBinder t) (resolveColumnF fBinder k)+resolveColumnF fBinder (TH.ImplicitParamT n t)+  = TH.ImplicitParamT n (resolveColumnF fBinder t)+#endif+#if MIN_VERSION_template_haskell(2,16,0)+resolveColumnF fBinder (TH.ForallVisT tvs t) =+  TH.ForallVisT tvs (resolveColumnF fBinder t)+#endif+#if MIN_VERSION_template_haskell(2,19,0)+resolveColumnF fBinder (TH.PromotedInfixT l c r)+  = TH.PromotedInfixT (resolveColumnF fBinder l) c (resolveColumnF fBinder r)+resolveColumnF fBinder (TH.PromotedUInfixT l c r)+  = TH.PromotedUInfixT (resolveColumnF fBinder l) c (resolveColumnF fBinder r)+#endif+resolveColumnF _ t = t
− src/Rel8/Table.hs
@@ -1,223 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language DataKinds #-}-{-# language DefaultSignatures #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language FunctionalDependencies #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Table-  ( Table-      ( Columns, Context, fromColumns, toColumns-      , FromExprs, fromResult, toResult-      , Transpose-      )-  , Congruent-  , TTable, TColumns, TContext, TFromExprs, TTranspose-  , TSerialize-  )-where---- base-import Data.Functor.Identity ( Identity( Identity ) )-import Data.Kind ( Constraint, Type )-import GHC.Generics ( Generic, Rep, from, to )-import Prelude hiding ( null )---- rel8-import Rel8.FCF ( Eval, Exp )-import Rel8.Generic.Map ( Map )-import Rel8.Generic.Table.Record-  ( GTable, GColumns, GContext, gfromColumns, gtoColumns-  , GSerialize, gfromResult, gtoResult-  )-import Rel8.Generic.Record ( Record(..) )-import Rel8.Schema.HTable ( HTable )-import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Null ( Sql )-import Rel8.Schema.Result ( Result )-import Rel8.Type ( DBType )----- | @Table@s are one of the foundational elements of Rel8, and describe data--- types that have a finite number of columns. Each of these columns contains--- data under a shared context, and contexts describe how to interpret the--- metadata about a column to a particular Haskell type. In Rel8, we have--- contexts for expressions (the 'Rel8.Expr' context), aggregations (the--- 'Rel8.Aggregate' context), insert values (the 'Rel8.Insert' contex), among--- others.------ In typical usage of Rel8 you don't need to derive instances of 'Table'--- yourself, as anything that's an instance of 'Rel8.Rel8able' is always a--- 'Table'.-type Table :: K.Context -> Type -> Constraint-class-  ( HTable (Columns a)-  , context ~ Context a-  , a ~ Transpose context a-  )-  => Table context a | a -> context- where-  -- | The 'HTable' functor that describes the schema of this table.-  type Columns a :: K.HTable--  -- | The common context that all columns use as an interpretation.-  type Context a :: K.Context--  -- | The @FromExprs@ type family maps a type in the @Expr@ context to the-  -- corresponding Haskell type.-  type FromExprs a :: Type--  type Transpose (context' :: K.Context) a :: Type---  toColumns :: a -> Columns a context-  fromColumns :: Columns a context -> a--  fromResult :: Columns a Result -> FromExprs a-  toResult :: FromExprs a -> Columns a Result--  type Columns a = GColumns TColumns (Rep (Record a))-  type Context a = GContext TContext (Rep (Record a))-  type FromExprs a = Map TFromExprs a-  type Transpose context a = Map (TTranspose context) a--  default toColumns ::-    ( Generic (Record a)-    , GTable (TTable context) TColumns (Rep (Record a))-    , Columns a ~ GColumns TColumns (Rep (Record a))-    )-    => a -> Columns a context-  toColumns =-    gtoColumns @(TTable context) @TColumns toColumns .-    from .-    Record--  default fromColumns ::-    ( Generic (Record a)-    , GTable (TTable context) TColumns (Rep (Record a))-    , Columns a ~ GColumns TColumns (Rep (Record a))-    )-    => Columns a context -> a-  fromColumns =-    unrecord .-    to .-    gfromColumns @(TTable context) @TColumns fromColumns--  default toResult ::-    ( Generic (Record (FromExprs a))-    , GSerialize TSerialize TColumns (Rep (Record a)) (Rep (Record (FromExprs a)))-    , Columns a ~ GColumns TColumns (Rep (Record a))-    )-    => FromExprs a -> Columns a Result-  toResult =-    gtoResult-      @TSerialize-      @TColumns-      @(Rep (Record a))-      @(Rep (Record (FromExprs a)))-      (\(_ :: proxy x) -> toResult @(Context x) @x) .-    from .-    Record--  default fromResult ::-    ( Generic (Record (FromExprs a))-    , GSerialize TSerialize TColumns (Rep (Record a)) (Rep (Record (FromExprs a)))-    , Columns a ~ GColumns TColumns (Rep (Record a))-    )-    => Columns a Result -> FromExprs a-  fromResult =-    unrecord .-    to .-    gfromResult-      @TSerialize-      @TColumns-      @(Rep (Record a))-      @(Rep (Record (FromExprs a)))-      (\(_ :: proxy x) -> fromResult @(Context x) @x)---instance Sql DBType a => Table Result (Identity a) where-  type Columns (Identity a) = HIdentity a-  type Context (Identity a) = Result-  type FromExprs (Identity a) = a-  type Transpose to (Identity a) = to a--  toColumns = HIdentity-  fromColumns (HIdentity a) = a-  toResult a = HIdentity (Identity a)-  fromResult (HIdentity (Identity a)) = a---data TTable :: K.Context -> Type -> Exp Constraint-type instance Eval (TTable context a) = Table context a---data TColumns :: Type -> Exp K.HTable-type instance Eval (TColumns a) = Columns a---data TContext :: Type -> Exp K.Context-type instance Eval (TContext a) = Context a---data TFromExprs :: Type -> Exp Type-type instance Eval (TFromExprs a) = FromExprs a---data TTranspose :: K.Context -> Type -> Exp Type-type instance Eval (TTranspose context a) = Transpose context a---data TSerialize :: Type -> Type -> Exp Constraint-type instance Eval (TSerialize expr a) =-  ( Table (Context expr) expr-  , a ~ FromExprs expr-  )---instance (Table context a, Table context b) => Table context (a, b)---instance-  ( Table context a, Table context b, Table context c-  )-  => Table context (a, b, c)---instance-  ( Table context a, Table context b, Table context c, Table context d-  )-  => Table context (a, b, c, d)---instance-  ( Table context a, Table context b, Table context c, Table context d-  , Table context e-  )-  => Table context (a, b, c, d, e)---instance-  ( Table context a, Table context b, Table context c, Table context d-  , Table context e, Table context f-  )-  => Table context (a, b, c, d, e, f)---instance-  ( Table context a, Table context b, Table context c, Table context d-  , Table context e, Table context f, Table context g-  )-  => Table context (a, b, c, d, e, f, g)---type Congruent :: Type -> Type -> Constraint-class Columns a ~ Columns b => Congruent a b-instance Columns a ~ Columns b => Congruent a b
− src/Rel8/Table/ADT.hs
@@ -1,168 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language RankNTypes #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilyDependencies #-}-{-# language UndecidableInstances #-}-{-# language UndecidableSuperClasses #-}--module Rel8.Table.ADT-  ( ADT( ADT )-  , ADTable-  , BuildableADT-  , BuildADT, buildADT-  , ConstructableADT-  , ConstructADT, constructADT-  , DeconstructADT, deconstructADT, deconstructAADT-  , NameADT, nameADT-  , ADTRep-  )-where---- base-import Data.Kind ( Constraint, Type )-import GHC.Generics ( Generic, from, to )-import GHC.TypeLits ( Symbol )-import Prelude---- rel8-import Rel8.Expr ( Expr )-import Rel8.FCF ( Eval, Exp )-import Rel8.Generic.Construction-  ( GGBuildable-  , GGBuild, ggbuild-  , GGConstructable-  , GGConstruct, ggconstruct-  , GGDeconstruct, ggdeconstruct, ggdeconstructA-  , GGName, ggname-  )-import Rel8.Generic.Record ( Record( Record ), unrecord )-import Rel8.Generic.Rel8able-  ( Rel8able-  , GRep, GColumns, gfromColumns, gtoColumns-  , GFromExprs, gfromResult, gtoResult-  , TSerialize, deserialize, serialize-  )-import qualified Rel8.Generic.Table.ADT as G-import qualified Rel8.Kind.Algebra as K-import Rel8.Schema.HTable ( HTable )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Name ( Name )-import Rel8.Schema.Result ( Result )-import Rel8.Table ( Table, TColumns )---- semigroupoids-import Data.Functor.Apply (Apply)---type ADT :: K.Rel8able -> K.Rel8able-newtype ADT t context = ADT (GColumnsADT t context)---instance ADTable t => Rel8able (ADT t) where-  type GColumns (ADT t) = GColumnsADT t-  type GFromExprs (ADT t) = t Result--  gfromColumns _ = ADT-  gtoColumns _ (ADT a) = a--  gfromResult =-    unrecord .-    to .-    G.gfromResultADT-      @TSerialize-      @TColumns-      @(Eval (ADTRep t Expr))-      @(Eval (ADTRep t Result))-      (\(_ :: proxy x) -> deserialize @_ @x)--  gtoResult =-    G.gtoResultADT-      @TSerialize-      @TColumns-      @(Eval (ADTRep t Expr))-      @(Eval (ADTRep t Result))-      (\(_ :: proxy x) -> serialize @_ @x) .-    from .-    Record---type ADTable :: K.Rel8able -> Constraint-class-  ( Generic (Record (t Result))-  , HTable (GColumnsADT t)-  , G.GSerializeADT TSerialize TColumns (Eval (ADTRep t Expr)) (Eval (ADTRep t Result))-  )-  => ADTable t-instance-  ( Generic (Record (t Result))-  , HTable (GColumnsADT t)-  , G.GSerializeADT TSerialize TColumns (Eval (ADTRep t Expr)) (Eval (ADTRep t Result))-  )-  => ADTable t---type BuildableADT :: K.Rel8able -> Symbol -> Constraint-class GGBuildable 'K.Sum name (ADTRep t) => BuildableADT t name-instance GGBuildable 'K.Sum name (ADTRep t) => BuildableADT t name---type BuildADT :: K.Rel8able -> Symbol -> Type-type BuildADT t name = GGBuild 'K.Sum name (ADTRep t) (ADT t Expr)---buildADT :: forall t name. BuildableADT t name => BuildADT t name-buildADT =-  ggbuild @'K.Sum @name @(ADTRep t) @(ADT t Expr) ADT---type ConstructableADT :: K.Rel8able -> Constraint-class GGConstructable 'K.Sum (ADTRep t) => ConstructableADT t-instance GGConstructable 'K.Sum (ADTRep t) => ConstructableADT t---type ConstructADT :: K.Rel8able -> Type-type ConstructADT t = forall r. GGConstruct 'K.Sum (ADTRep t) r---constructADT :: forall t. ConstructableADT t => ConstructADT t -> ADT t Expr-constructADT f =-  ggconstruct @'K.Sum @(ADTRep t) @(ADT t Expr) ADT-    (f @(ADT t Expr))---type DeconstructADT :: K.Rel8able -> Type -> Type-type DeconstructADT t r = GGDeconstruct 'K.Sum (ADTRep t) (ADT t Expr) r---deconstructADT :: forall t r. (ConstructableADT t, Table Expr r)-  => DeconstructADT t r-deconstructADT =-  ggdeconstruct @'K.Sum @(ADTRep t) @(ADT t Expr) @r (\(ADT a) -> a)---deconstructAADT :: forall t f r. (ConstructableADT t, Apply f, Table Expr r)-  => DeconstructADT t (f r)-deconstructAADT =-  ggdeconstructA @'K.Sum @(ADTRep t) @(ADT t Expr) @f @r (\(ADT a) -> a)---type NameADT :: K.Rel8able -> Type-type NameADT t = GGName 'K.Sum (ADTRep t) (ADT t Name)---nameADT :: forall t. ConstructableADT t => NameADT t-nameADT = ggname @'K.Sum @(ADTRep t) @(ADT t Name) ADT---data ADTRep :: K.Rel8able -> K.Context -> Exp (Type -> Type)-type instance Eval (ADTRep t context) = GRep t context---type GColumnsADT :: K.Rel8able -> K.HTable-type GColumnsADT t = G.GColumnsADT TColumns (GRep t Expr)
− src/Rel8/Table/Aggregate.hs
@@ -1,170 +0,0 @@-{-# language BlockArguments #-}-{-# language FlexibleContexts #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}--module Rel8.Table.Aggregate-  ( groupBy, groupByOn-  , listAgg, listAggOn, nonEmptyAgg, nonEmptyAggOn-  , listCat, listCatOn, nonEmptyCat, nonEmptyCatOn-  , filterWhere-  , orderAggregateBy-  )-where---- base-import Prelude---- opaleye-import qualified Opaleye.Internal.Aggregate as Opaleye---- profunctors-import Data.Profunctor (dimap, lmap)---- rel8-import Rel8.Aggregate (Aggregator,  Aggregator' (Aggregator), Aggregator1)-import Rel8.Expr ( Expr )-import Rel8.Expr.Aggregate-  ( filterWhereExplicit-  , groupByExprOn-  , slistAggExpr-  , slistCatExpr-  , snonEmptyAggExpr-  , snonEmptyCatExpr-  )-import Rel8.Order (Order (Order))-import Rel8.Schema.Dict ( Dict( Dict ) )-import Rel8.Schema.HTable (HTable, hfield, hspecs, htabulateA)-import Rel8.Schema.HTable.Vectorize (htraverseVectorP, hvectorizeA)-import Rel8.Schema.Null ( Sql )-import Rel8.Schema.Spec ( Spec( Spec, info ) )-import Rel8.Table (Table, toColumns, fromColumns)-import Rel8.Table.Eq ( EqTable, eqTable )-import Rel8.Table.List ( ListTable )-import Rel8.Table.NonEmpty ( NonEmptyTable )-import Rel8.Table.Opaleye (ifPP)-import Rel8.Type.Eq ( DBEq )----- | Group equal tables together. This works by aggregating each column in the--- given table with 'groupByExpr'.------ For example, if we have a table of items, we could group the items by the--- order they belong to:------ @--- itemsByOrder :: Query (OrderId Expr, ListTable Expr (Item Expr))--- itemsByOrder =---   aggregate---     do---       orderId <- groupByOn (.orderId)---       items <- listAgg---       pure (orderId, items)---     do---       each itemSchema--- @-groupBy :: forall a. EqTable a => Aggregator1 a a-groupBy = dimap toColumns fromColumns (hgroupBy (eqTable @a))----- | Applies 'groupBy' to the columns selected by the given function.-groupByOn :: EqTable a => (i -> a) -> Aggregator1 i a-groupByOn f = lmap f groupBy---hgroupBy :: HTable t => t (Dict (Sql DBEq)) -> Aggregator1 (t Expr) (t Expr)-hgroupBy eqs = htabulateA $ \field -> case hfield eqs field of-  Dict -> groupByExprOn (`hfield` field)----- | 'filterWhere' allows an 'Aggregator' to filter out rows from the input--- query before considering them for aggregation. Note that because the--- predicate supplied to 'filterWhere' could return 'Rel8.false' for every--- row, 'filterWhere' needs an 'Aggregator' as opposed to an 'Aggregator1', so--- that it can return a default value in such a case. For a variant of--- 'filterWhere' that can work with 'Aggregator1's, see--- 'Rel8.filterWhereOptional'.-filterWhere :: Table Expr a-  => (i -> Expr Bool) -> Aggregator i a -> Aggregator' fold i a-filterWhere = filterWhereExplicit ifPP----- | Aggregate rows into a single row containing an array of all aggregated--- rows. This can be used to associate multiple rows with a single row, without--- changing the over cardinality of the query. This allows you to essentially--- return a tree-like structure from queries.------ For example, if we have a table of orders and each orders contains multiple--- items, we could aggregate the table of orders, pairing each order with its--- items:------ @--- ordersWithItems :: Query (Order Expr, ListTable Expr (Item Expr))--- ordersWithItems = do---   order <- each orderSchema---   items <- aggregate listAgg (itemsFromOrder order)---   return (order, items)--- @-listAgg :: Table Expr a => Aggregator' fold a (ListTable Expr a)-listAgg =-  fromColumns <$>-  hvectorizeA \Spec {info} field ->-    lmap ((`hfield` field) . toColumns) $ slistAggExpr info----- | Applies 'listAgg' to the columns selected by the given function.-listAggOn :: Table Expr a => (i -> a) -> Aggregator' fold i (ListTable Expr a)-listAggOn f = lmap f listAgg----- | Like 'listAgg', but the result is guaranteed to be a non-empty list.-nonEmptyAgg :: Table Expr a => Aggregator1 a (NonEmptyTable Expr a)-nonEmptyAgg =-  fromColumns <$>-  hvectorizeA \Spec {info} field ->-    lmap ((`hfield` field) . toColumns) $ snonEmptyAggExpr info----- | Applies 'nonEmptyAgg' to the columns selected by the given function.-nonEmptyAggOn :: Table Expr a-  => (i -> a) -> Aggregator1 i (NonEmptyTable Expr a)-nonEmptyAggOn f = lmap f nonEmptyAgg----- | Concatenate lists into a single list.-listCat :: Table Expr a-  => Aggregator' fold (ListTable Expr a) (ListTable Expr a)-listCat = dimap toColumns fromColumns $-  htraverseVectorP (\field -> case hfield hspecs field of-    Spec {info} -> slistCatExpr info)----- | Applies 'listCat' to the list selected by the given function.-listCatOn :: Table Expr a-  => (i -> ListTable Expr a) -> Aggregator' fold i (ListTable Expr a)-listCatOn f = lmap f listCat----- | Concatenate non-empty lists into a single non-empty list.-nonEmptyCat :: Table Expr a-  => Aggregator1 (NonEmptyTable Expr a) (NonEmptyTable Expr a)-nonEmptyCat = dimap toColumns fromColumns $-  htraverseVectorP (\field -> case hfield hspecs field of-    Spec {info} -> snonEmptyCatExpr info)----- | Applies 'nonEmptyCat' to the non-empty list selected by the given--- function.-nonEmptyCatOn :: Table Expr a-  => (i -> NonEmptyTable Expr a) -> Aggregator1 i (NonEmptyTable Expr a)-nonEmptyCatOn f = lmap f nonEmptyCat----- | Order the values within each aggregation in an `Aggregator` using the--- given ordering. This is only relevant for aggregations that depend on the--- order they get their elements, like `Rel8.listAgg` and `Rel8.stringAgg`.-orderAggregateBy :: Order i -> Aggregator' fold i a -> Aggregator' fold i a-orderAggregateBy (Order order) (Aggregator fallback aggregator) =-  Aggregator fallback $ Opaleye.orderAggregate order aggregator
− src/Rel8/Table/Aggregate/Maybe.hs
@@ -1,89 +0,0 @@-{-# language FlexibleContexts #-}--module Rel8.Table.Aggregate.Maybe-  ( filterWhereOptional-  , optionalAggregate-  , aggregateJustTable-  , aggregateJustTable1-  , aggregateMaybeTable-  )-where---- base-import Prelude---- opaleye-import qualified Opaleye.Internal.Aggregate as Opaleye---- profunctors-import Data.Profunctor (lmap)---- rel8-import Rel8.Aggregate-  ( Aggregator' (Aggregator)-  , Aggregator, toAggregator-  , Aggregator1, toAggregator1-  )-import Rel8.Aggregate.Fold (Fallback (Fallback))-import Rel8.Expr (Expr)-import Rel8.Expr.Aggregate (groupByExprOn)-import Rel8.Expr.Opaleye (toColumn, toPrimExpr)-import Rel8.Table (Table)-import Rel8.Table.Aggregate (filterWhere)-import Rel8.Table.Maybe-  ( MaybeTable (MaybeTable, just, tag), justTable, nothingTable-  , isJustTable-  , makeMaybeTable-  )-import Rel8.Table.Nullify (aggregateNullify, unsafeUnnullifyTable)----- | A variant of 'filterWhere' that can be used with an 'Aggregator1'--- (upgrading it to an 'Aggregator' in the process). It returns--- 'nothingTable' in the case where the predicate matches zero rows.-filterWhereOptional :: Table Expr a-  => (i -> Expr Bool) -> Aggregator' fold i a -> Aggregator' fold' i (MaybeTable Expr a)-filterWhereOptional f (Aggregator _ aggregator) =-  Aggregator (Fallback nothingTable) $-    Opaleye.filterWhereInternal makeMaybeTable (toColumn . toPrimExpr . f) aggregator----- | 'optionalAggregate' upgrades an 'Aggregator1' into an 'Aggregator' by--- having it return 'nothingTable' when aggregating over an empty collection--- of rows.-optionalAggregate :: Table Expr a-  => Aggregator' fold i a -> Aggregator' fold' i (MaybeTable Expr a)-optionalAggregate = toAggregator nothingTable . fmap justTable----- | Lift an 'Aggregator' to operate on a 'MaybeTable'. If the input query has--- @'justTable' i@s, they are folded into a single @a@ by the given aggregator--- — in the case where the input query is all 'nothingTable's, the--- 'Aggregator'\'s fallback @a@ is returned.-aggregateJustTable :: Table Expr a-  => Aggregator i a-  -> Aggregator' fold (MaybeTable Expr i) a-aggregateJustTable =-  filterWhere isJustTable . lmap (unsafeUnnullifyTable . just)----- | Lift an 'Aggregator1' to operate on a 'MaybeTable'. If the input query--- has @'justTable' i@s, they are folded into a single @'justTable' a@ by the--- given aggregator — in the case where the input query is all--- 'nothingTable's, a single 'nothingTable' row is returned.-aggregateJustTable1 :: Table Expr a-  => Aggregator' fold i a-  -> Aggregator' fold' (MaybeTable Expr i) (MaybeTable Expr a)-aggregateJustTable1 =-  filterWhereOptional isJustTable . lmap (unsafeUnnullifyTable . just)----- | Lift an aggregator to operate on a 'MaybeTable'. @nothingTable@s and--- @justTable@s are grouped separately.-aggregateMaybeTable :: ()-  => Aggregator' fold i a-  -> Aggregator1 (MaybeTable Expr i) (MaybeTable Expr a)-aggregateMaybeTable aggregator =-  MaybeTable-    <$> groupByExprOn tag-    <*> lmap just (toAggregator1 (aggregateNullify aggregator))
− src/Rel8/Table/Alternative.hs
@@ -1,37 +0,0 @@-{-# language FlexibleContexts #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}--module Rel8.Table.Alternative-  ( AltTable ( (<|>:) )-  , AlternativeTable ( emptyTable )-  )-where---- base-import Data.Kind ( Constraint, Type )-import Prelude ()---- rel8-import Rel8.Expr ( Expr )-import Rel8.Table ( Table )----- | Like 'Alt' in Haskell. This class is purely a Rel8 concept, and allows you--- to take a choice between two tables. See also 'AlternativeTable'.------ For example, using '<|>:' on 'Rel8.MaybeTable' allows you to combine two--- tables and to return the first one that is a "just" MaybeTable.-type AltTable :: (Type -> Type) -> Constraint-class AltTable f where-  -- | An associative binary operation on 'Table's.-  (<|>:) :: Table Expr a => f a -> f a -> f a-  infixl 3 <|>:----- | Like 'Alternative' in Haskell, some 'Table's form a monoid on applicative--- functors.-type AlternativeTable :: (Type -> Type) -> Constraint-class AltTable f => AlternativeTable f where-  -- | The identity of '<|>:'.-  emptyTable :: Table Expr a => f a
− src/Rel8/Table/Bool.hs
@@ -1,48 +0,0 @@-{-# language FlexibleContexts #-}-{-# language TypeFamilies #-}-{-# language ViewPatterns #-}--module Rel8.Table.Bool-  ( bool-  , case_-  , nullable-  )-where---- base-import Prelude---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Bool ( boolExpr, caseExpr )-import Rel8.Expr.Null ( isNull, unsafeUnnullify )-import Rel8.Schema.HTable ( htabulate, hfield )-import Rel8.Table ( Table, fromColumns, toColumns )----- | An if-then-else expression on tables.------ @bool x y p@ returns @x@ if @p@ is @False@, and returns @y@ if @p@ is--- @True@.-bool :: Table Expr a => a -> a -> Expr Bool -> a-bool (toColumns -> false) (toColumns -> true) condition =-  fromColumns $ htabulate $ \field ->-    case (hfield false field, hfield true field) of-      (falseExpr, trueExpr) -> boolExpr falseExpr trueExpr condition-{-# INLINABLE bool #-}----- | Produce a table expression from a list of alternatives. Returns the first--- table where the @Expr Bool@ expression is @True@. If no alternatives are--- true, the given default is returned.-case_ :: Table Expr a => [(Expr Bool, a)] -> a -> a-case_ (map (fmap toColumns) -> branches) (toColumns -> fallback) =-  fromColumns $ htabulate $ \field -> case hfield fallback field of-    fallbackExpr ->-      case map (fmap (`hfield` field)) branches of-        branchExprs -> caseExpr branchExprs fallbackExpr----- | Like 'maybe', but to eliminate @null@.-nullable :: Table Expr b => b -> (Expr a -> b) -> Expr (Maybe a) -> b-nullable b f ma = bool (f (unsafeUnnullify ma)) b (isNull ma)
− src/Rel8/Table/Cols.hs
@@ -1,51 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Table.Cols-  ( Cols( Cols )-  , fromCols-  , toCols-  )-where---- base-import Data.Kind ( Type )-import Prelude---- rel8-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.HTable ( HTable )-import Rel8.Schema.Result ( Result )-import Rel8.Table ( Table(..) )---type Cols :: K.Context -> K.HTable -> Type-newtype Cols context columns = Cols (columns context)---instance (HTable columns, context ~ context') =>-  Table context' (Cols context columns)- where-  type Columns (Cols context columns) = columns-  type Context (Cols context columns) = context-  type FromExprs (Cols context columns) = Cols Result columns-  type Transpose to (Cols context columns) = Cols to columns--  toColumns (Cols a) = a-  fromColumns = Cols--  toResult (Cols a) = a-  fromResult = Cols---fromCols :: Table context a => Cols context (Columns a) -> a-fromCols (Cols a) = fromColumns a---toCols :: Table context a => a -> Cols context (Columns a)-toCols = Cols . toColumns
− src/Rel8/Table/Either.hs
@@ -1,298 +0,0 @@-{-# language ApplicativeDo #-}-{-# language DataKinds #-}-{-# language DeriveFunctor #-}-{-# language DerivingStrategies #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language LambdaCase #-}-{-# language MultiParamTypeClasses #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--{-# options_ghc -fno-warn-orphans #-}--module Rel8.Table.Either-  ( EitherTable(..)-  , eitherTable, leftTable, rightTable-  , isLeftTable, isRightTable-  , aggregateLeftTable, aggregateLeftTable1-  , aggregateRightTable, aggregateRightTable1-  , aggregateEitherTable-  , nameEitherTable-  )-where---- base-import Data.Bifunctor ( Bifunctor, bimap )-import Data.Functor.Identity ( Identity( Identity ) )-import Data.Kind ( Type )-import Prelude hiding ( undefined )---- comonad-import Control.Comonad ( extract )---- profunctors-import Data.Profunctor (lmap)---- rel8-import Rel8.Aggregate (Aggregator, Aggregator', Aggregator1, toAggregator1)-import Rel8.Expr ( Expr )-import Rel8.Expr.Aggregate (groupByExprOn)-import Rel8.Expr.Serialize ( litExpr )-import Rel8.Kind.Context ( Reifiable )-import Rel8.Schema.Context.Nullify ( Nullifiable )-import Rel8.Schema.Dict ( Dict( Dict ) )-import Rel8.Schema.HTable.Either ( HEitherTable(..) )-import Rel8.Schema.HTable.Identity ( HIdentity(..) )-import Rel8.Schema.HTable.Label ( hlabel, hunlabel )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Name ( Name )-import Rel8.Table-  ( Table, Columns, Context, fromColumns, toColumns-  , FromExprs, fromResult, toResult-  , Transpose-  )-import Rel8.Table.Aggregate (filterWhere)-import Rel8.Table.Aggregate.Maybe (filterWhereOptional)-import Rel8.Table.Bool ( bool )-import Rel8.Table.Eq ( EqTable, eqTable )-import Rel8.Table.Maybe (MaybeTable)-import Rel8.Table.Nullify-  ( Nullify, aggregateNullify, guard, unsafeUnnullifyTable-  )-import Rel8.Table.Ord ( OrdTable, ordTable )-import Rel8.Table.Projection ( Biprojectable, Projectable, biproject, project )-import Rel8.Table.Serialize ( ToExprs )-import Rel8.Table.Undefined ( undefined )-import Rel8.Type.Tag ( EitherTag( IsLeft, IsRight ), isLeft, isRight )---- semigroupoids-import Data.Functor.Apply ( Apply, (<.>) )-import Data.Functor.Bind ( Bind, (>>-) )----- | An @EitherTable a b@ is a Rel8 table that contains either the table @a@ or--- the table @b@. You can construct an @EitherTable@ using 'leftTable' and--- 'rightTable', and eliminate/pattern match using 'eitherTable'.------ An @EitherTable@ is operationally the same as Haskell's 'Either' type, but--- adapted to work with Rel8.-type EitherTable :: K.Context -> Type -> Type -> Type-data EitherTable context a b = EitherTable-  { tag :: context EitherTag-  , left :: Nullify context a-  , right :: Nullify context b-  }-  deriving stock Functor---instance Biprojectable (EitherTable context) where-  biproject f g (EitherTable tag a b) =-    EitherTable tag (project f a) (project g b)---instance Nullifiable context => Bifunctor (EitherTable context) where-  bimap f g (EitherTable tag a b) = EitherTable tag (fmap f a) (fmap g b)---instance Projectable (EitherTable context a) where-  project f (EitherTable tag a b) = EitherTable tag a (project f b)---instance (context ~ Expr, Table Expr a) => Apply (EitherTable context a) where-  EitherTable tag l1 f <.> EitherTable tag' l2 a =-    EitherTable (tag <> tag') (bool l1 l2 (isLeft tag)) (f <.> a)---instance (context ~ Expr, Table Expr a) => Applicative (EitherTable context a) where-  pure = rightTable-  (<*>) = (<.>)---instance (context ~ Expr, Table Expr a) => Bind (EitherTable context a) where-  EitherTable tag l1 a >>- f = case f (extract a) of-    EitherTable tag' l2 b ->-      EitherTable (tag <> tag') (bool l1 l2 (isRight tag)) b---instance (context ~ Expr, Table Expr a) => Monad (EitherTable context a) where-  (>>=) = (>>-)---instance (context ~ Expr, Table Expr a, Table Expr b) =>-  Semigroup (EitherTable context a b)- where-  a <> b = bool a b (isRightTable a)---instance-  ( Table context a, Table context b-  , Reifiable context, context ~ context'-  )-  => Table context' (EitherTable context a b)- where-  type Columns (EitherTable context a b) = HEitherTable (Columns a) (Columns b)-  type Context (EitherTable context a b) = Context a-  type FromExprs (EitherTable context a b) = Either (FromExprs a) (FromExprs b)-  type Transpose to (EitherTable context a b) =-    EitherTable to (Transpose to a) (Transpose to b)--  toColumns EitherTable {tag, left, right} = HEitherTable-    { htag = hlabel $ HIdentity tag-    , hleft = hlabel $ guard tag (== IsLeft) isLeft $ toColumns left-    , hright = hlabel $ guard tag (== IsRight) isRight $ toColumns right-    }--  fromColumns HEitherTable {htag, hleft, hright} = EitherTable-    { tag = unHIdentity $ hunlabel htag-    , left = fromColumns $ hunlabel hleft-    , right = fromColumns $ hunlabel hright-    }--  toResult = \case-    Left table -> HEitherTable-      { htag = hlabel (HIdentity (Identity IsLeft))-      , hleft = hlabel (toResult @_ @(Nullify context a) (Just table))-      , hright = hlabel (toResult @_ @(Nullify context b) Nothing)-      }-    Right table -> HEitherTable-      { htag = hlabel (HIdentity (Identity IsRight))-      , hleft = hlabel (toResult @_ @(Nullify context a) Nothing)-      , hright = hlabel (toResult @_ @(Nullify context b) (Just table))-      }--  fromResult HEitherTable {htag, hleft, hright} = case hunlabel htag of-    HIdentity (Identity tag) -> case tag of-      IsLeft -> maybe err Left $ fromResult @_ @(Nullify context a) (hunlabel hleft)-      IsRight -> maybe err Right $ fromResult @_ @(Nullify context b) (hunlabel hright)-    where-      err = error "Either.fromColumns: mismatch between tag and data"---instance (EqTable a, EqTable b, context ~ Expr) =>-  EqTable (EitherTable context a b)- where-  eqTable = HEitherTable-    { htag = hlabel (HIdentity Dict)-    , hleft = hlabel (eqTable @(Nullify context a))-    , hright = hlabel (eqTable @(Nullify context b))-    }---instance (OrdTable a, OrdTable b, context ~ Expr) =>-  OrdTable (EitherTable context a b)- where-  ordTable = HEitherTable-    { htag = hlabel (HIdentity Dict)-    , hleft = hlabel (ordTable @(Nullify context a))-    , hright = hlabel (ordTable @(Nullify context b))-    }---instance (ToExprs exprs1 a, ToExprs exprs2 b, x ~ EitherTable Expr exprs1 exprs2) =>-  ToExprs x (Either a b)----- | Test if an 'EitherTable' is a 'leftTable'.-isLeftTable :: EitherTable Expr a b -> Expr Bool-isLeftTable EitherTable {tag} = isLeft tag----- | Test if an 'EitherTable' is a 'rightTable'.-isRightTable :: EitherTable Expr a b -> Expr Bool-isRightTable EitherTable {tag} = isRight tag----- | Pattern match/eliminate an 'EitherTable', by providing mappings from a--- 'leftTable' and 'rightTable'.-eitherTable :: Table Expr c-  => (a -> c) -> (b -> c) -> EitherTable Expr a b -> c-eitherTable f g EitherTable {tag, left, right} =-  bool (f (extract left)) (g (extract right)) (isRight tag)----- | Construct a left 'EitherTable'. Like 'Left'.-leftTable :: Table Expr b => a -> EitherTable Expr a b-leftTable a = EitherTable (litExpr IsLeft) (pure a) undefined----- | Construct a right 'EitherTable'. Like 'Right'.-rightTable :: Table Expr a => b -> EitherTable Expr a b-rightTable = EitherTable (litExpr IsRight) undefined . pure----- | Lift an 'Aggregator' to operate on an 'EitherTable'. If the input query has--- @'leftTable' a@s, they are folded into a single @c@ by the given aggregator--- — in the case where the input query is all 'rightTable's, the--- 'Aggregator'\'s fallback @c@ is returned.-aggregateLeftTable :: Table Expr c-  => Aggregator a c-  -> Aggregator' fold (EitherTable Expr a b) c-aggregateLeftTable =-  filterWhere isLeftTable . lmap (unsafeUnnullifyTable . left)----- | Lift an 'Aggregator1' to operate on an 'EitherTable'. If the input query--- has @'leftTable' a@s, they are folded into a single @'Rel8.justTable' c@--- by the given aggregator — in the case where the input query is all--- 'rightTable's, a single 'nothingTable' row is returned.-aggregateLeftTable1 :: Table Expr c-  => Aggregator' fold a c-  -> Aggregator' fold' (EitherTable Expr a b) (MaybeTable Expr c)-aggregateLeftTable1 =-  filterWhereOptional isLeftTable . lmap (unsafeUnnullifyTable . left)----- | Lift an 'Aggregator' to operate on an 'EitherTable'. If the input query has--- @'rightTable' b@s, they are folded into a single @c@ by the given aggregator--- — in the case where the input query is all 'rightTable's, the--- 'Aggregator'\'s fallback @c@ is returned.-aggregateRightTable :: Table Expr c-  => Aggregator b c-  -> Aggregator' fold (EitherTable Expr a b) c-aggregateRightTable =-  filterWhere isRightTable . lmap (unsafeUnnullifyTable . right)----- | Lift an 'Aggregator1' to operate on an 'EitherTable'. If the input query--- has @'rightTable' b@s, they are folded into a single @'Rel8.justTable' c@--- by the given aggregator — in the case where the input query is all--- 'leftTable's, a single 'nothingTable' row is returned.-aggregateRightTable1 :: Table Expr c-  => Aggregator' fold a c-  -> Aggregator' fold' (EitherTable Expr a b) (MaybeTable Expr c)-aggregateRightTable1 =-  filterWhereOptional isLeftTable . lmap (unsafeUnnullifyTable . left)----- | Lift a pair aggregators to operate on an 'EitherTable'. @leftTable@s and--- @rightTable@s are grouped separately.-aggregateEitherTable :: ()-  => Aggregator' fold i a-  -> Aggregator' fold' i' b-  -> Aggregator1 (EitherTable Expr i i') (EitherTable Expr a b)-aggregateEitherTable a b =-  EitherTable-    <$> groupByExprOn tag-    <*> lmap left (toAggregator1 (aggregateNullify a))-    <*> lmap right (toAggregator1 (aggregateNullify b))----- | Construct a 'EitherTable' in the 'Name' context. This can be useful if you--- have a 'EitherTable' that you are storing in a table and need to construct a--- 'TableSchema'.-nameEitherTable-  :: Name EitherTag-     -- ^ The name of the column to track whether a row is a 'leftTable' or-     -- 'rightTable'.-  -> a-     -- ^ Names of the columns in the @a@ table.-  -> b-     -- ^ Names of the columns in the @b@ table.-  -> EitherTable Name a b-nameEitherTable tag left right = EitherTable tag (pure left) (pure right)
− src/Rel8/Table/Eq.hs
@@ -1,118 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language BlockArguments #-}-{-# language DataKinds #-}-{-# language DefaultSignatures #-}-{-# language DisambiguateRecordFields #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}-{-# language ViewPatterns #-}--module Rel8.Table.Eq-  ( EqTable( eqTable ), (==:), (/=:)-  )-where---- base-import Data.Foldable ( foldl' )-import Data.Functor.Const ( Const( Const ), getConst )-import Data.Kind ( Constraint, Type )-import Data.List.NonEmpty ( NonEmpty( (:|) ) )-import GHC.Generics ( Rep )-import Prelude---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Bool ( (||.), (&&.) )-import Rel8.Expr.Eq ( (==.), (/=.) )-import Rel8.FCF ( Eval, Exp )-import Rel8.Generic.Record ( Record )-import Rel8.Generic.Table.Record ( GTable, GColumns, gtable )-import Rel8.Schema.Dict ( Dict( Dict ) )-import Rel8.Schema.HTable ( htabulateA, hfield )-import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )-import Rel8.Schema.Null ( Sql )-import Rel8.Table ( Table, Columns, toColumns, TColumns )-import Rel8.Type.Eq ( DBEq )----- | The class of 'Table's that can be compared for equality. Equality on--- tables is defined by equality of all columns all columns, so this class--- means "all columns in a 'Table' have an instance of 'DBEq'".-type EqTable :: Type -> Constraint-class Table Expr a => EqTable a where-  eqTable :: Columns a (Dict (Sql DBEq))--  default eqTable ::-    ( GTable TEqTable TColumns (Rep (Record a))-    , Columns a ~ GColumns TColumns (Rep (Record a))-    )-    => Columns a (Dict (Sql DBEq))-  eqTable = gtable @TEqTable @TColumns @(Rep (Record a)) table-    where-      table (_ :: proxy x) = eqTable @x---data TEqTable :: Type -> Exp Constraint-type instance Eval (TEqTable a) = EqTable a---instance Sql DBEq a => EqTable (Expr a) where-  eqTable = HIdentity Dict---instance (EqTable a, EqTable b) => EqTable (a, b)---instance (EqTable a, EqTable b, EqTable c) => EqTable (a, b, c)---instance (EqTable a, EqTable b, EqTable c, EqTable d) => EqTable (a, b, c, d)---instance (EqTable a, EqTable b, EqTable c, EqTable d, EqTable e) =>-  EqTable (a, b, c, d, e)---instance (EqTable a, EqTable b, EqTable c, EqTable d, EqTable e, EqTable f) =>-  EqTable (a, b, c, d, e, f)---instance-  ( EqTable a, EqTable b, EqTable c, EqTable d, EqTable e, EqTable f-  , EqTable g-  )-  => EqTable (a, b, c, d, e, f, g)----- | Compare two 'Table's for equality. This corresponds to comparing all--- columns inside each table for equality, and combining all comparisons with--- @AND@.-(==:) :: forall a. EqTable a => a -> a -> Expr Bool-(toColumns -> as) ==: (toColumns -> bs) =-  foldl1' (&&.) $ getConst $ htabulateA $ \field ->-    case (hfield as field, hfield bs field) of-      (a, b) -> case hfield (eqTable @a) field of-        Dict -> Const (pure (a ==. b))-infix 4 ==:----- | Test if two 'Table's are different. This corresponds to comparing all--- columns inside each table for inequality, and combining all comparisons with--- @OR@.-(/=:) :: forall a. EqTable a => a -> a -> Expr Bool-(toColumns -> as) /=: (toColumns -> bs) =-  foldl1' (||.) $ getConst $ htabulateA $ \field ->-    case (hfield as field, hfield bs field) of-      (a, b) -> case hfield (eqTable @a) field of-        Dict -> Const (pure (a /=. b))-infix 4 /=:---foldl1' :: (a -> a -> a) -> NonEmpty a -> a-foldl1' f (a :| as) = foldl' f a as
− src/Rel8/Table/HKD.hs
@@ -1,223 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language RankNTypes #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}-{-# language UndecidableSuperClasses #-}--module Rel8.Table.HKD-  ( HKD( HKD )-  , HKDable-  , BuildableHKD-  , BuildHKD, buildHKD-  , ConstructableHKD-  , ConstructHKD, constructHKD-  , DeconstructHKD, deconstructHKD, deconstructAHKD-  , NameHKD, nameHKD-  , HKDRep-  )-where---- base-import Data.Kind ( Constraint, Type )-import GHC.Generics ( Generic, Rep, from, to )-import GHC.TypeLits ( Symbol )-import Prelude---- rel8-import Rel8.Column ( TColumn )-import Rel8.Expr ( Expr )-import Rel8.FCF ( Eval, Exp )-import Rel8.Kind.Algebra ( KnownAlgebra )-import Rel8.Generic.Construction-  ( GGBuildable-  , GGBuild, ggbuild-  , GGConstructable-  , GGConstruct, ggconstruct-  , GGDeconstruct, ggdeconstruct, ggdeconstructA-  , GGName, ggname-  )-import Rel8.Generic.Map ( GMap )-import Rel8.Generic.Record-  ( GRecord, GRecordable, grecord, gunrecord-  , Record( Record ), unrecord-  )-import Rel8.Generic.Rel8able-  ( Rel8able-  , GColumns, gfromColumns, gtoColumns-  , GFromExprs, gfromResult, gtoResult-  )-import Rel8.Generic.Table-  ( GGSerialize, GGColumns, GAlgebra, ggfromResult, ggtoResult-  )-import Rel8.Generic.Table.Record ( GTable, GContext )-import qualified Rel8.Generic.Table.Record as G-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.HTable ( HTable )-import Rel8.Schema.Name ( Name )-import Rel8.Schema.Result ( Result )-import Rel8.Table-  ( Table, fromColumns, toColumns, fromResult, toResult-  , TTable, TColumns, TContext-  , TSerialize-  )---- semigroupoids-import Data.Functor.Apply (Apply)---type GColumnsHKD :: Type -> K.HTable-type GColumnsHKD a =-  Eval (GGColumns (GAlgebra (Rep a)) TColumns (GRecord (GMap (TColumn Expr) (Rep a))))---type HKD :: Type -> K.Rel8able-newtype HKD a f = HKD (GColumnsHKD a f)---instance HKDable a => Rel8able (HKD a) where-  type GColumns (HKD a) = GColumnsHKD a-  type GFromExprs (HKD a) = a--  gfromColumns _ = HKD-  gtoColumns _ (HKD a) = a--  gfromResult =-    unrecord .-    to .-    ggfromResult-      @(GAlgebra (Rep a))-      @TSerialize-      @TColumns-      @(Eval (HKDRep a Expr))-      @(Eval (HKDRep a Result))-      (\(_ :: proxy x) -> fromResult @_ @x)--  gtoResult =-    ggtoResult-      @(GAlgebra (Rep a))-      @TSerialize-      @TColumns-      @(Eval (HKDRep a Expr))-      @(Eval (HKDRep a Result))-      (\(_ :: proxy x) -> toResult @_ @x) .-    from .-    Record---instance-  ( GTable (TTable f) TColumns (GRecord (GMap (TColumn f) (Rep a)))-  , G.GColumns TColumns (GRecord (GMap (TColumn f) (Rep a))) ~ GColumnsHKD a-  , GContext TContext (GRecord (GMap (TColumn f) (Rep a))) ~ f-  , GRecordable (GMap (TColumn f) (Rep a))-  )-  => Generic (HKD a f)- where-  type Rep (HKD a f) = GMap (TColumn f) (Rep a)--  from =-    gunrecord @(GMap (TColumn f) (Rep a)) .-    G.gfromColumns-      @(TTable f)-      @TColumns-      fromColumns .-    (\(HKD a) -> a)--  to =-    HKD .-    G.gtoColumns-      @(TTable f)-      @TColumns-      toColumns .-    grecord @(GMap (TColumn f) (Rep a))---type HKDable :: Type -> Constraint-class-  ( Generic (Record a)-  , HTable (GColumns (HKD a))-  , KnownAlgebra (GAlgebra (Rep a))-  , Eval (GGSerialize (GAlgebra (Rep a)) TSerialize TColumns (Eval (HKDRep a Expr)) (Eval (HKDRep a Result)))-  , GRecord (GMap (TColumn Result) (Rep a)) ~ Rep (Record a)-  )-  => HKDable a-instance-  ( Generic (Record a)-  , HTable (GColumns (HKD a))-  , KnownAlgebra (GAlgebra (Rep a))-  , Eval (GGSerialize (GAlgebra (Rep a)) TSerialize TColumns (Eval (HKDRep a Expr)) (Eval (HKDRep a Result)))-  , GRecord (GMap (TColumn Result) (Rep a)) ~ Rep (Record a)-  )-  => HKDable a---type Top_ :: Constraint-class Top_-instance Top_---data Top :: Type -> Exp Constraint-type instance Eval (Top _) = Top_---type BuildableHKD :: Type -> Symbol -> Constraint-class GGBuildable (GAlgebra (Rep a)) name (HKDRep a) => BuildableHKD a name-instance GGBuildable (GAlgebra (Rep a)) name (HKDRep a) => BuildableHKD a name---type BuildHKD :: Type -> Symbol -> Type-type BuildHKD a name = GGBuild (GAlgebra (Rep a)) name (HKDRep a) (HKD a Expr)---buildHKD :: forall a name. BuildableHKD a name => BuildHKD a name-buildHKD =-  ggbuild @(GAlgebra (Rep a)) @name @(HKDRep a) @(HKD a Expr) HKD---type ConstructableHKD :: Type -> Constraint-class GGConstructable (GAlgebra (Rep a)) (HKDRep a) => ConstructableHKD a-instance GGConstructable (GAlgebra (Rep a)) (HKDRep a) => ConstructableHKD a---type ConstructHKD :: Type -> Type-type ConstructHKD a = forall r. GGConstruct (GAlgebra (Rep a)) (HKDRep a) r---constructHKD :: forall a. ConstructableHKD a => ConstructHKD a -> HKD a Expr-constructHKD f =-  ggconstruct @(GAlgebra (Rep a)) @(HKDRep a) @(HKD a Expr) HKD-    (f @(HKD a Expr))---type DeconstructHKD :: Type -> Type -> Type-type DeconstructHKD a r = GGDeconstruct (GAlgebra (Rep a)) (HKDRep a) (HKD a Expr) r---deconstructHKD :: forall a r. (ConstructableHKD a, Table Expr r)-  => DeconstructHKD a r-deconstructHKD = ggdeconstruct @(GAlgebra (Rep a)) @(HKDRep a) @(HKD a Expr) @r (\(HKD a) -> a)---deconstructAHKD :: forall a f r. (ConstructableHKD a, Apply f, Table Expr r)-  => DeconstructHKD a (f r)-deconstructAHKD = ggdeconstructA @(GAlgebra (Rep a)) @(HKDRep a) @(HKD a Expr) @f @r (\(HKD a) -> a)---type NameHKD :: Type -> Type-type NameHKD a = GGName (GAlgebra (Rep a)) (HKDRep a) (HKD a Name)---nameHKD :: forall a. ConstructableHKD a => NameHKD a-nameHKD = ggname @(GAlgebra (Rep a)) @(HKDRep a) @(HKD a Name) HKD---data HKDRep :: Type -> K.Context -> Exp (Type -> Type)-type instance Eval (HKDRep a context) =-  GRecord (GMap (TColumn context) (Rep a))
− src/Rel8/Table/List.hs
@@ -1,193 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Table.List-  ( ListTable(..)-  , ($*)-  , listTable-  , nameListTable-  , head-  , index-  , last-  , length-  )-where---- base-import Data.Functor.Identity (Identity (Identity))-import Data.Int (Int32)-import Data.Kind ( Type )-import Prelude hiding (head, last, length)---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Array ( sappend, sempty, slistOf )-import Rel8.Expr.List (lengthExpr, sheadExpr, sindexExpr, slastExpr)-import Rel8.Schema.Dict ( Dict( Dict ) )-import Rel8.Schema.HTable.List ( HListTable )-import Rel8.Schema.HTable.Vectorize-  ( hvectorize, hunvectorize-  , hnullify-  , happend, hempty-  , hproject, hcolumn-  , First (..)-  )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Name ( Name( Name ) )-import Rel8.Schema.Null ( Nullity( Null, NotNull ) )-import Rel8.Schema.Result ( vectorizer, unvectorizer )-import Rel8.Schema.Spec ( Spec(..) )-import Rel8.Table-  ( Table, Context, Columns, fromColumns, toColumns-  , FromExprs, fromResult, toResult-  , Transpose-  )-import Rel8.Table.Alternative-  ( AltTable, (<|>:)-  , AlternativeTable, emptyTable-  )-import Rel8.Table.Eq ( EqTable, eqTable )-import Rel8.Table.Null (NullTable)-import Rel8.Table.Ord ( OrdTable, ordTable )-import Rel8.Table.Projection-  ( Projectable, Projecting, Projection, project, apply-  )-import Rel8.Table.Serialize ( ToExprs )----- | A @ListTable@ value contains zero or more instances of @a@. You construct--- @ListTable@s with 'Rel8.many' or 'Rel8.listAgg'.-type ListTable :: K.Context -> Type -> Type-newtype ListTable context a =-  ListTable (HListTable (Columns a) (Context a))---instance Projectable (ListTable context) where-  project f (ListTable a) = ListTable (hproject (apply f) a)---instance (Table context a, context ~ context') =>-  Table context' (ListTable context a)- where-  type Columns (ListTable context a) = HListTable (Columns a)-  type Context (ListTable context a) = Context a-  type FromExprs (ListTable context a) = [FromExprs a]-  type Transpose to (ListTable context a) = ListTable to (Transpose to a)--  fromColumns = ListTable-  toColumns (ListTable a) = a-  fromResult = fmap (fromResult @_ @a) . hunvectorize unvectorizer-  toResult = hvectorize vectorizer . fmap (toResult @_ @a)---instance (EqTable a, context ~ Expr) => EqTable (ListTable context a) where-  eqTable =-    hvectorize-      (\Spec {nullity} (Identity Dict) -> case nullity of-        Null -> Dict-        NotNull -> Dict)-      (Identity (eqTable @a))---instance (OrdTable a, context ~ Expr) => OrdTable (ListTable context a) where-  ordTable =-    hvectorize-      (\Spec {nullity} (Identity Dict) -> case nullity of-        Null -> Dict-        NotNull -> Dict)-      (Identity (ordTable @a))---instance (ToExprs exprs a, context ~ Expr) =>-  ToExprs (ListTable context exprs) [a]---instance context ~ Expr => AltTable (ListTable context) where-  (<|>:) = (<>)---instance context ~ Expr => AlternativeTable (ListTable context) where-  emptyTable = mempty---instance (context ~ Expr, Table Expr a) => Semigroup (ListTable context a)- where-  ListTable as <> ListTable bs = ListTable $ happend (const sappend) as bs---instance (context ~ Expr, Table Expr a) =>-  Monoid (ListTable context a)- where-  mempty = ListTable $ hempty $ \Spec {info} -> sempty info----- | Project a single expression out of a 'ListTable'.-($*) :: Projecting a (Expr b)-  => Projection a (Expr b) -> ListTable Expr a -> Expr [b]-f $* ListTable a = hcolumn $ hproject (apply f) a-infixl 4 $*----- | Construct a @ListTable@ from a list of expressions.-listTable :: Table Expr a => [a] -> ListTable Expr a-listTable =-  ListTable .-  hvectorize (\Spec {info} -> slistOf info) .-  fmap toColumns----- | Construct a 'ListTable' in the 'Name' context. This can be useful if you--- have a 'ListTable' that you are storing in a table and need to construct a--- 'TableSchema'.-nameListTable-  :: Table Name a-  => a -- ^ The names of the columns of elements of the list.-  -> ListTable Name a-nameListTable =-  ListTable .-  hvectorize (\_ (Identity (Name a)) -> Name a) .-  pure .-  toColumns----- | Get the first element of a 'ListTable' (or 'Rel8.nullTable' if empty).-head :: Table Expr a => ListTable Expr a -> NullTable Expr a-head =-  fromColumns .-  hnullify (\Spec {info} -> sheadExpr info) .-  toColumns----- | @'index' i as@ extracts a single element from @as@, returning--- 'Rel8.nullTable' if @i@ is out of range. Note that although PostgreSQL--- array indexes are 1-based (by default), this function is always 0-based.-index :: Table Expr a => Expr Int32 -> ListTable Expr a -> NullTable Expr a-index i =-  fromColumns .-  hnullify (\Spec {info} -> sindexExpr info i) .-  toColumns----- | Get the last element of a 'ListTable' (or 'Rel8.nullTable' if empty).-last :: Table Expr a => ListTable Expr a -> NullTable Expr a-last =-  fromColumns .-  hnullify (\Spec {info} -> slastExpr info) .-  toColumns----- | Get the length of a 'ListTable'-length :: Table Expr a => ListTable Expr a -> Expr Int32-length =-  getFirst .-  hunvectorize (\_ -> First . lengthExpr) .-  toColumns
− src/Rel8/Table/Maybe.hs
@@ -1,252 +0,0 @@-{-# language DataKinds #-}-{-# language DeriveFunctor #-}-{-# language DerivingStrategies #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Table.Maybe-  ( MaybeTable(..)-  , maybeTable, nothingTable, justTable-  , isNothingTable, isJustTable-  , fromMaybeTable-  , ($?)-  , nameMaybeTable-  , makeMaybeTable-  , unsafeFromJustTable-  )-where---- base-import Data.Functor ( ($>) )-import Data.Functor.Identity ( Identity( Identity ) )-import Data.Kind ( Type )-import Data.Maybe ( fromMaybe, isJust )-import Prelude hiding ( null, undefined )---- comonad-import Control.Comonad ( extract )---- opaleye-import qualified Opaleye.Field as Opaleye-import qualified Opaleye.SqlTypes as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Bool ( boolExpr )-import Rel8.Expr.Null ( isNull, isNonNull, null, nullify )-import Rel8.Expr.Opaleye (fromColumn, fromPrimExpr)-import Rel8.Kind.Context ( Reifiable )-import Rel8.Schema.Dict ( Dict( Dict ) )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.HTable.Identity ( HIdentity(..) )-import Rel8.Schema.HTable.Label ( hlabel, hunlabel )-import Rel8.Schema.HTable.Maybe ( HMaybeTable(..) )-import Rel8.Schema.Name ( Name )-import Rel8.Schema.Null ( Nullity( Null, NotNull ), Sql, nullable )-import qualified Rel8.Schema.Null as N-import Rel8.Table-  ( Table, Columns, Context, fromColumns, toColumns-  , FromExprs, fromResult, toResult-  , Transpose-  )-import Rel8.Table.Alternative-  ( AltTable, (<|>:)-  , AlternativeTable, emptyTable-  )-import Rel8.Table.Bool ( bool )-import Rel8.Table.Eq ( EqTable, eqTable )-import Rel8.Table.Ord ( OrdTable, ordTable )-import Rel8.Table.Projection ( Projectable, project )-import Rel8.Table.Nullify (Nullify, guard, unsafeUnnullifyTable)-import Rel8.Table.Serialize ( ToExprs )-import Rel8.Table.Undefined ( undefined )-import Rel8.Type ( DBType )-import Rel8.Type.Tag ( MaybeTag( IsJust ) )---- semigroupoids-import Data.Functor.Apply ( Apply, (<.>) )-import Data.Functor.Bind ( Bind, (>>-) )----- | @MaybeTable t@ is the table @t@, but as the result of an outer join. If--- the outer join fails to match any rows, this is essentialy @Nothing@, and if--- the outer join does match rows, this is like @Just@. Unfortunately, SQL--- makes it impossible to distinguish whether or not an outer join matched any--- rows based generally on the row contents - if you were to join a row--- entirely of nulls, you can't distinguish if you matched an all null row, or--- if the match failed.  For this reason @MaybeTable@ contains an extra field ---- a "nullTag" - to track whether or not the outer join produced any rows.-type MaybeTable :: K.Context -> Type -> Type-data MaybeTable context a = MaybeTable-  { tag :: context (Maybe MaybeTag)-  , just :: Nullify context a-  }-  deriving stock Functor---instance Projectable (MaybeTable context) where-  project f (MaybeTable tag a) = MaybeTable tag (project f a)---instance context ~ Expr => Apply (MaybeTable context) where-  MaybeTable tag f <.> MaybeTable tag' a = MaybeTable (tag <> tag') (f <.> a)----- | Has the same behavior as the @Applicative@ instance for @Maybe@. See also:--- 'Rel8.traverseMaybeTable'.-instance context ~ Expr => Applicative (MaybeTable context) where-  (<*>) = (<.>)-  pure = justTable---instance context ~ Expr => Bind (MaybeTable context) where-  MaybeTable tag a >>- f = case f (extract a) of-    MaybeTable tag' b -> MaybeTable (tag <> tag') b----- | Has the same behavior as the @Monad@ instance for @Maybe@.-instance context ~ Expr => Monad (MaybeTable context) where-  (>>=) = (>>-)---instance context ~ Expr => AltTable (MaybeTable context) where-  ma <|>: mb = bool ma mb (isNothingTable ma)---instance context ~ Expr => AlternativeTable (MaybeTable context) where-  emptyTable = nothingTable---instance (context ~ Expr, Table Expr a, Semigroup a) =>-  Semigroup (MaybeTable context a)- where-  ma <> mb = maybeTable mb (\a -> maybeTable ma (justTable . (a <>)) mb) ma---instance (context ~ Expr, Table Expr a, Semigroup a) =>-  Monoid (MaybeTable context a)- where-  mempty = nothingTable---instance (Table context a, Reifiable context, context ~ context') =>-  Table context' (MaybeTable context a)- where-  type Columns (MaybeTable context a) = HMaybeTable (Columns a)-  type Context (MaybeTable context a) = Context a-  type FromExprs (MaybeTable context a) = Maybe (FromExprs a)-  type Transpose to (MaybeTable context a) = MaybeTable to (Transpose to a)--  toColumns MaybeTable {tag, just} = HMaybeTable-    { htag = hlabel $ HIdentity tag-    , hjust = hlabel $ guard tag isJust isNonNull $ toColumns just-    }--  fromColumns HMaybeTable {htag, hjust} = MaybeTable-    { tag = unHIdentity $ hunlabel htag-    , just = fromColumns $ hunlabel hjust-    }--  toResult ma = HMaybeTable-    { htag = hlabel (HIdentity (Identity (IsJust <$ ma)))-    , hjust = hlabel (toResult @_ @(Nullify context a) ma)-    }--  fromResult HMaybeTable {htag, hjust} = case hunlabel htag of-    HIdentity (Identity tag) -> tag $>-      fromMaybe err (fromResult @_ @(Nullify context a) (hunlabel hjust))-    where-      err = error "Maybe.fromColumns: mismatch between tag and data"---instance (EqTable a, context ~ Expr) => EqTable (MaybeTable context a) where-  eqTable = HMaybeTable-    { htag = hlabel (HIdentity Dict)-    , hjust = hlabel (eqTable @(Nullify context a))-    }---instance (OrdTable a, context ~ Expr) => OrdTable (MaybeTable context a) where-  ordTable = HMaybeTable-    { htag = hlabel (HIdentity Dict)-    , hjust = hlabel (ordTable @(Nullify context a))-    }---instance (ToExprs exprs a, context ~ Expr) =>-  ToExprs (MaybeTable context exprs) (Maybe a)----- | Check if a @MaybeTable@ is absent of any row. Like 'Data.Maybe.isNothing'.-isNothingTable :: MaybeTable Expr a -> Expr Bool-isNothingTable (MaybeTable tag _) = isNull tag----- | Check if a @MaybeTable@ contains a row. Like 'Data.Maybe.isJust'.-isJustTable :: MaybeTable Expr a -> Expr Bool-isJustTable (MaybeTable tag _) = isNonNull tag----- | Perform case analysis on a 'MaybeTable'. Like 'maybe'.-maybeTable :: Table Expr b => b -> (a -> b) -> MaybeTable Expr a -> b-maybeTable b f ma@(MaybeTable _ a) = bool (f (extract a)) b (isNothingTable ma)-{-# INLINABLE maybeTable #-}----- | The null table. Like 'Nothing'.-nothingTable :: Table Expr a => MaybeTable Expr a-nothingTable = MaybeTable null (pure undefined)----- | Lift any table into 'MaybeTable'. Like 'Just'. Note you can also use--- 'pure'.-justTable :: a -> MaybeTable Expr a-justTable = MaybeTable mempty . pure----- | 'Data.Maybe.fromMaybe' for 'MaybeTable's.-fromMaybeTable :: Table Expr a => a -> MaybeTable Expr a -> a-fromMaybeTable fallback = maybeTable fallback id---unsafeFromJustTable :: MaybeTable Expr a -> a-unsafeFromJustTable (MaybeTable _ just) = unsafeUnnullifyTable just----- | Project a single expression out of a 'MaybeTable'. You can think of this--- operator like the '$' operator, but it also has the ability to return--- @null@.-($?) :: forall a b. Sql DBType b-  => (a -> Expr b) -> MaybeTable Expr a -> Expr (N.Nullify b)-f $? ma@(MaybeTable _ a) = case nullable @b of-  Null -> boolExpr (f (extract a)) null (isNothingTable ma)-  NotNull -> boolExpr (nullify (f (extract a))) null (isNothingTable ma)-infixl 4 $?----- | Construct a 'MaybeTable' in the 'Name' context. This can be useful if you--- have a 'MaybeTable' that you are storing in a table and need to construct a--- 'TableSchema'.-nameMaybeTable-  :: Name (Maybe MaybeTag)-     -- ^ The name of the column to track whether a row is a 'justTable' or-     -- 'nothingTable'.-  -> a-     -- ^ Names of the columns in @a@.-  -> MaybeTable Name a-nameMaybeTable tag = MaybeTable tag . pure---makeMaybeTable :: Opaleye.FieldNullable Opaleye.SqlBool -> a -> MaybeTable Expr a-makeMaybeTable tag a = MaybeTable-  { tag = fromPrimExpr $ fromColumn tag-  , just = pure a-  }
− src/Rel8/Table/Name.hs
@@ -1,89 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language UndecidableInstances #-}-{-# language ViewPatterns #-}--module Rel8.Table.Name-  ( namesFromLabels-  , namesFromLabelsWith-  , namesFromLabelsWithA-  , showLabels-  , showNames-  )-where---- base-import Data.Foldable ( fold )-import Data.Functor.Const ( Const( Const ), getConst )-import Data.Functor.Identity (runIdentity)-import Data.List.NonEmpty ( NonEmpty, intersperse, nonEmpty )-import Data.Maybe ( fromMaybe )-import Prelude---- rel8-import Rel8.Schema.HTable (htabulateA, hfield, hspecs)-import Rel8.Schema.Name ( Name( Name ) )-import Rel8.Schema.Spec ( Spec(..) )-import Rel8.Table ( Table(..) )---- semigroupoids-import Data.Functor.Apply (Apply)----- | Construct a table in the 'Name' context containing the names of all--- columns. Nested column names will be combined with @/@.------ See also: 'namesFromLabelsWith'.-namesFromLabels :: Table Name a => a-namesFromLabels = namesFromLabelsWith go-  where-    go = fold . intersperse "/"----- | Construct a table in the 'Name' context containing the names of all--- columns. The supplied function can be used to transform column names.------ This function can be used to generically derive the columns for a--- 'TableSchema'. For example,------ @--- myTableSchema :: TableSchema (MyTable Name)--- myTableSchema = TableSchema---   { columns = namesFromLabelsWith last---   }--- @------ will construct a 'TableSchema' where each columns names exactly corresponds--- to the name of the Haskell field.-namesFromLabelsWith :: Table Name a-  => (NonEmpty String -> String) -> a-namesFromLabelsWith = runIdentity . namesFromLabelsWithA . (pure .)---namesFromLabelsWithA :: (Apply f, Table Name a)-  => (NonEmpty String -> f String) -> f a-namesFromLabelsWithA f = fmap fromColumns $ htabulateA $ \field ->-  case hfield hspecs field of-    Spec {labels} -> Name <$> f (renderLabels labels)---showLabels :: forall a. Table (Context a) a => a -> [NonEmpty String]-showLabels _ = getConst $-  htabulateA @(Columns a) $ \field -> case hfield hspecs field of-    Spec {labels} -> Const (pure (renderLabels labels))---showNames :: forall a. Table Name a => a -> NonEmpty String-showNames (toColumns -> names) = getConst $-  htabulateA @(Columns a) $ \field -> case hfield names field of-    Name name -> Const (pure name)---renderLabels :: [String] -> NonEmpty String-renderLabels labels = fromMaybe (pure "anon") (nonEmpty labels )
− src/Rel8/Table/NonEmpty.hs
@@ -1,189 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Table.NonEmpty-  ( NonEmptyTable(..)-  , ($+)-  , nonEmptyTable-  , nameNonEmptyTable-  , head1-  , index1-  , last1-  , length1-  )-where---- base-import Data.Functor.Identity (Identity (Identity), runIdentity)-import Data.Int (Int32)-import Data.Kind ( Type )-import Data.List.NonEmpty ( NonEmpty )-import Prelude hiding ( id )---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Array ( sappend1, snonEmptyOf )-import Rel8.Expr.NonEmpty (length1Expr, shead1Expr, sindex1Expr, slast1Expr)-import Rel8.Schema.Dict ( Dict( Dict ) )-import Rel8.Schema.HTable.NonEmpty ( HNonEmptyTable )-import Rel8.Schema.HTable.Vectorize-  ( hvectorize, hunvectorize-  , hnullify-  , happend-  , hproject, hcolumn-  , First (..)-  )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Name ( Name( Name ) )-import Rel8.Schema.Null ( Nullity( Null, NotNull ) )-import Rel8.Schema.Result ( vectorizer, unvectorizer )-import Rel8.Schema.Spec ( Spec(..) )-import Rel8.Table-  ( Table, Context, Columns, fromColumns, toColumns-  , FromExprs, fromResult, toResult-  , Transpose-  )-import Rel8.Table.Alternative ( AltTable, (<|>:) )-import Rel8.Table.Eq ( EqTable, eqTable )-import Rel8.Table.Null (NullTable)-import Rel8.Table.Ord ( OrdTable, ordTable )-import Rel8.Table.Projection-  ( Projectable, Projecting, Projection, project, apply-  )-import Rel8.Table.Serialize ( ToExprs )----- | A @NonEmptyTable@ value contains one or more instances of @a@. You--- construct @NonEmptyTable@s with 'Rel8.some' or 'nonEmptyAgg'.-type NonEmptyTable :: K.Context -> Type -> Type-newtype NonEmptyTable context a =-  NonEmptyTable (HNonEmptyTable (Columns a) (Context a))---instance Projectable (NonEmptyTable context) where-  project f (NonEmptyTable a) = NonEmptyTable (hproject (apply f) a)---instance (Table context a, context ~ context') =>-  Table context' (NonEmptyTable context a)- where-  type Columns (NonEmptyTable context a) = HNonEmptyTable (Columns a)-  type Context (NonEmptyTable context a) = Context a-  type FromExprs (NonEmptyTable context a) = NonEmpty (FromExprs a)-  type Transpose to (NonEmptyTable context a) =-    NonEmptyTable to (Transpose to a)--  fromColumns = NonEmptyTable-  toColumns (NonEmptyTable a) = a-  fromResult = fmap (fromResult @_ @a) . hunvectorize unvectorizer-  toResult = hvectorize vectorizer . fmap (toResult @_ @a)---instance (EqTable a, context ~ Expr) =>-  EqTable (NonEmptyTable context a)- where-  eqTable =-    hvectorize-      (\Spec {nullity} (Identity Dict) -> case nullity of-        Null -> Dict-        NotNull -> Dict)-      (Identity (eqTable @a))---instance (OrdTable a, context ~ Expr) =>-  OrdTable (NonEmptyTable context a)- where-  ordTable =-    hvectorize-      (\Spec {nullity} (Identity Dict) -> case nullity of-        Null -> Dict-        NotNull -> Dict)-      (Identity (ordTable @a))---instance (ToExprs exprs a, context ~ Expr) =>-  ToExprs (NonEmptyTable context exprs) (NonEmpty a)---instance context ~ Expr => AltTable (NonEmptyTable context) where-  (<|>:) = (<>)---instance (Table Expr a, context ~ Expr) => Semigroup (NonEmptyTable context a)- where-  NonEmptyTable as <> NonEmptyTable bs = NonEmptyTable $-    happend (const sappend1) as bs----- | Project a single expression out of a 'NonEmptyTable'.-($+) :: Projecting a (Expr b)-  => Projection a (Expr b) -> NonEmptyTable Expr a -> Expr (NonEmpty b)-f $+ NonEmptyTable a = hcolumn $ hproject (apply f) a-infixl 4 $+----- | Construct a @NonEmptyTable@ from a non-empty list of expressions.-nonEmptyTable :: Table Expr a => NonEmpty a -> NonEmptyTable Expr a-nonEmptyTable =-  NonEmptyTable .-  hvectorize (\Spec {info} -> snonEmptyOf info) .-  fmap toColumns----- | Construct a 'NonEmptyTable' in the 'Name' context. This can be useful if--- you have a 'NonEmptyTable' that you are storing in a table and need to--- construct a 'TableSchema'.-nameNonEmptyTable-  :: Table Name a-  => a -- ^ The names of the columns of elements of the list.-  -> NonEmptyTable Name a-nameNonEmptyTable =-  NonEmptyTable .-  hvectorize (\_ (Identity (Name a)) -> Name a) .-  pure .-  toColumns----- | Get the first element of a 'NonEmptyTable'.-head1 :: Table Expr a => NonEmptyTable Expr a -> a-head1 =-  fromColumns .-  runIdentity .-  hunvectorize (\Spec {info} -> Identity . shead1Expr info) .-  toColumns----- | @'index1' i as@ extracts a single element from @as@, returning--- 'Rel8.nullTable' if @i@ is out of range. Note that although PostgreSQL--- array indexes are 1-based (by default), this function is always 0-based.-index1 :: Table Expr a => Expr Int32 -> NonEmptyTable Expr a -> NullTable Expr a-index1 i =-  fromColumns .-  hnullify (\Spec {info} -> sindex1Expr info i) .-  toColumns----- | Get the last element of a 'NonEmptyTable'.-last1 :: Table Expr a => NonEmptyTable Expr a -> a-last1 =-  fromColumns .-  runIdentity .-  hunvectorize (\Spec {info} -> Identity . slast1Expr info) .-  toColumns----- | Get the length of a 'NonEmptyTable'-length1 :: Table Expr a => NonEmptyTable Expr a -> Expr Int32-length1 =-  getFirst .-  hunvectorize (\_ -> First . length1Expr) .-  toColumns
− src/Rel8/Table/Null.hs
@@ -1,149 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Table.Null-  ( NullTable(..)-  , nullableTable, nullTable, nullifyTable, unsafeUnnullifyTable-  , isNullTable, isNonNullTable-  , nameNullTable-  , toMaybeTable, toNullTable-  )-where---- base-import Data.Kind ( Type )-import Prelude hiding ( null, undefined )---- comonad-import Control.Comonad ( extract )---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Bool ( not_ )-import Rel8.Kind.Context ( Reifiable )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Name ( Name )-import Rel8.Table-  ( Table, Columns, Context, fromColumns, toColumns-  , FromExprs, fromResult, toResult-  , Transpose-  )-import Rel8.Table.Alternative-  ( AltTable, (<|>:)-  , AlternativeTable, emptyTable-  )-import Rel8.Table.Bool ( bool )-import Rel8.Table.Eq ( EqTable, eqTable )-import Rel8.Table.Maybe ( MaybeTable, justTable, maybeTable, nothingTable )-import Rel8.Table.Nullify ( Nullify, isNull )-import Rel8.Table.Ord ( OrdTable, ordTable )-import Rel8.Table.Projection ( Projectable, project )-import Rel8.Table.Serialize ( ToExprs )-import Rel8.Table.Undefined ( undefined )----- | @NullTable t@ is the table @t@, but where all the columns in @t@ have the--- possibility of being 'Rel8.null'. This is very similar to--- 'Rel8.MaybeTable', except that it does not use an extra tag field, so it--- cannot distinguish between @Nothing@ and @Just Nothing@ if nested. In other--- words, if all of the columns of the @t@ passed to @NullTable@ are already--- nullable, then @NullTable@ has no effect.-type NullTable :: K.Context -> Type -> Type-newtype NullTable context a = NullTable (Nullify context a)---instance Projectable (NullTable context) where-  project f (NullTable a) = NullTable (project f a)---instance context ~ Expr => AltTable (NullTable context) where-  ma <|>: mb = bool ma mb (isNullTable ma)---instance context ~ Expr => AlternativeTable (NullTable context) where-  emptyTable = nullTable---instance (Table context a, Reifiable context, context ~ context') =>-  Table context' (NullTable context a)- where-  type Columns (NullTable context a) = Columns (Nullify context a)-  type Context (NullTable context a) = Context (Nullify context a)-  type FromExprs (NullTable context a) = FromExprs (Nullify context a)-  type Transpose to (NullTable context a) = NullTable to (Transpose to a)--  toColumns (NullTable a) = toColumns a-  fromColumns = NullTable . fromColumns--  toResult = toResult @_ @(Nullify context a)-  fromResult = fromResult @_ @(Nullify context a)---instance (EqTable a, context ~ Expr) => EqTable (NullTable context a) where-  eqTable = eqTable @(Nullify context a)---instance (OrdTable a, context ~ Expr) => OrdTable (NullTable context a) where-  ordTable = ordTable @(Nullify context a)---instance (ToExprs exprs a, context ~ Expr) =>-  ToExprs (NullTable context exprs) (Maybe a)----- | Check if any of the non-nullable fields of @a@ are 'Rel8.null' under the--- 'NullTable'. Returns 'Rel8.false' if @a@ has no non-nullable fields.-isNullTable :: Table Expr a => NullTable Expr a -> Expr Bool-isNullTable (NullTable a) = isNull a----- | The inverse of 'isNullTable'.-isNonNullTable :: Table Expr a => NullTable Expr a -> Expr Bool-isNonNullTable = not_ . isNullTable----- | Like 'Rel8.nullable'.-nullableTable :: (Table Expr a, Table Expr b)-  => b -> (a -> b) -> NullTable Expr a -> b-nullableTable b f ma@(NullTable a) = bool (f (extract a)) b (isNullTable ma)----- | The null table. Like 'Rel8.null'.-nullTable :: Table Expr a => NullTable Expr a-nullTable = NullTable (pure undefined)----- | Lift any table into 'NullTable'. Like 'Rel8.nullify'.-nullifyTable :: a -> NullTable Expr a-nullifyTable = NullTable . pure----- | Assume that a 'NullTable' is non-null. Like 'Rel8.unsafeUnnullify'.-unsafeUnnullifyTable :: NullTable Expr a -> a-unsafeUnnullifyTable (NullTable a) = extract a----- | Construct a 'NullTable' in the 'Name' context. This can be useful if you--- have a 'NullTable' that you are storing in a table and need to construct a--- 'TableSchema'.-nameNullTable :: a -> NullTable Name a-nameNullTable = NullTable . pure----- | Convert a 'NullTable' to a 'MaybeTable'.-toMaybeTable :: Table Expr a => NullTable Expr a -> MaybeTable Expr a-toMaybeTable = nullableTable nothingTable justTable----- | Convert a 'MaybeTable' to a 'NullTable'. Note that if the underlying @a@--- has no non-nullable fields, this is a lossy conversion.-toNullTable :: Table Expr a => MaybeTable Expr a -> NullTable Expr a-toNullTable = maybeTable nullTable nullifyTable
− src/Rel8/Table/Nullify.hs
@@ -1,222 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language LambdaCase #-}-{-# language MultiParamTypeClasses #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Table.Nullify-  ( Nullify-  , aggregateNullify-  , guard-  , isNull-  , unsafeUnnullifyTable-  )-where---- base-import Control.Applicative ( liftA2 )-import Data.Functor.Const ( Const( Const ), getConst )-import Data.Functor.Identity ( runIdentity )-import Data.Kind ( Type )-import Prelude---- comonad-import Control.Comonad ( Comonad, duplicate, extract, ComonadApply, (<@>) )---- profunctors-import Data.Profunctor (dimap)---- rel8-import Rel8.Aggregate (Aggregator')-import Rel8.Expr ( Expr )-import Rel8.Expr.Bool ( (||.), false )-import qualified Rel8.Expr.Null as Expr-import Rel8.Kind.Context ( Reifiable, contextSing )-import Rel8.Schema.Context.Nullify-  ( Nullifiability( NExpr )-  , NonNullifiability-  , Nullifiable, nullifiability-  , nullifiableOrNot, absurd-  , guarder-  , nullifier-  , unnullifier-  )-import Rel8.Schema.Dict ( Dict( Dict ) )-import Rel8.Schema.HTable ( HTable )-import Rel8.Schema.HTable.Nullify-  ( HNullify, hnulls, hnullify, hunnullify-  , hguard-  , hproject-  )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Null ( Nullity( NotNull, Null ) )-import qualified Rel8.Schema.Result as R-import Rel8.Table-  ( Table, Columns, Context, toColumns, fromColumns-  , FromExprs, fromResult, toResult-  , Transpose-  )-import Rel8.Schema.Spec ( Spec( Spec, nullity ) )-import Rel8.Table.Eq ( EqTable, eqTable )-import Rel8.Table.Ord ( OrdTable, ordTable )-import Rel8.Table.Projection ( Projectable, apply, project )---- semigroupoids-import Data.Functor.Apply ( Apply, (<.>), liftF2 )-import Data.Functor.Bind ( Bind, (>>-) )-import Data.Functor.Extend ( Extend, duplicated )---type Nullify :: K.Context -> Type -> Type-data Nullify context a-  = Table (Nullifiability context) a-  | Fields (NonNullifiability context) (HNullify (Columns a) (Context a))---instance Projectable (Nullify context) where-  project f = \case-    Table nullifiable a -> Table nullifiable (fromColumns (apply f (toColumns a)))-    Fields nonNullifiable a -> Fields nonNullifiable (hproject (apply f) a)---instance Nullifiable context => Functor (Nullify context) where-  fmap f = \case-    Table nullifiable a -> Table nullifiable (f a)-    Fields notNullifiable _ -> absurd nullifiability notNullifiable---instance Nullifiable context => Foldable (Nullify context) where-  foldMap f = \case-    Table _ a -> f a-    Fields notNullifiable _ -> absurd nullifiability notNullifiable---instance Nullifiable context => Traversable (Nullify context) where-  traverse f = \case-    Table nullifiable a -> Table nullifiable <$> f a-    Fields notNullifiable _ -> absurd nullifiability notNullifiable---instance Nullifiable context => Apply (Nullify context) where-  liftF2 f = \case-    Table nullifiable a -> \case-      Table _ b -> Table nullifiable (f a b)-      Fields notNullifiable _ -> absurd nullifiable notNullifiable-    Fields notNullifiable _ -> absurd nullifiability notNullifiable---instance Nullifiable context => Applicative (Nullify context) where-  pure = Table nullifiability-  liftA2 = liftF2---instance Nullifiable context => Bind (Nullify context) where-  Table _ a >>- f = f a-  Fields notNullifiable _ >>- _ = absurd nullifiability notNullifiable---instance Nullifiable context => Monad (Nullify context) where-  (>>=) = (>>-)---instance Nullifiable context => Extend (Nullify context) where-  duplicated = \case-    Table nullifiable a -> Table nullifiable (Table nullifiable a)-    Fields notNullifiable _ -> absurd nullifiability notNullifiable---instance Nullifiable context => Comonad (Nullify context) where-  extract = \case-    Table _ a -> a-    Fields notNullifiable _ -> absurd nullifiability notNullifiable-  duplicate = duplicated---instance Nullifiable context => ComonadApply (Nullify context) where-  (<@>) = (<.>)---instance (Table context a, Reifiable context, context ~ context') =>-  Table context' (Nullify context a)- where-  type Columns (Nullify context a) = HNullify (Columns a)-  type Context (Nullify context a) = Context a-  type FromExprs (Nullify context a) = Maybe (FromExprs a)-  type Transpose to (Nullify context a) = Nullify to (Transpose to a)--  fromColumns = case nullifiableOrNot contextSing of-    Left notNullifiable -> Fields notNullifiable-    Right nullifiable ->-      Table nullifiable .-      fromColumns .-      runIdentity .-      hunnullify (\spec -> pure . unnullifier nullifiable spec)--  toColumns = \case-    Table nullifiable a -> hnullify (nullifier nullifiable) (toColumns a)-    Fields _ a -> a--  fromResult = fmap (fromResult @_ @a) . hunnullify R.unnullifier--  toResult =-    maybe (hnulls (const R.null)) (hnullify R.nullifier) .-    fmap (toResult @_ @a)---instance (EqTable a, context ~ Expr) => EqTable (Nullify context a) where-  eqTable = hnullify (\_ Dict -> Dict) (eqTable @a)---instance (OrdTable a, context ~ Expr) => OrdTable (Nullify context a) where-  ordTable = hnullify (\_ Dict -> Dict) (ordTable @a)---aggregateNullify :: ()-  => Aggregator' fold i a-  -> Aggregator' fold (Nullify Expr i) (Nullify Expr a)-aggregateNullify = dimap from to-  where-    from = unsafeUnnullifyTable-    to = Table NExpr---guard :: (Reifiable context, HTable t)-  => context tag-  -> (tag -> Bool)-  -> (Expr tag -> Expr Bool)-  -> HNullify t context-  -> HNullify t context-guard tag isNonNull isNonNullExpr =-  hguard (guarder contextSing tag isNonNull isNonNullExpr)---isNull :: forall a. Table Expr a => Nullify Expr a -> Expr Bool-isNull =-  maybe false getAny .-  getConst .-  hunnullify (\Spec {nullity} a -> Const $ case nullity of-    NotNull -> Just $ Any $ Expr.isNull a-    Null -> Nothing) .-  toColumns---unsafeUnnullifyTable :: Nullify Expr a -> a-unsafeUnnullifyTable = \case-  Table _ a -> a-  Fields notNullifiable _ -> absurd NExpr notNullifiable---newtype Any = Any-  { getAny :: Expr Bool-  }---instance Semigroup Any where-  Any a <> Any b = Any (a ||. b)
− src/Rel8/Table/Opaleye.hs
@@ -1,168 +0,0 @@-{-# language BlockArguments #-}-{-# language DataKinds #-}-{-# language DisambiguateRecordFields #-}-{-# language FlexibleContexts #-}-{-# language NamedFieldPuns #-}-{-# language RankNTypes #-}-{-# language TypeFamilies #-}-{-# language ViewPatterns #-}--{-# options_ghc -Wno-deprecations #-}--module Rel8.Table.Opaleye-  ( attributes-  , binaryspec-  , distinctspec-  , exprs-  , exprsWithNames-  , ifPP-  , relExprPP-  , table-  , tableFields-  , unpackspec-  , valuesspec-  , view-  , castTable-  , fromOrder-  )-where---- base-import Data.Foldable (traverse_)-import Data.Functor.Const ( Const( Const ), getConst )-import Data.List.NonEmpty ( NonEmpty )-import Prelude---- opaleye-import qualified Opaleye.Adaptors as Opaleye-import qualified Opaleye.Field as Opaleye ( Field_ )-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye-import qualified Opaleye.Internal.Operators as Opaleye-import qualified Opaleye.Internal.Order as Opaleye-import qualified Opaleye.Internal.PackMap as Opaleye-import qualified Opaleye.Internal.Unpackspec as Opaleye-import qualified Opaleye.Internal.Values as Opaleye-import qualified Opaleye.Table as Opaleye---- profunctors-import Data.Profunctor ( dimap, lmap )---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Opaleye-  ( fromPrimExpr, toPrimExpr-  , scastExpr, traverseFieldP-  )-import Rel8.Schema.HTable-  ( htabulateA, hfield, hspecs, htabulate-  , htraverseP, htraversePWithField-  )-import Rel8.Schema.Name ( Name( Name ), Selects, ppColumn )-import Rel8.Schema.QualifiedName (QualifiedName (QualifiedName))-import Rel8.Schema.Spec ( Spec(..) )-import Rel8.Schema.Table ( TableSchema(..), ppTable )-import Rel8.Table ( Table, fromColumns, toColumns )-import Rel8.Type.Information ( typeName )-import Rel8.Type.Name (showTypeName)---- semigroupoids-import Data.Functor.Apply ( WrappedApplicative(..) )-import Data.Profunctor.Product ( ProductProfunctor )---attributes :: Selects names exprs => TableSchema names -> exprs-attributes schema@TableSchema {columns} = fromColumns $ htabulate $ \field ->-  case hfield (toColumns columns) field of-    Name column -> fromPrimExpr $ Opaleye.ConstExpr $-      Opaleye.OtherLit $-        show (ppTable schema) <> "." <> show (ppColumn column)---fromOpaleyespec :: (ProductProfunctor p, Table Expr a)-  => p (Opaleye.Field_ n x) (Opaleye.Field_ n x)-  -> p a a-fromOpaleyespec x =-  dimap toColumns fromColumns (htraverseP (traverseFieldP x))---binaryspec :: Table Expr a => Opaleye.Binaryspec a a-binaryspec = fromOpaleyespec Opaleye.binaryspecField---distinctspec :: Table Expr a => Opaleye.Distinctspec a a-distinctspec = fromOpaleyespec Opaleye.distinctspecField---exprs :: Table Expr a => a -> NonEmpty Opaleye.PrimExpr-exprs (toColumns -> as) = getConst $ htabulateA $ \field ->-  case hfield as field of-    expr -> Const (pure (toPrimExpr expr))---exprsWithNames :: Selects names exprs-  => names -> exprs -> NonEmpty (String, Opaleye.PrimExpr)-exprsWithNames names as = getConst $ htabulateA $ \field ->-  case (hfield (toColumns names) field, hfield (toColumns as) field) of-    (Name name, expr) -> Const (pure (name, toPrimExpr expr))---ifPP :: Table Expr a => Opaleye.IfPP a a-ifPP = fromOpaleyespec Opaleye.ifPPField---relExprPP :: Table Expr a => Opaleye.RelExprPP a a-relExprPP = fromOpaleyespec Opaleye.relExprColumn---table :: Selects names exprs => TableSchema names -> Opaleye.Table exprs exprs-table (TableSchema (QualifiedName name schema) columns) =-  case schema of-    Nothing -> Opaleye.table name (tableFields columns)-    Just schemaName -> Opaleye.tableWithSchema schemaName name (tableFields columns)---tableFields :: Selects names exprs-  => names -> Opaleye.TableFields exprs exprs-tableFields (toColumns -> names) = dimap toColumns fromColumns $-  unwrapApplicative $ htabulateA $ \field -> WrapApplicative $-    case hfield names field of-      name -> lmap (`hfield` field) (go name)-  where-    go :: Name a -> Opaleye.TableFields (Expr a) (Expr a)-    go (Name name) =-      traverseFieldP $-        Opaleye.requiredTableField name---unpackspec :: Table Expr a => Opaleye.Unpackspec a a-unpackspec = fromOpaleyespec Opaleye.unpackspecField-{-# INLINABLE unpackspec #-}---valuesspec :: Table Expr a => Opaleye.Valuesspec a a-valuesspec = dimap toColumns fromColumns $-  htraversePWithField (traverseFieldP . Opaleye.valuesspecFieldType . typeName)-  where-    typeName = showTypeName . Rel8.Type.Information.typeName . info . hfield hspecs---view :: Selects names exprs => names -> exprs-view columns = fromColumns $ htabulate $ \field ->-  case hfield (toColumns columns) field of-    Name column -> fromPrimExpr $ Opaleye.BaseTableAttrExpr column----- | Transform a table by adding 'CAST' to all columns. This is most useful for--- finalising a SELECT or RETURNING statement, guaranteed that the output--- matches what is encoded in each columns TypeInformation.-castTable :: Table Expr a => a -> a-castTable (toColumns -> as) = fromColumns $ htabulate \field ->-  case hfield hspecs field of-    Spec {info} -> case hfield as field of-        expr -> scastExpr info expr---fromOrder :: Opaleye.Order a -> Opaleye.Unpackspec a a-fromOrder (Opaleye.Order o) =-  Opaleye.Unpackspec $ Opaleye.PackMap $ \f a ->-    a <$ traverse_ (f . snd) (o a)
− src/Rel8/Table/Ord.hs
@@ -1,154 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language DataKinds #-}-{-# language DefaultSignatures #-}-{-# language DisambiguateRecordFields #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}-{-# language ViewPatterns #-}--module Rel8.Table.Ord-  ( OrdTable( ordTable ), (<:), (<=:), (>:), (>=:), least, greatest-  )-where---- base-import Data.Functor.Const ( Const( Const ), getConst )-import Data.Kind ( Constraint, Type )-import GHC.Generics ( Rep )-import Prelude hiding ( seq )---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Bool ( (||.), (&&.), false, true )-import Rel8.Expr.Eq ( (==.) )-import Rel8.Expr.Ord ( (<.), (>.) )-import Rel8.FCF ( Eval, Exp )-import Rel8.Generic.Record ( Record )-import Rel8.Generic.Table.Record ( GTable, GColumns, gtable )-import Rel8.Schema.Dict ( Dict( Dict ) )-import Rel8.Schema.HTable ( htabulateA, hfield )-import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )-import Rel8.Schema.Null (Sql)-import Rel8.Table ( Columns, toColumns, TColumns )-import Rel8.Table.Bool ( bool )-import Rel8.Table.Eq ( EqTable )-import Rel8.Type.Ord ( DBOrd )----- | The class of 'Table's that can be ordered. Ordering on tables is defined--- by their lexicographic ordering of all columns, so this class means "all--- columns in a 'Table' have an instance of 'DBOrd'".-type OrdTable :: Type -> Constraint-class EqTable a => OrdTable a where-  ordTable :: Columns a (Dict (Sql DBOrd))--  default ordTable ::-    ( GTable TOrdTable TColumns (Rep (Record a))-    , Columns a ~ GColumns TColumns (Rep (Record a))-    )-    => Columns a (Dict (Sql DBOrd))-  ordTable = gtable @TOrdTable @TColumns @(Rep (Record a)) table-    where-      table (_ :: proxy x) = ordTable @x---data TOrdTable :: Type -> Exp Constraint-type instance Eval (TOrdTable a) = OrdTable a---instance Sql DBOrd a => OrdTable (Expr a) where-  ordTable = HIdentity Dict---instance (OrdTable a, OrdTable b) => OrdTable (a, b)---instance (OrdTable a, OrdTable b, OrdTable c) => OrdTable (a, b, c)---instance (OrdTable a, OrdTable b, OrdTable c, OrdTable d) => OrdTable (a, b, c, d)---instance (OrdTable a, OrdTable b, OrdTable c, OrdTable d, OrdTable e) =>-  OrdTable (a, b, c, d, e)---instance-  ( OrdTable a, OrdTable b, OrdTable c, OrdTable d, OrdTable e, OrdTable f-  )-  => OrdTable (a, b, c, d, e, f)---instance-  ( OrdTable a, OrdTable b, OrdTable c, OrdTable d, OrdTable e, OrdTable f-  , OrdTable g-  )-  => OrdTable (a, b, c, d, e, f, g)----- | Test if one 'Table' sorts before another. Corresponds to comparing all--- columns with '<'.-(<:) :: forall a. OrdTable a => a -> a -> Expr Bool-(toColumns -> as) <: (toColumns -> bs) =-  foldr @[] go false $ getConst $ htabulateA $ \field ->-    case (hfield as field, hfield bs field) of-      (a, b) -> case hfield (ordTable @a) field of-        Dict -> Const [(a <. b, a ==. b)]-  where-    go (lt, eq) a = lt ||. (eq &&. a)-infix 4 <:----- | Test if one 'Table' sorts before, or is equal to, another. Corresponds to--- comparing all columns with '<='.-(<=:) :: forall a. OrdTable a => a -> a -> Expr Bool-(toColumns -> as) <=: (toColumns -> bs) =-  foldr @[] go true $ getConst $ htabulateA $ \field ->-    case (hfield as field, hfield bs field) of-      (a, b) -> case hfield (ordTable @a) field of-        Dict -> Const [(a <. b, a ==. b)]-  where-    go (lt, eq) a = lt ||. (eq &&. a)-infix 4 <=:----- | Test if one 'Table' sorts after another. Corresponds to comparing all--- columns with '>'.-(>:) :: forall a. OrdTable a => a -> a -> Expr Bool-(toColumns -> as) >: (toColumns -> bs) =-  foldr @[] go false $ getConst $ htabulateA $ \field ->-    case (hfield as field, hfield bs field) of-      (a, b) -> case hfield (ordTable @a) field of-        Dict -> Const [(a >. b, a ==. b)]-  where-    go (gt, eq) a = gt ||. (eq &&. a)-infix 4 >:----- | Test if one 'Table' sorts after another. Corresponds to comparing all--- columns with '>='.-(>=:) :: forall a. OrdTable a => a -> a -> Expr Bool-(toColumns -> as) >=: (toColumns -> bs) =-  foldr @[] go true $ getConst $ htabulateA $ \field ->-    case (hfield as field, hfield bs field) of-      (a, b) -> case hfield (ordTable @a) field of-        Dict -> Const [(a >. b, a ==. b)]-  where-    go (gt, eq) a = gt ||. (eq &&. a)-infix 4 >=:----- | Given two 'Table's, return the table that sorts before the other.-least :: OrdTable a => a -> a -> a-least a b = bool b a (a <: b)----- | Given two 'Table's, return the table that sorts after the other.-greatest :: OrdTable a => a -> a -> a-greatest a b = bool b a (a >: b)
− src/Rel8/Table/Order.hs
@@ -1,50 +0,0 @@-{-# language DataKinds #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}--module Rel8.Table.Order-  ( ascTable-  , descTable-  )-where---- base-import Data.Functor.Const ( Const( Const ), getConst )-import Data.Functor.Contravariant ( (>$<), contramap )-import Prelude---- rel8-import Rel8.Expr.Order ( asc, desc, nullsFirst, nullsLast )-import Rel8.Order ( Order )-import Rel8.Schema.Dict ( Dict( Dict ) )-import Rel8.Schema.HTable (htabulateA, hfield, hspecs)-import Rel8.Schema.Null ( Nullity( Null, NotNull ) )-import Rel8.Schema.Spec ( Spec( Spec, nullity ) )-import Rel8.Table ( Columns, toColumns )-import Rel8.Table.Ord ( OrdTable, ordTable )----- | Construct an 'Order' for a 'Table' by sorting all columns into ascending--- orders (any nullable columns will be sorted with @NULLS FIRST@).-ascTable :: forall a. OrdTable a => Order a-ascTable = contramap toColumns $ getConst $-  htabulateA @(Columns a) $ \field -> case hfield hspecs field of-    Spec {nullity} -> case hfield (ordTable @a) field of-      Dict -> Const $ (`hfield` field) >$<-        case nullity of-          Null -> nullsFirst asc-          NotNull -> asc----- | Construct an 'Order' for a 'Table' by sorting all columns into descending--- orders (any nullable columns will be sorted with @NULLS LAST@).-descTable :: forall a. OrdTable a => Order a-descTable = contramap toColumns $ getConst $-  htabulateA @(Columns a) $ \field -> case hfield hspecs field of-    Spec {nullity} -> case hfield (ordTable @a) field of-      Dict -> Const $ (`hfield` field) >$<-        case nullity of-          Null -> nullsLast desc-          NotNull -> desc
− src/Rel8/Table/Projection.hs
@@ -1,73 +0,0 @@-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MonoLocalBinds #-}-{-# language MultiParamTypeClasses #-}-{-# language StandaloneKindSignatures #-}-{-# language UndecidableInstances #-}--module Rel8.Table.Projection-  ( Projection-  , Projectable( project )-  , Biprojectable( biproject )-  , Projecting-  , apply-  )-where---- base-import Data.Kind ( Constraint, Type )-import Prelude---- rel8-import Rel8.Schema.Field ( Field( Field ), fields )-import Rel8.Schema.HTable ( hfield, htabulate )-import Rel8.Table ( Columns, Context, Transpose, toColumns )-import Rel8.Table.Transpose ( Transposes )----- | The constraint @'Projecting' a b@ ensures that @'Projection' a b@ is a--- usable 'Projection'.-type Projecting :: Type -> Type -> Constraint-class-  ( Transposes (Context a) (Field a) a (Transpose (Field a) a)-  , Transposes (Context a) (Field a) b (Transpose (Field a) b)-  )-  => Projecting a b-instance-  ( Transposes (Context a) (Field a) a (Transpose (Field a) a)-  , Transposes (Context a) (Field a) b (Transpose (Field a) b)-  )-  => Projecting a b----- | A @'Projection' a b@s is a special type of function @a -> b@ whereby the--- resulting @b@ is guaranteed to be composed only from columns contained in--- @a@.-type Projection :: Type -> Type -> Type-type Projection a b = Transpose (Field a) a -> Transpose (Field a) b----- | @'Projectable' f@ means that @f@ is a kind of functor on 'Rel8.Table's--- that allows the mapping of a 'Projection' over its underlying columns.-type Projectable :: (Type -> Type) -> Constraint-class Projectable f where-  -- | Map a 'Projection' over @f@.-  project :: Projecting a b-    => Projection a b -> f a -> f b----- | @'Biprojectable' p@ means that @p@ is a kind of bifunctor on--- 'Rel8.Table's that allows the mapping of a pair of 'Projection's  over its--- underlying columns.-type Biprojectable :: (Type -> Type -> Type) -> Constraint-class Biprojectable p where-  -- | Map a pair of 'Projection's over @p@.-  biproject :: (Projecting a b, Projecting c d)-    => Projection a b -> Projection c d -> p a c -> p b d---apply :: Projecting a b-  => Projection a b -> Columns a context -> Columns b context-apply f a = case toColumns (f fields) of-  bs -> htabulate $ \field -> case hfield bs field of-    Field field' -> hfield a field'
− src/Rel8/Table/Rel8able.hs
@@ -1,96 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--{-# options_ghc -fno-warn-orphans #-}--module Rel8.Table.Rel8able-  (-  )-where---- base-import Prelude ()---- base-compat-import Data.Type.Equality.Compat---- rel8-import Rel8.Expr ( Expr )-import qualified Rel8.Kind.Algebra as K-import Rel8.Kind.Context ( Reifiable, contextSing )-import Rel8.Generic.Rel8able-  ( Rel8able, Algebra-  , GColumns, gfromColumns, gtoColumns-  , GFromExprs, gfromResult, gtoResult-  )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.HTable ( HConstrainTable, hdicts )-import Rel8.Schema.Null ( Sql )-import Rel8.Schema.Result ( Result )-import Rel8.Table-  ( Table, Columns, Context, fromColumns, toColumns-  , FromExprs, fromResult, toResult-  , Transpose-  )-import Rel8.Table.ADT ( ADT )-import Rel8.Table.Eq ( EqTable, eqTable )-import Rel8.Table.Ord ( OrdTable, ordTable )-import Rel8.Table.Serialize ( ToExprs )-import Rel8.Type.Eq ( DBEq )-import Rel8.Type.Ord ( DBOrd )---instance (Rel8able t, Reifiable context, context ~ context') =>-  Table context' (t context)- where-  type Columns (t context) = GColumns t-  type Context (t context) = context-  type FromExprs (t context) = GFromExprs t-  type Transpose to (t context) = t to--  fromColumns = gfromColumns contextSing-  toColumns = gtoColumns contextSing-  fromResult = gfromResult @t-  toResult = gtoResult @t---instance-  ( context ~ Expr-  , Rel8able t-  , HConstrainTable (Columns (t context)) (Sql DBEq)-  )-  => EqTable (t context)- where-  eqTable = hdicts @(Columns (t context)) @(Sql DBEq)---instance-  ( context ~ Expr-  , Rel8able t-  , HConstrainTable (Columns (t context)) (Sql DBEq)-  , HConstrainTable (Columns (t context)) (Sql DBOrd)-  )-  => OrdTable (t context)- where-  ordTable = hdicts @(Columns (t context)) @(Sql DBOrd)---instance-  ( Rel8able t', t' ~ Choose (Algebra t) t-  , x ~ t' Expr-  , result ~ Result-  )-  => ToExprs x (t result)---type Choose :: K.Algebra -> K.Rel8able -> K.Rel8able-type family Choose algebra t where-  Choose 'K.Sum t = ADT t-  Choose 'K.Product t = t
− src/Rel8/Table/Serialize.hs
@@ -1,149 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language FunctionalDependencies #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Table.Serialize-  ( Serializable, lit, litHTable, parse-  , ToExprs-  )-where---- base-import Data.Functor.Identity ( Identity( Identity ) )-import Data.Kind ( Constraint, Type )-import Data.List.NonEmpty ( NonEmpty )-import Prelude---- hasql-import qualified Hasql.Decoders as Hasql---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Serialize ( slitExpr, sparseValue )-import Rel8.Schema.HTable ( HTable, htabulate, htabulateA, hfield, hspecs )-import Rel8.Schema.Null ( NotNull, Sql )-import Rel8.Schema.Result ( Result )-import Rel8.Schema.Spec ( Spec(..) )-import Rel8.Table ( Table, fromColumns, FromExprs, fromResult, toResult )-import Rel8.Type ( DBType )---- semigroupoids-import Data.Functor.Apply ( WrappedApplicative(..) )----- | @ToExprs exprs a@ is evidence that the types @exprs@ and @a@ describe--- essentially the same type, but @exprs@ is in the 'Expr' context, and @a@ is--- a normal Haskell type.-type ToExprs :: Type -> Type -> Constraint-class Table Expr exprs => ToExprs exprs a---instance {-# OVERLAPPABLE #-} (Sql DBType a, x ~ Expr a) => ToExprs x a---instance (Sql DBType a, x ~ [a]) => ToExprs (Expr x) [a]---instance (Sql DBType a, NotNull a, x ~ Maybe a) => ToExprs (Expr x) (Maybe a)---instance (Sql DBType a, NotNull a, x ~ NonEmpty a) => ToExprs (Expr x) (NonEmpty a)---instance (ToExprs exprs1 a, ToExprs exprs2 b, x ~ (exprs1, exprs2)) =>-  ToExprs x (a, b)---instance-  ( ToExprs exprs1 a-  , ToExprs exprs2 b-  , ToExprs exprs3 c-  , x ~ (exprs1, exprs2, exprs3)-  )-  => ToExprs x (a, b, c)---instance-  ( ToExprs exprs1 a-  , ToExprs exprs2 b-  , ToExprs exprs3 c-  , ToExprs exprs4 d-  , x ~ (exprs1, exprs2, exprs3, exprs4)-  )-  => ToExprs x (a, b, c, d)---instance-  ( ToExprs exprs1 a-  , ToExprs exprs2 b-  , ToExprs exprs3 c-  , ToExprs exprs4 d-  , ToExprs exprs5 e-  , x ~ (exprs1, exprs2, exprs3, exprs4, exprs5)-  )-  => ToExprs x (a, b, c, d, e)---instance-  ( ToExprs exprs1 a-  , ToExprs exprs2 b-  , ToExprs exprs3 c-  , ToExprs exprs4 d-  , ToExprs exprs5 e-  , ToExprs exprs6 f-  , x ~ (exprs1, exprs2, exprs3, exprs4, exprs5, exprs6)-  )-  => ToExprs x (a, b, c, d, e, f)---instance-  ( ToExprs exprs1 a-  , ToExprs exprs2 b-  , ToExprs exprs3 c-  , ToExprs exprs4 d-  , ToExprs exprs5 e-  , ToExprs exprs6 f-  , ToExprs exprs7 g-  , x ~ (exprs1, exprs2, exprs3, exprs4, exprs5, exprs6, exprs7)-  )-  => ToExprs x (a, b, c, d, e, f, g)----- | @Serializable@ witnesses the one-to-one correspondence between the type--- @sql@, which contains SQL expressions, and the type @haskell@, which--- contains the Haskell decoding of rows containing @sql@ SQL expressions.-type Serializable :: Type -> Type -> Constraint-class (ToExprs exprs a, a ~ FromExprs exprs) => Serializable exprs a | exprs -> a-instance (ToExprs exprs a, a ~ FromExprs exprs) => Serializable exprs a-instance {-# OVERLAPPING #-} Sql DBType a => Serializable (Expr a) a----- | Use @lit@ to turn literal Haskell values into expressions. @lit@ is--- capable of lifting single @Expr@s to full tables.-lit :: forall exprs a. Serializable exprs a => a -> exprs-lit = fromColumns . litHTable . toResult @_ @exprs---parse :: forall exprs a. Serializable exprs a => Hasql.Row a-parse = fromResult @_ @exprs <$> parseHTable---litHTable :: HTable t => t Result -> t Expr-litHTable as = htabulate $ \field ->-  case hfield hspecs field of-    Spec {nullity, info} -> case hfield as field of-      Identity value -> slitExpr nullity info value---parseHTable :: HTable t => Hasql.Row (t Result)-parseHTable = unwrapApplicative $ htabulateA $ \field ->-  WrapApplicative $ case hfield hspecs field of-    Spec {nullity, info} -> Identity <$> sparseValue nullity info
− src/Rel8/Table/These.hs
@@ -1,482 +0,0 @@-{-# language DataKinds #-}-{-# language DeriveFunctor #-}-{-# language DerivingStrategies #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TupleSections #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--{-# options_ghc -fno-warn-orphans #-}--module Rel8.Table.These-  ( TheseTable(..)-  , theseTable, thisTable, thatTable, thoseTable-  , isThisTable, isThatTable, isThoseTable-  , hasHereTable, hasThereTable-  , justHereTable, justThereTable-  , alignMaybeTable-  , aggregateThisTable, aggregateThisTable1-  , aggregateThatTable, aggregateThatTable1-  , aggregateThoseTable, aggregateThoseTable1-  , aggregateHereTable, aggregateHereTable1-  , aggregateThereTable, aggregateThereTable1-  , aggregateTheseTable-  , nameTheseTable-  )-where---- base-import Control.Arrow ((&&&))-import Data.Bifunctor ( Bifunctor, bimap )-import Data.Kind ( Type )-import Data.Maybe ( isJust )-import Prelude hiding ( null, undefined )---- profunctors-import Data.Profunctor (lmap)---- rel8-import Rel8.Aggregate (Aggregator, Aggregator', Aggregator1)-import Rel8.Expr ( Expr )-import Rel8.Expr.Bool ( (&&.), (||.), boolExpr, not_ )-import Rel8.Expr.Null ( null, isNonNull )-import Rel8.Kind.Context ( Reifiable )-import Rel8.Schema.Context.Nullify ( Nullifiable )-import Rel8.Schema.Dict ( Dict( Dict ) )-import Rel8.Schema.HTable.Label ( hlabel, hrelabel, hunlabel )-import Rel8.Schema.HTable.Identity ( HIdentity(..) )-import Rel8.Schema.HTable.Maybe ( HMaybeTable(..) )-import Rel8.Schema.HTable.These ( HTheseTable(..) )-import qualified Rel8.Schema.Kind as K-import Rel8.Schema.Name ( Name )-import Rel8.Table-  ( Table, Columns, Context, fromColumns, toColumns-  , FromExprs, fromResult, toResult-  , Transpose-  )-import Rel8.Table.Aggregate (filterWhere)-import Rel8.Table.Aggregate.Maybe-  ( aggregateJustTable, aggregateJustTable1-  , aggregateMaybeTable-  , filterWhereOptional-  )-import Rel8.Table.Eq ( EqTable, eqTable )-import Rel8.Table.Maybe-  ( MaybeTable(..)-  , maybeTable, justTable, nothingTable-  , isJustTable-  , nameMaybeTable-  , unsafeFromJustTable-  )-import Rel8.Table.Nullify ( Nullify, guard )-import Rel8.Table.Ord ( OrdTable, ordTable )-import Rel8.Table.Projection ( Biprojectable, Projectable, biproject, project )-import Rel8.Table.Serialize ( ToExprs )-import Rel8.Table.Undefined ( undefined )-import Rel8.Type.Tag ( MaybeTag )---- semigroupoids-import Data.Functor.Apply ( Apply, (<.>) )-import Data.Functor.Bind ( Bind, (>>-) )---- these-import Data.These ( These( This, That, These ) )-import Data.These.Combinators ( justHere, justThere )----- | @TheseTable a b@ is a Rel8 table that contains either the table @a@, the--- table @b@, or both tables @a@ and @b@. You can construct @TheseTable@s using--- 'thisTable', 'thatTable' and 'thoseTable'. @TheseTable@s can be--- eliminated/pattern matched using 'theseTable'.------ @TheseTable@ is operationally the same as Haskell's 'These' type, but--- adapted to work with Rel8.-type TheseTable :: K.Context -> Type -> Type -> Type-data TheseTable context a b = TheseTable-  { here :: MaybeTable context a-  , there :: MaybeTable context b-  }-  deriving stock Functor---instance Biprojectable (TheseTable context) where-  biproject f g (TheseTable a b) = TheseTable (project f a) (project g b)---instance Nullifiable context => Bifunctor (TheseTable context) where-  bimap f g (TheseTable a b) = TheseTable (fmap f a) (fmap g b)---instance Projectable (TheseTable context a) where-  project f (TheseTable a b) = TheseTable a (project f b)---instance (context ~ Expr, Table Expr a, Semigroup a) =>-  Apply (TheseTable context a)- where-  fs <.> as = TheseTable-    { here = here fs <> here as-    , there = there fs <.> there as-    }---instance (context ~ Expr, Table Expr a, Semigroup a) =>-  Applicative (TheseTable context a)- where-  pure = thatTable-  (<*>) = (<.>)---instance (context ~ Expr, Table Expr a, Semigroup a) =>-  Bind (TheseTable context a)- where-  TheseTable here1 ma >>- f = case ma >>- f' of-    mtb -> TheseTable-      { here = maybeTable here1 ((here1 <>) . fst) mtb-      , there = snd <$> mtb-      }-    where-      f' a = case f a of-        TheseTable here2 mb -> (here2,) <$> mb---instance (context ~ Expr, Table Expr a, Semigroup a) =>-  Monad (TheseTable context a)- where-  (>>=) = (>>-)---instance (context ~ Expr, Table Expr a, Table Expr b, Semigroup a, Semigroup b) =>-  Semigroup (TheseTable context a b)- where-  a <> b = TheseTable-    { here = here a <> here b-    , there = there a <> there b-    }---instance-  ( Table context a, Table context b-  , Reifiable context, context ~ context'-  )-  => Table context' (TheseTable context a b)- where-  type Columns (TheseTable context a b) = HTheseTable (Columns a) (Columns b)-  type Context (TheseTable context a b) = Context a-  type FromExprs (TheseTable context a b) =-    These (FromExprs a) (FromExprs b)-  type Transpose to (TheseTable context a b) =-    TheseTable to (Transpose to a) (Transpose to b)--  toColumns TheseTable {here, there} = HTheseTable-    { hhereTag = hlabel $ HIdentity $ tag here-    , hhere =-        hlabel $ guard (tag here) isJust isNonNull $ toColumns $ just here-    , hthereTag = hlabel $ HIdentity $ tag there-    , hthere =-        hlabel $ guard (tag there) isJust isNonNull $ toColumns $ just there-    }--  fromColumns HTheseTable {hhereTag, hhere, hthereTag, hthere} = TheseTable-    { here = MaybeTable-        { tag = unHIdentity $ hunlabel hhereTag-        , just = fromColumns $ hunlabel hhere-        }-    , there = MaybeTable-        { tag = unHIdentity $ hunlabel hthereTag-        , just = fromColumns $ hunlabel hthere-        }-    }--  toResult tables = HTheseTable-    { hhereTag = hrelabel hhereTag-    , hhere = hrelabel hhere-    , hthereTag = hrelabel hthereTag-    , hthere = hrelabel hthere-    }-    where-      HMaybeTable-        { htag = hhereTag-        , hjust = hhere-        } = toResult @_ @(MaybeTable context a) (justHere tables)-      HMaybeTable-        { htag = hthereTag-        , hjust = hthere-        } = toResult @_ @(MaybeTable context b) (justThere tables)--  fromResult HTheseTable {hhereTag, hhere, hthereTag, hthere} =-    case (here, there) of-      (Just a, Nothing) -> This a-      (Nothing, Just b) -> That b-      (Just a, Just b) -> These a b-      _ -> error "These.fromColumns: mismatch between tags and data"-    where-      here = fromResult @_ @(MaybeTable context a) mhere-      there = fromResult @_ @(MaybeTable context b) mthere-      mhere = HMaybeTable-        { htag = hrelabel hhereTag-        , hjust = hrelabel hhere-        }-      mthere = HMaybeTable-        { htag = hrelabel hthereTag-        , hjust = hrelabel hthere-        }---instance (EqTable a, EqTable b, context ~ Expr) =>-  EqTable (TheseTable context a b)- where-  eqTable = HTheseTable-    { hhereTag = hlabel (HIdentity Dict)-    , hhere = hlabel (eqTable @(Nullify context a))-    , hthereTag = hlabel (HIdentity Dict)-    , hthere = hlabel (eqTable @(Nullify context b))-    }---instance (OrdTable a, OrdTable b, context ~ Expr) =>-  OrdTable (TheseTable context a b)- where-  ordTable = HTheseTable-    { hhereTag = hlabel (HIdentity Dict)-    , hhere = hlabel (ordTable @(Nullify context a))-    , hthereTag = hlabel (HIdentity Dict)-    , hthere = hlabel (ordTable @(Nullify context b))-    }---instance (ToExprs exprs1 a, ToExprs exprs2 b, x ~ TheseTable Expr exprs1 exprs2) =>-  ToExprs x (These a b)----- | Test if a 'TheseTable' was constructed with 'thisTable'.------ Corresponds to 'Data.These.Combinators.isThis'.-isThisTable :: TheseTable Expr a b -> Expr Bool-isThisTable a = hasHereTable a &&. not_ (hasThereTable a)----- | Test if a 'TheseTable' was constructed with 'thatTable'.------ Corresponds to 'Data.These.Combinators.isThat'.-isThatTable :: TheseTable Expr a b -> Expr Bool-isThatTable a = not_ (hasHereTable a) &&. hasThereTable a----- | Test if a 'TheseTable' was constructed with 'thoseTable'.------ Corresponds to 'Data.These.Combinators.isThese'.-isThoseTable :: TheseTable Expr a b -> Expr Bool-isThoseTable a = hasHereTable a &&. hasThereTable a----- | Test if the @a@ side of @TheseTable a b@ is present.------ Corresponds to 'Data.These.Combinators.hasHere'.-hasHereTable :: TheseTable Expr a b -> Expr Bool-hasHereTable TheseTable {here} = isJustTable here----- | Test if the @b@ table of @TheseTable a b@ is present.------ Corresponds to 'Data.These.Combinators.hasThere'.-hasThereTable :: TheseTable Expr a b -> Expr Bool-hasThereTable TheseTable {there} = isJustTable there----- | Attempt to project out the @a@ table of a @TheseTable a b@.------ Corresponds to 'Data.These.Combinators.justHere'.-justHereTable :: TheseTable context a b -> MaybeTable context a-justHereTable = here----- | Attempt to project out the @b@ table of a @TheseTable a b@.------ Corresponds to 'Data.These.Combinators.justThere'.-justThereTable :: TheseTable context a b -> MaybeTable context b-justThereTable = there----- | Construct a @TheseTable@ from two 'MaybeTable's.-alignMaybeTable :: ()-  => MaybeTable Expr a-  -> MaybeTable Expr b-  -> MaybeTable Expr (TheseTable Expr a b)-alignMaybeTable a b = MaybeTable tag (pure (TheseTable a b))-  where-    tag = boolExpr null mempty (isJustTable a ||. isJustTable b)----- | Construct a @TheseTable@. Corresponds to 'This'.-thisTable :: Table Expr b => a -> TheseTable Expr a b-thisTable a = TheseTable (justTable a) nothingTable----- | Construct a @TheseTable@. Corresponds to 'That'.-thatTable :: Table Expr a => b -> TheseTable Expr a b-thatTable b = TheseTable nothingTable (justTable b)----- | Construct a @TheseTable@. Corresponds to 'These'.-thoseTable :: a -> b -> TheseTable Expr a b-thoseTable a b = TheseTable (justTable a) (justTable b)----- | Pattern match on a 'TheseTable'. Corresponds to 'these'.-theseTable :: Table Expr c-  => (a -> c) -> (b -> c) -> (a -> b -> c) -> TheseTable Expr a b -> c-theseTable f g h TheseTable {here, there} =-  maybeTable-    (maybeTable undefined f here)-    (\b -> maybeTable (g b) (`h` b) here)-    there----- | Lift an 'Aggregator' to operate on a 'TheseTable'. If the input query has--- @'thisTable' a@s, they are folded into a single @c@ by the given aggregator--- — in the case where the input query is all 'thatTable's or 'thoseTable's,--- the 'Aggregator'\'s fallback @c@ is returned.-aggregateThisTable :: Table Expr c-  => Aggregator a c-  -> Aggregator' fold (TheseTable Expr a b) c-aggregateThisTable =-  filterWhere isThisTable . lmap (unsafeFromJustTable . here)----- | Lift an 'Aggregator1' to operate on a 'TheseTable'. If the input query--- has @'thisTable' a@s, they are folded into a single @'Rel8.justTable' c@--- by the given aggregator — in the case where the input query is all--- 'thatTable's or 'thoseTable's, a single 'nothingTable' row is returned.-aggregateThisTable1 :: Table Expr c-  => Aggregator' fold a c-  -> Aggregator' fold' (TheseTable Expr a b) (MaybeTable Expr c)-aggregateThisTable1 =-  filterWhereOptional isThisTable . lmap (unsafeFromJustTable . here)----- | Lift an 'Aggregator' to operate on a 'TheseTable'. If the input query has--- @'thatTable' b@s, they are folded into a single @c@ by the given aggregator--- — in the case where the input query is all 'thisTable's or 'thoseTable's,--- the 'Aggregator'\'s fallback @c@ is returned.-aggregateThatTable :: Table Expr c-  => Aggregator b c-  -> Aggregator' fold (TheseTable Expr a b) c-aggregateThatTable =-  filterWhere isThatTable . lmap (unsafeFromJustTable . there)----- | Lift an 'Aggregator1' to operate on a 'TheseTable'. If the input query--- has @'thatTable' b@s, they are folded into a single @'Rel8.justTable' c@--- by the given aggregator — in the case where the input query is all--- 'thisTable's or 'thoseTable's, a single 'nothingTable' row is returned.-aggregateThatTable1 :: Table Expr c-  => Aggregator' fold b c-  -> Aggregator' fold' (TheseTable Expr a b) (MaybeTable Expr c)-aggregateThatTable1 =-  filterWhereOptional isThatTable . lmap (unsafeFromJustTable . there)----- | Lift an 'Aggregator' to operate on a 'ThoseTable'. If the input query has--- @'thoseTable' a b@s, they are folded into a single @c@ by the given--- aggregator — in the case where the input query is all 'thisTable's or--- 'thatTable's, the 'Aggregator'\'s fallback @c@ is returned.-aggregateThoseTable :: Table Expr c-  => Aggregator (a, b) c-  -> Aggregator' fold (TheseTable Expr a b) c-aggregateThoseTable =-  filterWhere isThoseTable-    . lmap (unsafeFromJustTable . here &&& unsafeFromJustTable . there)----- | Lift an 'Aggregator1' to operate on a 'TheseTable'. If the input query--- has @'thoseTable' a b@s, they are folded into a single @'Rel8.justTable' c@--- by the given aggregator — in the case where the input query is all--- 'thisTable's or 'thatTable's, a single 'nothingTable' row is returned.-aggregateThoseTable1 :: Table Expr c-  => Aggregator' fold (a, b) c-  -> Aggregator' fold' (TheseTable Expr a b) (MaybeTable Expr c)-aggregateThoseTable1 =-  filterWhereOptional isThoseTable-    . lmap (unsafeFromJustTable . here &&& unsafeFromJustTable . there)----- | Lift an 'Aggregator' to operate on a 'TheseTable'. If the input query has--- @'thisTable' a@s or @'thoseTable' a _@s, the @a@s are folded into a single--- @c@ by the given aggregator — in the case where the input query is all--- 'thatTable's, the 'Aggregator'\'s fallback @c@ is returned.-aggregateHereTable :: Table Expr c-  => Aggregator a c-  -> Aggregator' fold (TheseTable Expr a b) c-aggregateHereTable = lmap here . aggregateJustTable----- | Lift an 'Aggregator1' to operate on an 'TheseTable'. If the input query--- has @'thisTable' a@s or @'thoseTable' a _@s, the @a@s are folded into a--- single @'Rel8.justTable' c@ by the given aggregator — in the case where--- the input query is all 'thatTable's, a single 'nothingTable' row is--- returned.-aggregateHereTable1 :: Table Expr c-  => Aggregator' fold a c-  -> Aggregator' fold' (TheseTable Expr a b) (MaybeTable Expr c)-aggregateHereTable1 = lmap here . aggregateJustTable1----- | Lift an 'Aggregator' to operate on a 'TheseTable'. If the input query has--- @'thatTable' b@s or @'thoseTable' _ b@s, the @b@s are folded into a single--- @c@ by the given aggregator — in the case where the input query is all--- 'thisTable's, the 'Aggregator'\'s fallback @c@ is returned.-aggregateThereTable :: Table Expr c-  => Aggregator b c-  -> Aggregator' fold (TheseTable Expr a b) c-aggregateThereTable = lmap there . aggregateJustTable----- | Lift an 'Aggregator1' to operate on an 'TheseTable'. If the input query--- has @'thatTable' b@s or @'thoseTable' _ b@s, the @b@s are folded into a--- single @'Rel8.justTable' c@ by the given aggregator — in the case where--- the input query is all 'thisTable's, a single 'nothingTable' row is--- returned.-aggregateThereTable1 :: Table Expr c-  => Aggregator' fold b c-  -> Aggregator' fold' (TheseTable Expr a b) (MaybeTable Expr c)-aggregateThereTable1 = lmap there . aggregateJustTable1----- | Lift a pair aggregators to operate on a 'TheseTable'. 'thisTable's,--- 'thatTable's are 'thoseTable's are grouped separately.-aggregateTheseTable :: ()-  => Aggregator' fold i a-  -> Aggregator' fold' i' b-  -> Aggregator1 (TheseTable Expr i i') (TheseTable Expr a b)-aggregateTheseTable a b =-  TheseTable-    <$> lmap here (aggregateMaybeTable a)-    <*> lmap there (aggregateMaybeTable b)----- | Construct a 'TheseTable' in the 'Name' context. This can be useful if you--- have a 'TheseTable' that you are storing in a table and need to construct a--- 'TableSchema'.-nameTheseTable :: ()-  => Name (Maybe MaybeTag)-     -- ^ The name of the column to track the presence of the @a@ table.-  -> Name (Maybe MaybeTag)-     -- ^ The name of the column to track the presence of the @b@ table.-  -> a-     -- ^ Names of the columns in the @a@ table.-  -> b-     -- ^ Names of the columns in the @b@ table.-  -> TheseTable Name a b-nameTheseTable here there a b =-  TheseTable-    { here = nameMaybeTable here a-    , there = nameMaybeTable there b-    }
− src/Rel8/Table/Transpose.hs
@@ -1,50 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleInstances #-}-{-# language FunctionalDependencies #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Table.Transpose-  ( Transposes-  )-where---- base-import Data.Kind ( Constraint, Type )-import Prelude ()---- base-compat-import Data.Type.Equality.Compat---- rel8-import qualified Rel8.Schema.Kind as K-import Rel8.Table ( Table, Transpose, Congruent )----- | @'Transposes' from to a b@ means that @a@ and @b@ are 'Table's, in the--- @from@ and @to@ contexts respectively, which share the same underlying--- structure. In other words, @b@ is a version of @a@ transposed from the--- @from@ context to the @to@ context (and vice versa).-type Transposes :: K.Context -> K.Context -> Type -> Type -> Constraint-class-  ( Table from a-  , Table to b-  , Congruent a b-  , b ~ Transpose to a-  , a ~ Transpose from b-  )-  => Transposes from to a b-    | a -> from-    , b -> to-    , a to -> b-    , b from -> a-instance-  ( Table from a-  , Table to b-  , Congruent a b-  , b ~ Transpose to a-  , a ~ Transpose from b-  )-  => Transposes from to a b
− src/Rel8/Table/Undefined.hs
@@ -1,26 +0,0 @@-{-# language FlexibleContexts #-}-{-# language NamedFieldPuns #-}-{-# language TypeFamilies #-}--module Rel8.Table.Undefined-  ( undefined-  )-where---- base-import Prelude hiding ( undefined )---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Null ( snull, unsafeUnnullify )-import Rel8.Schema.HTable ( htabulate, hfield, hspecs )-import Rel8.Schema.Null ( Nullity( Null, NotNull ) )-import Rel8.Schema.Spec ( Spec(..) )-import Rel8.Table ( Table, fromColumns )---undefined :: Table Expr a => a-undefined = fromColumns $ htabulate $ \field -> case hfield hspecs field of-  Spec {nullity, info} -> case nullity of-    Null -> snull info-    NotNull -> unsafeUnnullify (snull info)
− src/Rel8/Table/Verify.hs
@@ -1,644 +0,0 @@--{-# language BlockArguments #-}-{-# language LambdaCase #-}-{-# language RecordWildCards #-}-{-# language RankNTypes #-}-{-# language DuplicateRecordFields #-}-{-# language DerivingStrategies #-}-{-# language OverloadedRecordDot #-}-{-# language TypeApplications #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneDeriving #-}-{-# language DeriveAnyClass #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language DeriveGeneric #-}-{-# language GeneralizedNewtypeDeriving #-}-{-# language OverloadedStrings #-}-{-# language GADTs #-}--module Rel8.Table.Verify-    ( getSchemaErrors-    , SomeTableSchema(..)-    , showCreateTable-    , checkedShowCreateTable-    ) where---- base-import Control.Monad-import Data.Bits (shiftR, (.&.))-import Data.Either (lefts)-import Data.Function-import Data.Functor ((<&>))-import Data.Functor.Const-import Data.Functor.Contravariant ( (>$<) )-import Data.Int ( Int16, Int64 )-import qualified Data.List as L-import Data.List.NonEmpty ( NonEmpty((:|)) )-import qualified Data.List.NonEmpty as NonEmpty-import Data.Maybe (isJust, mapMaybe)-import Data.Text ( Text )-import qualified Data.Text as T-import GHC.Generics-import Prelude hiding ( filter )-import qualified Prelude as P---- containers-import qualified Data.Map as M---- hasql-import Hasql.Connection-import qualified Hasql.Statement as HS---- rel8-import Rel8 -- not importing this seems to cause a type error???-import Rel8.Column ( Column )-import Rel8.Column.List ( HList )-import Rel8.Expr ( Expr )-import Rel8.Generic.Rel8able (GFromExprs, Rel8able)-import Rel8.Query ( Query )-import Rel8.Schema.HTable-import Rel8.Schema.Name ( Name(Name) )-import Rel8.Schema.Null hiding (nullable)-import qualified Rel8.Schema.Null as Null-import qualified Rel8.Statement.Run as RSR-import Rel8.Schema.Table ( TableSchema(..) )-import Rel8.Schema.Spec-import Rel8.Schema.Result ( Result )-import Rel8.Schema.QualifiedName ( QualifiedName(..) )-import Rel8.Table ( Columns )-import Rel8.Table.List ( ListTable )-import Rel8.Table.Serialize ( ToExprs )-import Rel8.Type ( DBType(..) )-import Rel8.Type.Eq ( DBEq )-import Rel8.Type.Name ( TypeName(..) )---- these-import Data.These---data Relkind-    = OrdinaryTable-    | Index-    | Sequence-    | ToastTable-    | View-    | MaterializedView-    | CompositeType-    | ForeignTable-    | PartitionedTable-    | PartitionedIndex-  deriving stock (Show)-  deriving anyclass (DBEq)--instance DBType Relkind where-  typeInformation = parseTypeInformation parser printer typeInformation-    where-      parser = \case-        "r"         -> pure OrdinaryTable-        "i"         -> pure Index-        "S"         -> pure Sequence-        "t"         -> pure ToastTable-        "v"         -> pure View-        "m"         -> pure MaterializedView-        "c"         -> pure CompositeType-        "f"         -> pure ForeignTable-        "p"         -> pure PartitionedTable-        "I"         -> pure PartitionedIndex-        (x :: Text) -> Left $ "Unknown relkind: " ++ show x--      printer = \case-        OrdinaryTable -> "r"-        Index -> "i"-        Sequence -> "S"-        ToastTable -> "t"-        View -> "v"-        MaterializedView -> "m"-        CompositeType -> "c"-        ForeignTable -> "f"-        PartitionedTable -> "p"-        PartitionedIndex -> "I"--newtype Oid = Oid Int64-  deriving newtype (DBType, DBEq, Show)--data PGClass f = PGClass-  { oid :: Column f Oid-  , relname :: Column f Text-  , relkind :: Column f Relkind-  , relnamespace :: Column f Oid-  }-  deriving stock (Generic)-  deriving anyclass (Rel8able)--deriving stock instance Show (PGClass Result)--pgclass :: TableSchema (PGClass Name)-pgclass = TableSchema-  { name = QualifiedName "pg_class" (Just "pg_catalog")-  , columns = namesFromLabelsWith NonEmpty.last-  }--data PGAttribute f = PGAttribute-  { attrelid :: Column f Oid-  , attname :: Column f Text-  , atttypid :: Column f Oid-  , attnum :: Column f Int64-  , atttypmod :: Column f Int64-  , attnotnull :: Column f Bool-  , attndims :: Column f Int16-  }-  deriving stock (Generic)-  deriving anyclass (Rel8able)--deriving stock instance Show (PGAttribute Result)--pgattribute :: TableSchema (PGAttribute Name)-pgattribute = TableSchema-  { name = QualifiedName "pg_attribute" (Just "pg_catalog")-  , columns = namesFromLabelsWith NonEmpty.last-  }--data PGType f = PGType-  { oid :: Column f Oid-  , typname :: Column f Text-  , typnamespace :: Column f Oid-  }-  deriving stock (Generic)-  deriving anyclass (Rel8able)--deriving stock instance Show (PGType Result)--pgtype :: TableSchema (PGType Name)-pgtype = TableSchema-  { name = QualifiedName "pg_type" (Just "pg_catalog")-  , columns = namesFromLabelsWith NonEmpty.last-  }--data PGNamespace f = PGNamespace-  { oid :: Column f Oid-  , nspname :: Column f Text-  }-  deriving stock (Generic)-  deriving anyclass (Rel8able)--deriving stock instance Show (PGNamespace Result)--pgnamespace :: TableSchema (PGNamespace Name)-pgnamespace = TableSchema-  { name = QualifiedName "pg_namespace" (Just "pg_catalog")-  , columns = namesFromLabelsWith NonEmpty.last-  }--data PGCast f = PGCast-  { oid :: Column f Oid-  , castsource :: Column f Oid-  , casttarget :: Column f Oid-  , castfunc :: Column f Oid-  , castcontext :: Column f Text -- Char-  , castmethod :: Column f Char-  }-  deriving stock (Generic)-  deriving anyclass (Rel8able)--deriving stock instance Show (PGCast Result)--pgcast :: TableSchema (PGCast Name)-pgcast = TableSchema-  { name = QualifiedName "pg_cast" (Just "pg_catalog")-  , columns = namesFromLabelsWith NonEmpty.last-  }--data PGTable f = PGTable-  { name :: Column f Text-  , columns :: HList f (Attribute f)-  }-  deriving stock (Generic)-  deriving anyclass (Rel8able)--deriving stock instance Show (PGTable Result)--data Attribute f = Attribute-  { attribute :: PGAttribute f-  , typ :: PGType f-  , namespace :: PGNamespace f-  }-  deriving stock (Generic)-  deriving anyclass (Rel8able)--deriving stock instance Show (Attribute Result)--data Cast f = Cast-  { source :: PGType f-  , target :: PGType f-  , context :: Column f Text -- Char -  }-  deriving stock (Generic)-  deriving anyclass (Rel8able)--deriving stock instance Show (Cast Result)--fetchTables :: Query (ListTable Expr (PGTable Expr))-fetchTables = many do-    PGClass{ oid = tableOid, relname } <- orderBy (relname >$< asc) do-      each pgclass-        >>= filter ((lit OrdinaryTable ==.) . relkind)--    columns <- many do-      attribute@PGAttribute{ atttypid } <--        each pgattribute-          >>= filter ((tableOid ==.) . attrelid)-          >>= filter ((>. 0) . attnum)--      typ <--        each pgtype-          >>= filter (\PGType{ oid = typoid } -> atttypid ==. typoid)--      namespace <--        each pgnamespace-          >>= filter (\PGNamespace{ oid = nsoid } -> nsoid ==. typ.typnamespace)----      return Attribute{ attribute, typ, namespace }--    return PGTable-      { name = relname-      , ..-      }--fetchCasts :: Query (ListTable Expr (Cast Expr))-fetchCasts = many do-    PGCast {castsource, casttarget, castcontext} <- each pgcast-    src <- each pgtype >>= filter (\PGType { oid = typoid } -> typoid ==. castsource)-    tgt <- each pgtype >>= filter (\PGType { oid = typoid } -> typoid ==. casttarget)-    return Cast { source = src, target = tgt, context = castcontext }---data CheckEnv = CheckEnv-  { schemaMap :: M.Map String [Attribute Result] -- map of schemas to attributes-  , casts :: [(String, String)] -- list of implicit casts-  } deriving (Show)---nullableToBool :: Nullity a -> Bool-nullableToBool Null = True-nullableToBool NotNull = False---attrsToMap :: [Attribute Result] -> M.Map String (Attribute Result)-attrsToMap = M.fromList . map (\attr -> (T.unpack attr.attribute.attname, attr))---data TypeInfo = TypeInfo-  { label :: [String]-  , isNull :: Bool-  , typeName :: TypeName-  }-instance Show TypeInfo where-  show = showTypeInfo----- @'schemaToTypeMap'@ takes a schema and returns a map of database column names--- to the type information associated with the column. It is possible (though--- undesirable) to write a schema which has multiple columns with the same name,--- so a list of results are returned for each key.-schemaToTypeMap :: forall k. Rel8able k => k Name -> M.Map String (NonEmpty.NonEmpty TypeInfo)-schemaToTypeMap cols = go . uncurry zip . getConst $-  htabulateA @(Columns (k Name)) $ \field -> -    case (hfield hspecs field, hfield (toColumns cols) field) of -      (Spec {..}, Name name) -> Const ([name], [-        TypeInfo { label = labels-                 , isNull = nullableToBool nullity-                 , typeName = info.typeName}])-  where-    go :: [(String, TypeInfo)] -> M.Map String (NonEmpty.NonEmpty TypeInfo)-    go = M.fromListWith (<>) . map (\(name, typeInfo) -> (name, NonEmpty.singleton typeInfo))---- A checked version of @schemaToTypeMap@, which returns a list of columns with--- duplicate names if any such columns are present. Otherwise it returns the--- type map with no duplicates.-checkedSchemaToTypeMap :: Rel8able k-  => k Name-  -> Either (M.Map String (NonEmpty.NonEmpty TypeInfo)) (M.Map String TypeInfo)-checkedSchemaToTypeMap cols =-  let typeMap = schemaToTypeMap cols-      duplicates = M.filter (\col -> length col > 1) typeMap-  in if length duplicates > 0-  then Left duplicates-  else Right (typeMap & M.mapMaybe \case-    a :| [] -> Just a-    _ -> Nothing)---showCreateTable_helper :: String -> M.Map String TypeInfo -> String-showCreateTable_helper name typeMap = "CREATE TABLE " <> show name <> " ("-    ++ L.intercalate "," (fmap go $ M.assocs typeMap)-    ++ "\n);"-  where-    go :: (String, TypeInfo) -> String-    go (name, typeInfo) = "\n    " ++ show name ++ " " ++ showTypeInfo typeInfo----- |@'showCreateTable'@ shows an example CREATE TABLE statement for the table.--- This does not show relationships like primary or foreign keys, but can still--- be useful to see what types @rel8@ will expect of the underlying database.------ In the event that multiple columns have the same name, this will fail silently. To--- handle that case, see 'checkedShowCreateTable'-showCreateTable :: Rel8able k => TableSchema (k Name) -> String-showCreateTable schema = showCreateTable_helper schema.name.name $ fmap NonEmpty.head $ schemaToTypeMap schema.columns---- |@'checkedShowCreateTable'@ shows an example CREATE TABLE statement for the--- table. This does not show relationships like primary or foreign keys, but can--- still be useful to see what types rel8 will expect of the underlying database.------ In the event that multiple columns have the same name, this will return a map of--- names to the labels identifying the column.-checkedShowCreateTable :: Rel8able k => TableSchema (k Name) -> Either (M.Map String (NonEmpty [String])) String-checkedShowCreateTable schema = case checkedSchemaToTypeMap schema.columns of-    Left e -> Left $ (fmap . fmap) (\typ -> typ.label)  e-    Right a -> Right $ showCreateTable_helper schema.name.name a---- implicit casts are ok as long as they're bidirectional-checkTypeEquality :: CheckEnv -> TypeInfo -> TypeInfo -> Maybe ColumnError-checkTypeEquality env db hs-  | Prelude.and [sameDims, sameMods, toName db == toName hs || castExists]-    = Nothing-  | otherwise-    = Just BidirectionalCastDoesNotExist-  where-    castExists = Prelude.and-      [ (toName db, toName hs) `elem` env.casts-      , (toName hs, toName db) `elem` env.casts-      ]--    sameMods, sameDims :: Bool-    sameMods = db.typeName.modifiers == hs.typeName.modifiers-    sameDims = db.typeName.arrayDepth == hs.typeName.arrayDepth--    sameName = equalName db.typeName.name hs.typeName.name--    toName :: TypeInfo -> String-    toName typeInfo = case typeInfo.typeName.name of-        QualifiedName name _ -> L.dropWhile (=='_') name--equalName :: QualifiedName -> QualifiedName -> Bool-equalName (QualifiedName a (Just b)) (QualifiedName a' (Just b'))-  = L.dropWhile (=='_') a == L.dropWhile (=='_') a' && b == b'-equalName (QualifiedName a _) (QualifiedName a' _)-  = dropWhile (=='_') a == dropWhile (=='_') a'---- check types for a single table-compareTypes-    :: CheckEnv-    -> M.Map String (Attribute Result)-    -> M.Map String TypeInfo-    -> [ColumnInfo]-compareTypes env attrMap typeMap = fmap (uncurry go) $ M.assocs (disjointUnion attrMap typeMap)-  where-    go :: String -> These (Attribute Result) TypeInfo -> ColumnInfo-    go name (These a b) = ColumnInfo-        { name = name-        , dbType = Just $ fromAttribute a-        , hsType = Just $ b-        , error = checkTypeEquality env (fromAttribute a) b-        }-    go name (This a) = ColumnInfo-        { name = name-        , dbType = Just $ fromAttribute a-        , hsType = Nothing-        , error =-            if a.attribute.attnotnull-            then Just DbTypeIsNotNullButNotPresentInHsType-            else Nothing-        }-    go name (That b) = ColumnInfo-        { name = name-        , dbType = Nothing-        , hsType = Just $ b-        , error = Just HsTypeIsPresentButNotPresentInDbType-        }--    fromAttribute :: Attribute Result -> TypeInfo-    fromAttribute attr = TypeInfo-        { label = [T.unpack attr.attribute.attname]-        , isNull = not attr.attribute.attnotnull-        , typeName = TypeName-            { name = QualifiedName-                (T.unpack attr.typ.typname)-                (Just $ T.unpack attr.namespace.nspname)-            , modifiers = toModifier-                (T.dropWhile (=='_') attr.typ.typname)-                attr.attribute.atttypmod-            , arrayDepth = fromIntegral attr.attribute.attndims-            }-        }--    toModifier :: Text -> Int64 -> [String]-    toModifier "bpchar" (-1) = []-    toModifier "bpchar" n = [show (n - 4)]-    toModifier "numeric" (-1) = []-    toModifier "numeric" n = [show $ (n - 4) `shiftR` 16, show $ (n - 4) .&. 65535]-    toModifier _ _ = []--    disjointUnion :: Ord k => M.Map k a -> M.Map k b -> M.Map k (These a b)-    disjointUnion a b = M.unionWith go (fmap This a) (fmap That b)-      where-        go :: These a b -> These a b -> These a b-        go (This a) (That b) = These a b-        go _ _ = undefined----- |@pShowTable@ is a helper function which takes a grid of text and prints it--- as a table, with padding so that cells are lined in columns, and a bordered--- header for the first row-pShowTable :: [[Text]] -> Text-pShowTable xs-    = T.intercalate "\n"-    $ addHeaderBorder-    $ fmap (T.intercalate " | ")-    $ L.transpose-    $ zip lengths xs' <&> \(n, column) -> column <&> \cell -> T.justifyLeft n ' ' cell-  where-    addHeaderBorder :: [Text] -> [Text]-    addHeaderBorder [] = []-    addHeaderBorder (x : xs) = x : T.replicate (T.length x) "-" : xs--    xs' :: [[Text]]-    xs' = L.transpose xs--    lengths :: [Int]-    lengths = fmap (maximum . fmap T.length) $ xs'---pShowErrors :: [TableInfo] -> Text-pShowErrors = T.intercalate "\n\n" . fmap go-  where-    go :: TableInfo -> Text-    go (TableInfo {tableExists, name, columns}) = "Table: " <> T.pack name-        <> if not tableExists then " does not exist\n" else "\n"-        <> pShowTable (["Column Name", "Implied DB type", "Current DB type", "Error"] : (columns <&> \column ->-            [ T.pack $ column.name-            , T.pack $ maybe "" showTypeInfo column.hsType-            , T.pack $ maybe "" showTypeInfo column.dbType-            , T.pack $ maybe "" show column.error-            ]))-    go (DuplicateNames {name, duplicates}) = mconcat-        [ "Table "-        , T.pack (show name)-        , " has multiple columns with the same name. This is an error with the Haskell code generating an impossible schema, rather than an error in your current setup of the database itself. Using 'namesFromLabels' can ensure each column has unique names, which is the easiest way to prevent this, but may require changing names in your database to match the new generated names."-        , pShowTable (["DB name", "Haskell label"] : (M.assocs duplicates <&> \(name, typs) ->-            [ T.pack name-            , T.intercalate " " $ fmap (\typ -> T.intercalate "/" $ fmap T.pack typ.label) $ NonEmpty.toList typs-            ]))-        ]---data TableInfo-  = TableInfo-    { tableExists :: Bool-    , name :: String-    , columns :: [ColumnInfo]-    }-  | DuplicateNames-    { name :: String-    , duplicates :: M.Map String (NonEmpty.NonEmpty TypeInfo)-    }-  deriving (Show)--data ColumnInfo = ColumnInfo-    { name   :: String-    , hsType :: Maybe TypeInfo-    , dbType :: Maybe TypeInfo-    , error :: Maybe ColumnError-    } deriving (Show)--data ColumnError-    = DbTypeIsNotNullButNotPresentInHsType-    | HsTypeIsPresentButNotPresentInDbType-    | BidirectionalCastDoesNotExist-    deriving (Show)---showTypeInfo :: TypeInfo -> String-showTypeInfo typeInfo = concat-    [ name-    , if Prelude.null modifiers then "" else "(" <> L.intercalate "," modifiers <> ")"-    , concat (replicate (fromIntegral typeInfo.typeName.arrayDepth) "[]")-    , if typeInfo.isNull then "" else " NOT NULL"-    ]-  where-    name = case typeInfo.typeName.name of-        QualifiedName a Nothing -> show (dropWhile (=='_') a)-        QualifiedName a (Just b) -> show b <> "." <> show (dropWhile (=='_') a)--    modifiers :: [String]-    modifiers = typeInfo.typeName.modifiers---verifySchema :: Rel8able k => CheckEnv -> TableSchema (k Name) -> TableInfo-verifySchema env schema = case checkedSchemaToTypeMap schema.columns of-    Left dups -> DuplicateNames schema.name.name dups-    Right typeMap -> go typeMap maybeTable-  where-    maybeTable = M.lookup schema.name.name env.schemaMap-    go typeMap Nothing = TableInfo-        { tableExists = False-        , name = schema.name.name-        , columns = compareTypes env mempty typeMap-        }-    go typeMap (Just attrs) = TableInfo-        { tableExists = True-        , name = schema.name.name-        , columns = compareTypes env (attrsToMap attrs) typeMap-        }---fetchCheckEnv :: HS.Statement () CheckEnv-fetchCheckEnv = fetchSchema <&> \(tbls, casts) -> -  let tblMap = foldMap (\PGTable {..} -> M.singleton (T.unpack name) columns) tbls-      castMap = map (\Cast {..} -> (T.unpack source.typname, T.unpack target.typname)) $ L.filter (\Cast {context} -> context == "i") casts-  in CheckEnv tblMap castMap- where-  fetchSchema :: HS.Statement () ([PGTable Result], [Cast Result])-  fetchSchema = run1 $ select $ liftA2 (,) fetchTables fetchCasts----- |@'SomeTableSchema'@ is used to allow the collection of a variety of different--- @TableSchema@s under a single type, like:------ @--- userTable :: TableSchema (User Name)--- orderTable :: TableSchema (Order Name)------ tables :: [SomeTableSchema]--- tables = [SomeTableSchema userTable, SomeTable orderTable]--- @------ This is used by @'schemaErrors'@ to conveniently group every table an--- application relies on for typechecking the postgresql schemas--- together in a single batch.-data SomeTableSchema where-    -- The ToExpr constraint isn't used here, but can be used to read from the-    -- SomeTableSchema, which can be useful to combine the type checking with more-    -- thorough value-level checking of the validity of existing rows in the-    -- table.-    SomeTableSchema-        :: (ToExprs (k Expr) (GFromExprs k), Rel8able k)-        => TableSchema (k Name) -> SomeTableSchema---- |@'getSchemaErrors'@ checks whether the provided schemas have the correct PostgreSQL--- column names and types to allow reading and writing from their equivalent Haskell--- types, returning a list of errors if that is not the case. The function does not--- crash on encountering a bug, instead leaving it to the caller to decide how--- to respond. A schema is valid if:------ 1. for every existing field, the types match--- 2. all non-nullable columns are present in the hs type--- 3. no nonexistent columns are present in the hs type--- 4. no two columns in the same schema share the same name------ It's still possible for a valid schema to allow invalid data, for instance,--- if using an ADT, which can introduce restrictions on which values are allowed--- for the column representing the tag, and introduce restrictions on which--- columns are non-null depending on the value of the tag. However, if the--- schema is valid rel8 shouldn't be able to write invalid data to the table.------ However, it is possible for migrations to cause valid data to become invalid--- in ways not detectable by this function, if the migration code changes the--- schema correctly but doesn't handle the value-level constraints correctly. So--- it is a good idea to both read from the tables and check the schema for errors--- in a transaction during the migration. The former will catch value-level--- bugs, while the latter will help ensure the schema is set up correctly to--- be able to insert new data.------ This function does nothing to check that the conflict target of an @Upsert@--- are valid for the schema, nor can it prevent invalid uses of @unsafeDefault@.--- However, it should be enough to catch the most likely errors.-getSchemaErrors :: [SomeTableSchema] -> HS.Statement () (Maybe Text)-getSchemaErrors someTables = fmap collectErrors fetchCheckEnv-  where-    collectErrors :: CheckEnv -> Maybe Text-    collectErrors env-        = fmap pShowErrors-        . filterErrors-        . fmap \case-            SomeTableSchema t -> verifySchema env t-        $ someTables--    -- removes each column which is valid for use by rel8, as well as each table-    -- which contains only valid columns-    filterErrors :: [TableInfo] -> Maybe [TableInfo]-    filterErrors tables = case mapMaybe go tables of-        [] -> Nothing-        xs -> Just xs-      where-        go :: TableInfo -> Maybe TableInfo-        go TableInfo {..} = case P.filter (\cd -> isJust cd.error) columns of-            [] -> if tableExists then Nothing else Just $ TableInfo { name , tableExists , columns = [] }-            xs -> Just $ TableInfo { name , tableExists , columns = xs }-        go DuplicateNames {..} = Just (DuplicateNames {..})--
− src/Rel8/Table/Window.hs
@@ -1,120 +0,0 @@-{-# language ApplicativeDo #-}-{-# language FlexibleContexts #-}-{-# language MonoLocalBinds #-}-{-# language NamedFieldPuns #-}--module Rel8.Table.Window-  ( currentRow-  , lag, lagOn-  , lead, leadOn-  , firstValue, firstValueOn-  , lastValue, lastValueOn-  , nthValue, nthValueOn-  )-where---- base-import Data.Int (Int32)-import Prelude hiding (null)---- opaleye-import qualified Opaleye.Window as Opaleye---- profunctor-import Data.Profunctor (dimap, lmap)---- rel8-import Rel8.Expr (Expr)-import Rel8.Expr.Null (null, nullify, snull)-import Rel8.Expr.Serialize (litExpr)-import Rel8.Expr.Window-  ( lagExpr, lagExprOn-  , leadExpr, leadExprOn-  , firstValueExpr-  , lastValueExpr-  , nthValueExpr, nthValueExprOn-  )-import Rel8.Schema.HTable (htraverseP)-import Rel8.Schema.HTable.Identity (HIdentity (HIdentity))-import Rel8.Schema.HTable.Label (hlabel)-import Rel8.Schema.HTable.Maybe (HMaybeTable (HMaybeTable))-import Rel8.Schema.HTable.Nullify (hnullify)-import Rel8.Schema.Null (Nullity (NotNull, Null))-import Rel8.Schema.Spec (Spec (..))-import Rel8.Table (Table, fromColumns, toColumns)-import Rel8.Table.Maybe (MaybeTable)-import Rel8.Type.Tag (MaybeTag (IsJust))-import Rel8.Window (Window (Window))----- | Return every column of the current row of a window query.-currentRow :: Window a a-currentRow = Window $ Opaleye.over (Opaleye.noWindowFunction id) mempty mempty----- | @'lag' n@ returns the row @n@ rows before the current row in a given--- window. Returns 'Rel8.nothingTable' if @n@ is out of bounds.-lag :: Table Expr a => Expr Int32 -> Window a (MaybeTable Expr a)-lag n = do-  htag <- lagExprOn n null (\_ -> nullify (litExpr IsJust))-  hjust <- lmap toColumns $ hnullify $ \Spec {info, nullity} ->-    case nullity of-      NotNull -> lagExprOn n (snull info) nullify-      Null -> lagExpr n (snull info)-  pure $ fromColumns $ HMaybeTable (hlabel (HIdentity htag)) (hlabel hjust)----- | Applies 'lag' to the columns selected by the given function.-lagOn :: Table Expr a => Expr Int32 -> (i -> a) -> Window i (MaybeTable Expr a)-lagOn n f = lmap f (lag n)----- | @'lead' n@ returns the row @n@ rows after the current row in a given--- window. Returns 'Rel8.nothingTable' if @n@ is out of bounds.-lead :: Table Expr a => Expr Int32 -> Window a (MaybeTable Expr a)-lead n = do-  htag <- leadExprOn n null (\_ -> nullify (litExpr IsJust))-  hjust <- lmap toColumns $ hnullify $ \Spec {info, nullity} ->-    case nullity of-      NotNull -> leadExprOn n (snull info) nullify-      Null -> leadExpr n (snull info)-  pure $ fromColumns $ HMaybeTable (hlabel (HIdentity htag)) (hlabel hjust)----- | Applies 'lead' to the columns selected by the given function.-leadOn :: Table Expr a => Expr Int32 -> (i -> a) -> Window i (MaybeTable Expr a)-leadOn n f = lmap f (lead n)----- | 'firstValue' returns the first row of the window of the current row.-firstValue :: Table Expr a => Window a a-firstValue = dimap toColumns fromColumns $ htraverseP firstValueExpr----- | Applies 'firstValue' to the columns selected by the given function.-firstValueOn :: Table Expr a => (i -> a) -> Window i a-firstValueOn f = lmap f firstValue----- | 'lastValue' returns the first row of the window of the current row.-lastValue :: Table Expr a => Window a a-lastValue = dimap toColumns fromColumns $ htraverseP lastValueExpr----- | Applies 'lastValue' to the columns selected by the given function.-lastValueOn :: Table Expr a => (i -> a) -> Window i a-lastValueOn f = lmap f lastValue----- | @'nthValue' n@ returns the @n@th row of the window of the current row.--- Returns 'Rel8.nothingTable' if @n@ is out of bounds.-nthValue :: Table Expr a => Expr Int32 -> Window a (MaybeTable Expr a)-nthValue n = do-  htag <- nthValueExprOn n (\_ -> litExpr IsJust)-  hjust <- lmap toColumns $ hnullify $ \_ -> nthValueExpr n-  pure $ fromColumns $ HMaybeTable (hlabel (HIdentity htag)) (hlabel hjust)----- | Applies 'nthValue' to the columns selected by the given function.-nthValueOn :: Table Expr a => Expr Int32 -> (i -> a) -> Window i (MaybeTable Expr a)-nthValueOn n f = lmap f (nthValue n)
src/Rel8/Tabulate.hs view
@@ -53,7 +53,7 @@ where  -- base-import Control.Applicative ( (<|>), empty, liftA2 )+import Control.Applicative ( (<|>), empty ) import Control.Monad ( liftM2 ) import Data.Bifunctor ( Bifunctor, bimap, first, second ) import Data.Foldable ( traverse_ )@@ -84,41 +84,41 @@ import qualified Data.Profunctor.Product as PP  -- rel8-import Rel8.Aggregate (Aggregator' (Aggregator), Aggregator, toAggregator1)-import Rel8.Aggregate.Fold (Fallback (Fallback))-import Rel8.Expr ( Expr )-import Rel8.Expr.Aggregate (countStar)-import Rel8.Expr.Bool ( true )-import Rel8.Order ( Order( Order ) )-import Rel8.Query ( Query )-import qualified Rel8.Query.Aggregate as Q-import qualified Rel8.Query.Exists as Q ( exists, present, absent )-import Rel8.Query.Filter ( where_ )-import Rel8.Query.List ( catNonEmptyTable )-import qualified Rel8.Query.Materialize as Q-import qualified Rel8.Query.Maybe as Q ( optional )-import Rel8.Query.Opaleye ( mapOpaleye, unsafePeekQuery )-import Rel8.Query.Rebind ( rebind )-import Rel8.Query.These ( alignBy )-import Rel8.Table ( Table, fromColumns, toColumns )-import Rel8.Table.Aggregate (groupBy, listAgg, nonEmptyAgg)-import Rel8.Table.Alternative+import Rel8.Internal.Aggregate (Aggregator' (Aggregator), Aggregator, toAggregator1)+import Rel8.Internal.Aggregate.Fold (Fallback (Fallback))+import Rel8.Internal.Expr ( Expr )+import Rel8.Internal.Expr.Aggregate (countStar)+import Rel8.Internal.Expr.Bool ( true )+import Rel8.Internal.Order ( Order( Order ) )+import Rel8.Internal.Query ( Query )+import qualified Rel8.Internal.Query.Aggregate as Q+import qualified Rel8.Internal.Query.Exists as Q ( exists, present, absent )+import Rel8.Internal.Query.Filter ( where_ )+import Rel8.Internal.Query.List ( catNonEmptyTable )+import qualified Rel8.Internal.Query.Materialize as Q+import qualified Rel8.Internal.Query.Maybe as Q ( optional )+import Rel8.Internal.Query.Opaleye ( mapOpaleye, unsafePeekQuery )+import Rel8.Internal.Query.Rebind ( rebind )+import Rel8.Internal.Query.These ( alignBy )+import Rel8.Internal.Table ( Table, fromColumns, toColumns )+import Rel8.Internal.Table.Aggregate (groupBy, listAgg, nonEmptyAgg)+import Rel8.Internal.Table.Alternative   ( AltTable, (<|>:)   , AlternativeTable, emptyTable   )-import Rel8.Table.Eq (EqTable, (==:))-import Rel8.Table.List (ListTable)-import Rel8.Table.Maybe (MaybeTable (MaybeTable), fromMaybeTable)-import Rel8.Table.NonEmpty (NonEmptyTable)-import Rel8.Table.Opaleye ( unpackspec )-import Rel8.Table.Ord ( OrdTable )-import Rel8.Table.Order ( ascTable )-import Rel8.Table.Projection+import Rel8.Internal.Table.Eq (EqTable, (==:))+import Rel8.Internal.Table.List (ListTable)+import Rel8.Internal.Table.Maybe (MaybeTable (MaybeTable), fromMaybeTable)+import Rel8.Internal.Table.NonEmpty (NonEmptyTable)+import Rel8.Internal.Table.Opaleye ( unpackspec )+import Rel8.Internal.Table.Ord ( OrdTable )+import Rel8.Internal.Table.Order ( ascTable )+import Rel8.Internal.Table.Projection   ( Biprojectable, biproject   , Projectable, project   , apply   )-import Rel8.Table.These ( TheseTable( TheseTable ), theseTable )+import Rel8.Internal.Table.These ( TheseTable( TheseTable ), theseTable )  -- semigroupoids import Data.Functor.Apply ( Apply, liftF2 )
− src/Rel8/Type.hs
@@ -1,560 +0,0 @@-{-# language DisambiguateRecordFields #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language LambdaCase #-}-{-# language MonoLocalBinds #-}-{-# language MultiWayIf #-}-{-# language OverloadedStrings #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language UndecidableInstances #-}--module Rel8.Type-  ( DBType (typeInformation)-  )-where---- aeson-import Data.Aeson ( Value )-import qualified Data.Aeson as Aeson-import qualified Data.Aeson.Text as Aeson---- attoparsec-import qualified Data.Attoparsec.ByteString.Char8 as A---- base-import Control.Applicative ((<|>))-import Data.Fixed (Fixed)-import Data.Functor.Contravariant ((>$<))-import Data.Int (Int16, Int32, Int64)-import Data.List.NonEmpty ( NonEmpty )-import Data.Kind ( Constraint, Type )-import Prelude-import Text.Read (readMaybe)---- bytestring-import Data.ByteString (ByteString)-import qualified Data.ByteString as BS-import qualified Data.ByteString.Char8 as BS8-import qualified Data.ByteString.Lazy as Lazy ( ByteString )-import qualified Data.ByteString.Lazy as ByteString ( fromStrict, toStrict )-import qualified Data.ByteString.Builder as B-import Data.ByteString.Builder.Prim (primBounded)---- case-insensitive-import Data.CaseInsensitive ( CI )-import qualified Data.CaseInsensitive as CI---- hasql-import qualified Hasql.Decoders as Decoders-import qualified Hasql.Encoders as Encoders---- iproute-import Data.IP (IPRange)---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye-import qualified Opaleye.Internal.HaskellDB.Sql.Default as Opaleye ( quote )---- rel8-import Rel8.Schema.Null ( NotNull, Sql, nullable )-import Rel8.Type.Array ( listTypeInformation, nonEmptyTypeInformation )-import Rel8.Type.Decimal (PowerOf10, resolution)-import Rel8.Type.Decoder (Decoder (..))-import Rel8.Type.Encoder (Encoder (..))-import Rel8.Type.Information ( TypeInformation(..), mapTypeInformation )-import Rel8.Type.Name (TypeName (..))-import Rel8.Type.Parser (parse)-import qualified Rel8.Type.Builder.ByteString as Builder-import qualified Rel8.Type.Parser.ByteString as Parser-import qualified Rel8.Type.Builder.Time as Builder-import qualified Rel8.Type.Parser.Time as Parser---- scientific-import Data.ByteString.Builder.Scientific (scientificBuilder)-import Data.Scientific (Scientific)---- text-import Data.Text ( Text )-import qualified Data.Text as Text-import qualified Data.Text.Encoding as Text (decodeUtf8, encodeUtf8Builder)-import qualified Data.Text.Lazy as Lazy (Text, unpack)-import qualified Data.Text.Lazy as Text (fromStrict, toStrict)---- time-import Data.Time.Calendar (Day)-import Data.Time.Clock (DiffTime, UTCTime)-import Data.Time.LocalTime-  ( CalendarDiffTime (CalendarDiffTime)-  , LocalTime-  , TimeOfDay-  )-import Data.Time.Format (formatTime, defaultTimeLocale)---- utf8-import qualified Data.ByteString.UTF8 as UTF8---- uuid-import Data.UUID ( UUID )-import qualified Data.UUID as UUID----- | Haskell types that can be represented as expressions in a database. There--- should be an instance of @DBType@ for all column types in your database--- schema (e.g., @int@, @timestamptz@, etc).--- --- Rel8 comes with stock instances for most default types in PostgreSQL, so you--- should only need to derive instances of this class for custom database--- types, such as types defined in PostgreSQL extensions, or custom domain--- types.-type DBType :: Type -> Constraint-class NotNull a => DBType a where-  typeInformation :: TypeInformation a----- | Corresponds to @bool@-instance DBType Bool where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.bool-          , text = \case-              False -> "f"-              True -> "t"-          , quote = Opaleye.ConstExpr . Opaleye.BoolLit-          }-    , decode =-        Decoder-          { binary = Decoders.bool-          , text = \case-              "t" -> pure True-              "f" -> pure False-              input -> Left $ "bool: bad bool " <> show input-          }-    , delimiter = ','-    , typeName = "bool"-    }----- | Corresponds to @char@-instance DBType Char where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.char-          , text = B.charUtf8-          , quote = Opaleye.ConstExpr . Opaleye.StringLit . pure-          }-    , decode = -        Decoder-          { binary = Decoders.char-          , text = \input -> case UTF8.uncons input of-              Just (char, rest) | BS.null rest -> pure char-              _ -> Left $ "char: bad char " <> show input-          }-    , delimiter = ','-    , typeName =-        TypeName-          { name = "bpchar"-          , modifiers = ["1"]-          , arrayDepth = 0-          }-    }----- | Corresponds to @int2@-instance DBType Int16 where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.int2-          , text = B.int16Dec-          , quote = Opaleye.ConstExpr . Opaleye.IntegerLit . toInteger-          }-    , decode =-        Decoder-          { binary = Decoders.int2-          , text = parse (A.signed A.decimal)-          }-    , delimiter = ','-    , typeName = "int2"-    }----- | Corresponds to @int4@-instance DBType Int32 where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.int4-          , text = B.int32Dec-          , quote = Opaleye.ConstExpr . Opaleye.IntegerLit . toInteger-          }-    , decode =-        Decoder-          { binary = Decoders.int4-          , text = parse (A.signed A.decimal)-          }-    , delimiter = ','-    , typeName = "int4"-    }----- | Corresponds to @int8@-instance DBType Int64 where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.int8-          , text = B.int64Dec-          , quote = Opaleye.ConstExpr . Opaleye.IntegerLit . toInteger-          }-    , decode =-        Decoder-          { binary = Decoders.int8-          , text = parse (A.signed A.decimal)-          }-    , delimiter = ','-    , typeName = "int8"-    }----- | Corresponds to @float4@ and @real@-instance DBType Float where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.float4-          , text =-              \x ->-                if | x == (1 / 0)  -> "Infinity"-                   | isNaN x       -> "NaN"-                   | x == (-1 / 0) -> "-Infinity"-                   | otherwise     -> B.floatDec x-          , quote =-              \x -> Opaleye.ConstExpr-                if | x == (1 / 0)  -> Opaleye.OtherLit "'Infinity'"-                   | isNaN x       -> Opaleye.OtherLit "'NaN'"-                   | x == (-1 / 0) -> Opaleye.OtherLit "'-Infinity'"-                   | otherwise     -> Opaleye.DoubleLit $ realToFrac x-          }-    , decode =-        Decoder-          { binary = Decoders.float4-          , text = parse (floating (realToFrac <$> A.double))-          }-    , delimiter = ','-    , typeName = "float4"-    }----- | Corresponds to @float8@ and @double precision@-instance DBType Double where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.float8-          , text =-              \x ->-                if | x == (1 / 0)  -> "Infinity"-                   | isNaN x       -> "NaN"-                   | x == (-1 / 0) -> "-Infinity"-                   | otherwise     -> B.doubleDec x-          , quote =-              \x -> Opaleye.ConstExpr-                if | x == (1 / 0)  -> Opaleye.OtherLit "'Infinity'"-                   | isNaN x       -> Opaleye.OtherLit "'NaN'"-                   | x == (-1 / 0) -> Opaleye.OtherLit "'-Infinity'"-                   | otherwise     -> Opaleye.DoubleLit x-          }-    , decode =-        Decoder-          { binary = Decoders.float8-          , text = parse (floating A.double)-          }-    , delimiter = ','-    , typeName = "float8"-    }----- | Corresponds to @numeric@-instance DBType Scientific where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.numeric-          , text = scientificBuilder-          , quote = Opaleye.ConstExpr . Opaleye.NumericLit-          }-    , decode =-        Decoder-          { binary = Decoders.numeric-          , text = parse A.scientific-          }-    , delimiter = ','-    , typeName = "numeric"-    }----- | Corresponds to @numeric(1000, log₁₀ n)@-instance PowerOf10 n => DBType (Fixed n) where-  typeInformation =-    mapTypeInformation realToFrac realToFrac (typeInformation @Scientific)-      { typeName =-          TypeName-            { name = "numeric"-            , modifiers = ["1000", show (resolution @n)]-            , arrayDepth = 0-            }-      }----- | Corresponds to @timestamptz@-instance DBType UTCTime where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.timestamptz-          , text = primBounded Builder.utcTime-          , quote =-              Opaleye.ConstExpr . Opaleye.OtherLit .-              formatTime defaultTimeLocale "'%FT%T%QZ'"-          }-    , decode =-        Decoder-          { binary = Decoders.timestamptz-          , text = parse Parser.utcTime-          }-    , delimiter = ','-    , typeName = "timestamptz"-    }----- | Corresponds to @date@-instance DBType Day where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.date-          , text = primBounded Builder.day-          , quote =-              Opaleye.ConstExpr . Opaleye.OtherLit .-              formatTime defaultTimeLocale "'%F'"-          }-    , decode =-        Decoder-          { binary = Decoders.date-          , text = parse Parser.day-          }-    , delimiter = ','-    , typeName = "date"-    }----- | Corresponds to @timestamp@-instance DBType LocalTime where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.timestamp-          , text = primBounded Builder.localTime-          , quote =-              Opaleye.ConstExpr . Opaleye.OtherLit .-              formatTime defaultTimeLocale "'%FT%T%Q'"-          }-    , decode =-        Decoder-          { binary = Decoders.timestamp-          , text = parse Parser.localTime-          }-    , delimiter = ','-    , typeName = "timestamp"-    }----- | Corresponds to @time@-instance DBType TimeOfDay where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.time-          , text = primBounded Builder.timeOfDay-          , quote =-              Opaleye.ConstExpr . Opaleye.OtherLit .-              formatTime defaultTimeLocale "'%T%Q'"-          }-    , decode =-        Decoder-          { binary = Decoders.time-          , text = parse Parser.timeOfDay-          }-    , delimiter = ','-    , typeName = "time"-    }----- | Corresponds to @interval@-instance DBType CalendarDiffTime where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = toDiffTime >$< Encoders.interval-          , text = Builder.calendarDiffTime-          , quote =-              Opaleye.ConstExpr . Opaleye.OtherLit .-              formatTime defaultTimeLocale "'%bmon %0Es'"-          }-    , decode =-        Decoder-          { binary = CalendarDiffTime 0 . realToFrac <$> Decoders.interval-          , text = parse Parser.calendarDiffTime-          }-    , delimiter = ','-    , typeName = "interval"-    }----- | Corresponds to @text@-instance DBType Text where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.text-          , text = Text.encodeUtf8Builder-          , quote = Opaleye.ConstExpr . Opaleye.StringLit . Text.unpack-          }-    , decode =-        Decoder-          { binary = Decoders.text-          , text = pure . Text.decodeUtf8-          }-    , delimiter = ','-    , typeName = "text"-    }----- | Corresponds to @text@-instance DBType Lazy.Text where-  typeInformation =-    mapTypeInformation Text.fromStrict Text.toStrict typeInformation----- | Corresponds to @citext@-instance DBType (CI Text) where-  typeInformation = mapTypeInformation CI.mk CI.original typeInformation-    { typeName = "citext"-    }----- | Corresponds to @citext@-instance DBType (CI Lazy.Text) where-  typeInformation = mapTypeInformation CI.mk CI.original typeInformation-    { typeName = "citext"-    }----- | Corresponds to @bytea@-instance DBType ByteString where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.bytea-          , text = Builder.bytestring-          , quote = Opaleye.ConstExpr . Opaleye.ByteStringLit-          }-    , decode =-        Decoder-          { binary = Decoders.bytea-          , text = parse Parser.bytestring-          }-    , delimiter = ','-    , typeName = "bytea"-    }----- | Corresponds to @bytea@-instance DBType Lazy.ByteString where-  typeInformation =-    mapTypeInformation ByteString.fromStrict ByteString.toStrict-      typeInformation----- | Corresponds to @uuid@-instance DBType UUID where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.uuid-          , text = B.byteString . UUID.toASCIIBytes-          , quote = Opaleye.ConstExpr . Opaleye.StringLit . UUID.toString-          }-    , decode =-        Decoder-          { binary = Decoders.uuid-          , text = \input -> case UUID.fromASCIIBytes input of-              Just a -> pure a-              Nothing -> Left $ "uuid: bad UUID " <> show input-          }-    , delimiter = ','-    , typeName = "uuid"-    }----- | Corresponds to @jsonb@-instance DBType Value where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.jsonb-          , text = Aeson.fromEncoding . Aeson.toEncoding-          , quote =-              Opaleye.ConstExpr . Opaleye.OtherLit . Opaleye.quote .-              Lazy.unpack . Aeson.encodeToLazyText-          }-    , decode =-        Decoder-          { binary = Decoders.jsonb-          , text = Aeson.eitherDecodeStrict-          }-    , delimiter = ','-    , typeName = "jsonb"-    }----- | Corresponds to @inet@-instance DBType IPRange where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = Encoders.inet-          , text = B.string7 . show-          , quote = Opaleye.ConstExpr . Opaleye.StringLit . show-          }-    , decode =-        Decoder-          { binary = Decoders.inet-          , text = \str -> case readMaybe $ BS8.unpack str of-              Just x -> Right x-              Nothing -> Left "Failed to parse inet"-          }-    , delimiter = ','-    , typeName = "inet"-    }---instance Sql DBType a => DBType [a] where-  typeInformation = listTypeInformation nullable typeInformation---instance Sql DBType a => DBType (NonEmpty a) where-  typeInformation = nonEmptyTypeInformation nullable typeInformation---floating :: Floating a => A.Parser a -> A.Parser a-floating p = p <|> A.signed (1.0 / 0 <$ "Infinity") <|> 0.0 / 0 <$ "NaN"---toDiffTime :: CalendarDiffTime -> DiffTime-toDiffTime (CalendarDiffTime months seconds) =-  realToFrac (months * 30 * 24 * 60 * 60) + realToFrac seconds
− src/Rel8/Type/Array.hs
@@ -1,260 +0,0 @@-{-# language DisambiguateRecordFields #-}-{-# language GADTs #-}-{-# language LambdaCase #-}-{-# language NamedFieldPuns #-}-{-# language OverloadedStrings #-}-{-# language TypeApplications #-}-{-# language ViewPatterns #-}--module Rel8.Type.Array-  ( array, quoteArrayElement, extractArrayElement-  , arrayTypeName-  , listTypeInformation-  , nonEmptyTypeInformation-  , head, index, last, length-  )-where---- attoparsec-import qualified Data.Attoparsec.ByteString.Char8 as A---- base-import Control.Applicative ((<|>), many)-import Data.Bifunctor (first)-import Data.Foldable (fold, toList)-import Data.Functor.Contravariant ((>$<))-import Data.List.NonEmpty (NonEmpty, nonEmpty)-import Prelude hiding (head, last, length, null, repeat, zipWith)---- bytestring-import Data.ByteString (ByteString)-import Data.ByteString.Builder (Builder, toLazyByteString)-import qualified Data.ByteString.Builder as B-import qualified Data.ByteString.Char8 as BS-import qualified Data.ByteString.Lazy as L---- case-insensitive-import qualified Data.CaseInsensitive as CI---- hasql-import qualified Hasql.Decoders as Decoders-import qualified Hasql.Encoders as Encoders---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Schema.Null (Unnullify, Nullity (Null, NotNull))-import Rel8.Type.Builder.Fold (interfoldMap)-import Rel8.Type.Decoder (Decoder (..), Parser)-import Rel8.Type.Encoder (Encoder (..))-import Rel8.Type.Information (TypeInformation(..), parseTypeInformation)-import Rel8.Type.Name (TypeName (..), showTypeName)-import Rel8.Type.Nullable (NullableOrNot (..))-import Rel8.Type.Parser (parse)---- text-import qualified Data.Text as Text-import qualified Data.Text.Lazy as Text (toStrict)-import qualified Data.Text.Lazy.Encoding as Lazy (decodeUtf8)---array :: Foldable f-  => TypeInformation a -> f Opaleye.PrimExpr -> Opaleye.PrimExpr-array info =-  Opaleye.CastExpr (showTypeName (arrayType info) <> "[]") .-  Opaleye.ArrayExpr . map (quoteArrayElement info) . toList-{-# INLINABLE array #-}---listTypeInformation :: ()-  => Nullity a-  -> TypeInformation (Unnullify a)-  -> TypeInformation [a]-listTypeInformation nullity info@TypeInformation {decode, encode, delimiter} =-  TypeInformation-    { decode =-        Decoder-          { binary = Decoders.listArray $ case nullity of-              Null -> Decoders.nullable (decodeArrayElement info decode)-              NotNull -> Decoders.nonNullable (decodeArrayElement info decode)-          , text = case nullity of-              Null -> arrayParser delimiter (Nullable decode)-              NotNull -> arrayParser delimiter (NonNullable decode)-          }-    , encode =-        Encoder-          { binary = Encoders.foldableArray $ case nullity of-              Null -> Encoders.nullable (encodeArrayElement info encode)-              NotNull -> Encoders.nonNullable (encodeArrayElement info encode)-          , text = case nullity of-              Null -> arrayBuild delimiter (Nullable encode)-              NotNull -> arrayBuild delimiter (NonNullable encode)-          , quote = case nullity of-              Null ->-                Opaleye.ArrayExpr .-                fmap (quoteArrayElement info . maybe null (quote encode))-              NotNull ->-                Opaleye.ArrayExpr .-                fmap (quoteArrayElement info . quote encode)-          }-    , delimiter = ','-    , typeName = arrayTypeName info-    }-  where-    null = Opaleye.ConstExpr Opaleye.NullLit---nonEmptyTypeInformation :: ()-  => Nullity a-  -> TypeInformation (Unnullify a)-  -> TypeInformation (NonEmpty a)-nonEmptyTypeInformation nullity =-  parseTypeInformation fromList toList . listTypeInformation nullity-  where-    fromList = maybe (Left message) Right . nonEmpty-    message = "failed to decode NonEmptyList: got empty list"---arrayTypeName :: TypeInformation a -> TypeName-arrayTypeName info = (arrayType info) {arrayDepth = 1}---isArray :: TypeInformation a -> Bool-isArray = (> 0) . arrayDepth . typeName---arrayType :: TypeInformation a -> TypeName-arrayType info-  | isArray info = "text"-  | otherwise = typeName info---decodeArrayElement :: TypeInformation a -> Decoder x -> Decoders.Value x-decodeArrayElement info Decoder {binary, text}-  | isArray info =-      Decoders.refine (first Text.pack . text) Decoders.bytea-  | otherwise = binary---encodeArrayElement :: TypeInformation a -> Encoder x -> Encoders.Value x-encodeArrayElement info Encoder {binary, text}-  | isArray info = Text.toStrict . Lazy.decodeUtf8 . toLazyByteString . text >$< Encoders.text-  | otherwise = binary---quoteArrayElement :: TypeInformation a -> Opaleye.PrimExpr -> Opaleye.PrimExpr-quoteArrayElement info-  | isArray info = Opaleye.CastExpr "text" . Opaleye.CastExpr (showTypeName (typeName info))-  | otherwise = id---extractArrayElement :: TypeInformation a -> Opaleye.PrimExpr -> Opaleye.PrimExpr-extractArrayElement info-  | isArray info = Opaleye.CastExpr (showTypeName (typeName info))-  | otherwise = id---parseArray :: Char -> ByteString -> Either String [Maybe ByteString]-parseArray delimiter = parse $ do-  A.char '{' *> A.sepBy element (A.char delimiter) <* A.char '}'-  where-    element = null <|> nonNull-      where-        null = Nothing <$ A.string "NULL"-        nonNull = Just <$> (quoted <|> unquoted)-          where-            unquoted = A.takeWhile1 (A.notInClass (delimiter : "\"{}"))-            quoted = A.char '"' *> contents <* A.char '"'-              where-                contents = fold <$> many (unquote <|> unescape)-                  where-                    unquote = A.takeWhile1 (A.notInClass "\"\\")-                    unescape = A.char '\\' *> do-                      BS.singleton <$> do-                        A.char '\\' <|> A.char '"'---arrayParser :: Char -> NullableOrNot Decoder a -> Parser [a]-arrayParser delimiter = \case-  Nullable Decoder {text} -> \input -> do-    elements <- parseArray delimiter input-    traverse (traverse text) elements-  NonNullable Decoder {text} -> \input -> do-    elements <- parseArray delimiter input-    traverse (maybe (Left "array: unexpected null") text) elements---buildArray :: Char -> [Maybe ByteString] -> Builder-buildArray delimiter elements =-  B.char8 '{' <>-  interfoldMap (B.char8 delimiter) element elements <>-  B.char8 '}'-  where-    element = \case-      Nothing -> B.string7 "NULL"-      Just a-        | BS.null a -> "\"\""-        | CI.mk a == "null" -> escaped-        | BS.any (A.inClass escapeClass) a -> escaped-        | otherwise -> unescaped-        where-          escapeClass = delimiter : "\\\"{}\t\n"-          unescaped = B.byteString a-          escaped =-            B.char8 '"' <> BS.foldr ((<>) . escape) mempty a <> B.char8 '"'-            where-              escape = \case-                '"' -> B.string7 "\\\""-                '\\' -> B.string7 "\\\\"-                c -> B.char8 c---arrayBuild :: Char -> NullableOrNot Encoder a -> [a] -> Builder-arrayBuild delimiter = \case-  Nullable Encoder {text} ->-    buildArray delimiter .-    map (fmap (L.toStrict . toLazyByteString . text))-  NonNullable Encoder {text} ->-    buildArray delimiter .-    map (Just . L.toStrict . toLazyByteString . text)---head :: TypeInformation a -> Opaleye.PrimExpr -> Opaleye.PrimExpr-head info a = extractArrayElement info $ subscript (lower a) a---last :: TypeInformation a -> Opaleye.PrimExpr -> Opaleye.PrimExpr-last info a = extractArrayElement info $ subscript (upper a) a---subscript :: Opaleye.PrimExpr -> Opaleye.PrimExpr -> Opaleye.PrimExpr-subscript i a = Opaleye.ArrayIndex a i---index :: TypeInformation a -> Opaleye.PrimExpr -> Opaleye.PrimExpr -> Opaleye.PrimExpr-index info i a = extractArrayElement info $ subscript (plus (lower a) i) a---lower :: Opaleye.PrimExpr -> Opaleye.PrimExpr-lower a = Opaleye.FunExpr "array_lower" [a, one]---upper :: Opaleye.PrimExpr -> Opaleye.PrimExpr-upper a = Opaleye.FunExpr "array_lower" [a, one]---length :: Opaleye.PrimExpr -> Opaleye.PrimExpr-length a = Opaleye.FunExpr "coalesce" [Opaleye.FunExpr "array_length" [a, one], zero]---one :: Opaleye.PrimExpr-one = Opaleye.ConstExpr (Opaleye.IntegerLit 1)---zero :: Opaleye.PrimExpr-zero = Opaleye.ConstExpr (Opaleye.IntegerLit 0)---plus :: Opaleye.PrimExpr -> Opaleye.PrimExpr -> Opaleye.PrimExpr-plus = Opaleye.BinExpr (Opaleye.:+)
− src/Rel8/Type/Builder/ByteString.hs
@@ -1,16 +0,0 @@-{-# language OverloadedStrings #-}--module Rel8.Type.Builder.ByteString (-  bytestring,-) where---- base-import Prelude---- bytestring-import Data.ByteString (ByteString)-import Data.ByteString.Builder (Builder, byteStringHex, string7)---bytestring :: ByteString -> Builder-bytestring bytes = string7 "\\x" <> byteStringHex bytes
− src/Rel8/Type/Builder/Fold.hs
@@ -1,16 +0,0 @@-{-# language LambdaCase #-}--module Rel8.Type.Builder.Fold (-  interfoldMap-) where---- base-import Prelude---interfoldMap :: (Foldable t, Monoid m) => m -> (a -> m) -> t a -> m-interfoldMap sep f = maybe mempty id . foldr go Nothing-  where-    go x = \case-      Nothing -> Just (f x)-      Just acc -> Just (f x <> sep <> acc)
− src/Rel8/Type/Builder/Time.hs
@@ -1,151 +0,0 @@-{-# language BangPatterns #-}-{-# language NumericUnderscores #-}-{-# language OverloadedStrings #-}-{-# language PatternSynonyms #-}-{-# language PartialTypeSignatures #-}-{-# language TypeApplications #-}-{-# language ViewPatterns #-}--{-# options_ghc -Wno-partial-type-signatures #-}--- bytestring does not export Monoidal so we can't write a complete type--- signature for 'divide'--{-# options_ghc -Wno-unused-top-binds #-}--- GHC considers the YMD pattern unused but we use its selectors--module Rel8.Type.Builder.Time (-  calendarDiffTime,-  day,-  localTime,-  timeOfDay,-  utcTime,-) where---- base-import Data.Char (chr)-import Data.Fixed (Fixed (MkFixed), Pico)-import Data.Int (Int32, Int64)-import Prelude hiding ((<>))---- bytestring-import Data.ByteString.Builder (Builder, string7)-import Data.ByteString.Builder.Prim (-  BoundedPrim, condB, emptyB, liftFixedToBounded,-  FixedPrim, char8, int32Dec,-  (>$<), (>*<),- )---- time-import Data.Time.Calendar (Day, toGregorian)-import Data.Time.Clock (UTCTime (utctDay, utctDayTime))-import Data.Time.Format.ISO8601 (iso8601Show)-import Data.Time.LocalTime (-  CalendarDiffTime,-  LocalTime (localDay, localTimeOfDay),-  TimeOfDay (todHour, todMin, todSec),-  timeToTimeOfDay- )---digit :: FixedPrim Int-digit = (\x -> chr (x + 48)) >$< char8---digits2 :: FixedPrim Int-digits2 = divide (`quotRem` 10) digit digit---digits3 :: FixedPrim Int-digits3 = divide (`quotRem` 10) digits2 digit---digits4 :: FixedPrim Int-digits4 = divide (`quotRem` 10) digits3 digit---frac :: BoundedPrim Int64-frac = condB (== 0) emptyB $ liftFixedToBounded (char '.') <> trunc12-  where-    trunc12 =-      divide-        (`quotRem` 1_000_000)-        (fromIntegral >$< ifZero trunc6 (liftFixedToBounded digits6))-        (fromIntegral >$< nonZero trunc6)--    digitB = liftFixedToBounded digit--    digits6 = divide (`quotRem` 10) digits5 digit-    digits5 = divide (`quotRem` 10) digits4 digit--    trunc6 = divide (`quotRem` 100_000) digitB trunc5-    trunc5 = nonZero $ divide (`quotRem` 10_000) digitB trunc4-    trunc4 = nonZero $ divide (`quotRem` 1_000) digitB trunc3-    trunc3 = nonZero $ divide (`quotRem` 100) digitB trunc2-    trunc2 = nonZero $ divide (`quotRem` 10) digitB trunc1-    trunc1 = nonZero digitB--    nonZero = ifZero emptyB-    ifZero = condB (== 0)---seconds :: BoundedPrim Pico-seconds =-  (\(MkFixed s) -> fromIntegral s `quotRem` 1_000_000_000_000) >$<-  (liftFixedToBounded (fromIntegral >$< digits2) >*< frac)---year :: BoundedPrim Int32-year = condB (>= 10000) int32Dec (liftFixedToBounded (fromIntegral >$< digits4))---day :: BoundedPrim Day-day =-  (fromIntegral . ymdYear >$< year) <>-  liftFixedToBounded-    ( char '-' <> (ymdMonth >$< digits2) <> char '-' <> (ymdDay >$< digits2)-    )---pattern YMD :: Integer -> Int -> Int -> Day-pattern YMD {ymdYear, ymdMonth, ymdDay} <--  (toGregorian -> (ymdYear, ymdMonth, ymdDay))---timeOfDay :: BoundedPrim TimeOfDay-timeOfDay =-  liftFixedToBounded-    ( (todHour >$< digits2) <> char ':' <> (todMin >$< digits2) <> char ':'-    ) <>-  (todSec >$< seconds)---utcTime :: BoundedPrim UTCTime-utcTime =-  (utctDay >$< day) <>-  liftFixedToBounded (char ' ') <>-  (timeToTimeOfDay . utctDayTime >$< timeOfDay) <>-  liftFixedToBounded (char 'Z')---localTime :: BoundedPrim LocalTime-localTime =-  (localDay >$< day) <>-  liftFixedToBounded (char ' ') <>-  (localTimeOfDay >$< timeOfDay)---calendarDiffTime :: CalendarDiffTime -> Builder-calendarDiffTime = string7 . iso8601Show---char :: Char -> FixedPrim a-char c = (\_ -> c) >$< char8---(<>) :: _ => f a -> f a -> f a-(<>) = divide (\a -> (a, a))-infixr 6 <>---divide :: _ => (a -> (b, c)) -> f b -> f c -> f a-divide f a b = f >$< (a >*< b)
− src/Rel8/Type/Composite.hs
@@ -1,263 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language BlockArguments #-}-{-# language DataKinds #-}-{-# language DisambiguateRecordFields #-}-{-# language FlexibleContexts #-}-{-# language GADTs #-}-{-# language LambdaCase #-}-{-# language NamedFieldPuns #-}-{-# language OverloadedStrings #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language UndecidableInstances #-}-{-# language UndecidableSuperClasses #-}-{-# language ViewPatterns #-}--module Rel8.Type.Composite-  ( Composite( Composite )-  , DBComposite( compositeFields, compositeTypeName )-  , compose, decompose-  )-where---- attoparsec-import qualified Data.Attoparsec.ByteString.Char8 as A---- base-import Control.Applicative ((<|>), many, optional)-import Data.Foldable (fold)-import Data.Functor.Const (Const (Const), getConst)-import Data.Functor.Contravariant ((>$<))-import Data.Functor.Identity (Identity (Identity), runIdentity)-import Data.Kind ( Constraint, Type )-import Data.List (uncons)-import Prelude---- bytestring-import Data.ByteString (ByteString)-import qualified Data.ByteString.Char8 as BS-import Data.ByteString.Builder (Builder)-import Data.ByteString.Builder (toLazyByteString)-import qualified Data.ByteString.Builder as B-import Data.ByteString.Lazy (toStrict)---- hasql-import qualified Hasql.Decoders as Decoders-import qualified Hasql.Encoders as Encoders---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Opaleye ( castExpr, fromPrimExpr, toPrimExpr )-import Rel8.Schema.HTable ( HTable, hfield, hspecs, htabulate, htabulateA )-import Rel8.Schema.Name ( Name( Name ) )-import Rel8.Schema.Null ( Nullity( Null, NotNull ) )-import Rel8.Schema.QualifiedName (QualifiedName)-import Rel8.Schema.Result ( Result )-import Rel8.Schema.Spec ( Spec( Spec, nullity, info ) )-import Rel8.Table ( fromColumns, toColumns, fromResult, toResult )-import Rel8.Table.Eq ( EqTable )-import Rel8.Table.HKD ( HKD, HKDable )-import Rel8.Table.Ord ( OrdTable )-import Rel8.Table.Rel8able ()-import Rel8.Table.Serialize ( litHTable )-import Rel8.Type ( DBType, typeInformation )-import Rel8.Type.Builder.Fold (interfoldMap)-import Rel8.Type.Decoder (Decoder (Decoder), Parser)-import qualified Rel8.Type.Decoder as Decoder-import Rel8.Type.Encoder (Encoder (Encoder))-import qualified Rel8.Type.Encoder as Encoder-import Rel8.Type.Eq ( DBEq )-import Rel8.Type.Information ( TypeInformation(..) )-import Rel8.Type.Name (TypeName (..))-import Rel8.Type.Ord ( DBOrd, DBMax, DBMin )-import Rel8.Type.Parser (parse)---- semigroupoids-import Data.Functor.Apply ( WrappedApplicative(..) )---- transformers-import Control.Monad.Trans.Class (lift)-import Control.Monad.Trans.State.Strict (StateT (StateT), runStateT)----- | A deriving-via helper type for column types that store a Haskell product--- type in a single Postgres column using a Postgres composite type.------ Note that this must map to a specific extant type in your database's schema--- (created with @CREATE TYPE@). Use 'DBComposite' to specify the name of this--- Postgres type and the names of the individual fields (for projecting with--- 'decompose').-type Composite :: Type -> Type-newtype Composite a = Composite-  { unComposite :: a-  }---instance DBComposite a => DBType (Composite a) where-  typeInformation = TypeInformation-    { decode =-        Decoder-          { binary = Decoders.composite (Composite . fromResult @_ @(HKD a Expr) <$> decoder)-          , text = fmap (Composite . fromResult @_ @(HKD a Expr)) . parser-          }-    , encode =-        Encoder-          { binary = Encoders.composite (toResult @_ @(HKD a Expr) . unComposite >$< encoder)-          , text = builder . toResult @_ @(HKD a Expr) . unComposite-          , quote = quoter . litHTable . toResult @_ @(HKD a Expr) . unComposite-          }-    , delimiter = ','-    , typeName =-        TypeName-          { name = compositeTypeName @a-          , modifiers = []-          , arrayDepth = 0-          }-    }---instance (DBComposite a, EqTable (HKD a Expr)) => DBEq (Composite a)---instance (DBComposite a, OrdTable (HKD a Expr)) => DBOrd (Composite a)---instance (DBComposite a, OrdTable (HKD a Expr)) => DBMax (Composite a)---instance (DBComposite a, OrdTable (HKD a Expr)) => DBMin (Composite a)----- | 'DBComposite' is used to associate composite type metadata with a Haskell--- type.-type DBComposite :: Type -> Constraint-class (DBType a, HKDable a) => DBComposite a where-  -- | The names of all fields in the composite type that @a@ maps to.-  compositeFields :: HKD a Name--  -- | The name of the composite type that @a@ maps to.-  compositeTypeName :: QualifiedName----- | Collapse a 'HKD' into a PostgreSQL composite type.------ 'HKD' values are represented in queries by having a column for each field in--- the corresponding Haskell type. 'compose' collapses these columns into a--- single column expression, by combining them into a PostgreSQL composite--- type.-compose :: DBComposite a => HKD a Expr -> Expr a-compose = castExpr . fromPrimExpr . quoter . toColumns----- | Expand a composite type into a 'HKD'.------ 'decompose' is the inverse of 'compose'.-decompose :: forall a. DBComposite a => Expr a -> HKD a Expr-decompose (toPrimExpr -> a) = fromColumns $ htabulate \field ->-  case hfield names field of-    Name name -> case hfield hspecs field of-      Spec {} -> fromPrimExpr $ Opaleye.CompositeExpr a name-  where-    names = toColumns (compositeFields @a)---decoder :: HTable t => Decoders.Composite (t Result)-decoder = unwrapApplicative $ htabulateA \field ->-  case hfield hspecs field of-    Spec {nullity, info} -> WrapApplicative $ Identity <$>-      case nullity of-        Null -> Decoders.field $ Decoders.nullable $ Decoder.binary $ decode info-        NotNull -> Decoders.field $ Decoders.nonNullable $ Decoder.binary $ decode info---parser :: HTable t => Parser (t Result)-parser input = do-  fields <- parseRow input-  (a, rest) <- runStateT go fields-  case rest of-    [] -> pure a-    _ -> Left "composite: too many fields"-  where-    go = htabulateA \field -> do-      mbytes <- StateT $ maybe missing pure . uncons-      lift $ Identity <$> case hfield hspecs field of-        Spec {nullity, info} -> case nullity of-          Null -> traverse (Decoder.text (decode info)) mbytes-          NotNull -> case mbytes of-            Nothing -> Left "composite: unexpected null"-            Just bytes -> Decoder.text (decode info) bytes-    missing = Left "composite: missing fields"---parseRow :: ByteString -> Either String [Maybe ByteString]-parseRow = parse $ do-  A.char '(' *> A.sepBy element (A.char ',') <* A.char ')'-  where-    element = optional (quoted <|> unquoted)-      where-        unquoted = A.takeWhile1 (A.notInClass ",\"()")-        quoted = A.char '"' *> contents <* A.char '"'-          where-            contents = fold <$> many (unquote <|> unescape <|> quote)-              where-                unquote = A.takeWhile1 (A.notInClass "\"\\")-                unescape = A.char '\\' *> do-                  BS.singleton <$> do-                    A.char '\\' <|> A.char '"'-                quote = "\"" <$ A.string "\"\""---encoder :: forall t. HTable t => Encoders.Composite (t Result)-encoder = getConst $ htabulateA @t \field ->-  case hfield hspecs field of-    Spec {nullity, info} -> Const $-      runIdentity . (`hfield` field) >$<-        case nullity of-          Null -> Encoders.field $ Encoders.nullable build-          NotNull -> Encoders.field $ Encoders.nonNullable build-        where-          build = Encoder.binary (encode info)---builder :: HTable t => t Result -> Builder-builder input = buildRow $ getConst $ htabulateA \field ->-  Const $ pure $-    case hfield input field of-      Identity a ->-        case hfield hspecs field of-          Spec {nullity, info} -> case nullity of-            Null -> build <$> a-            NotNull -> Just $ build a-            where-              build =-                toStrict . toLazyByteString . Encoder.text (encode info)---buildRow :: [Maybe ByteString] -> Builder-buildRow elements =-  B.char8 '(' <>-  interfoldMap (B.char8 ',') (foldMap element) elements <>-  B.char8 ')'-  where-    element a-        | BS.null a = "\"\""-        | BS.all (A.notInClass escapeClass) a = B.byteString a-        | otherwise =-            B.char8 '"' <> BS.foldr ((<>) . escape) mempty a <> B.char8 '"'-        where-          escapeClass = ",\\\"()\t\n"-          escape = \case-            '"' -> B.string7 "\"\""-            '\\' -> B.string7 "\\\\"-            c -> B.char8 c---quoter :: HTable t => t Expr -> Opaleye.PrimExpr-quoter a = Opaleye.FunExpr "ROW" exprs-  where-    exprs = getConst $ htabulateA \field -> case hfield a field of-      expr -> Const [toPrimExpr expr]
− src/Rel8/Type/Decimal.hs
@@ -1,103 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language ConstraintKinds #-}-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language NoStarIsType #-}-{-# language PolyKinds #-}-{-# language RankNTypes #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Type.Decimal-  ( PowerOf10-  , resolution-  )-where---- base-import Data.Fixed (E0, E1, E2, E3, E6, E9, E12, HasResolution)-import Data.Proxy (Proxy (Proxy))-import Data.Type.Equality (type (==))-import Data.Type.Ord (type (<?))-import Data.Kind (Constraint)-import GHC.TypeLits (ErrorMessage ((:<>:), ShowType, Text), TypeError)-import GHC.TypeNats (KnownNat, Nat, type (+), type (-), type (*), Div, natVal)-import Numeric.Natural (Natural)-import Prelude---type PowerOf10 :: a -> Constraint-class (HasResolution n, KnownNat (Log n)) => PowerOf10 n where-  type Log n :: Nat---instance (KnownNat n, KnownNat (Log n), IsPowerOf10 n) => PowerOf10 n where-  type Log n = Log10 n---instance PowerOf10 E0 where-  type Log E0 = 0---instance PowerOf10 E1 where-  type Log E1 = 1---instance PowerOf10 E2 where-  type Log E2 = 2---instance PowerOf10 E3 where-  type Log E3 = 3---instance PowerOf10 E6 where-  type Log E6 = 6---instance PowerOf10 E9 where-  type Log E9 = 9---instance PowerOf10 E12 where-  type Log E12 = 12---resolution :: forall n. PowerOf10 n => Natural-resolution = natVal (Proxy @(Log n))---type Exp10 :: Nat -> Nat-type Exp10 n = Exp10' 1 n---type Exp10' :: Nat -> Nat -> Nat-type family Exp10' x n where-  Exp10' x 0 = x-  Exp10' x n = Exp10' (x * 10) (n - 1)---type Log10 :: Nat -> Nat-type Log10 n = Log10' (n <? 10) n---type Log10' :: Bool -> Nat -> Nat-type family Log10' bool n where-  Log10' 'True _n = 0-  Log10' 'False n = 1 + Log10 (Div n 10)---type IsPowerOf10 :: Nat -> Constraint-type IsPowerOf10 n = IsPowerOf10' (Exp10 (Log10 n) == n) n---type IsPowerOf10' :: Bool -> Nat -> Constraint-type family IsPowerOf10' bool n where-  IsPowerOf10' 'True _n = ()-  IsPowerOf10' 'False n =-    TypeError ('ShowType n ' :<>: 'Text " is not a power of 10")
− src/Rel8/Type/Decoder.hs
@@ -1,54 +0,0 @@-{-# language DerivingStrategies #-}-{-# language DeriveFunctor #-}-{-# language NamedFieldPuns #-}-{-# language StandaloneKindSignatures #-}-{-# language DuplicateRecordFields #-}--module Rel8.Type.Decoder (-  Decoder (..),-  Parser,-  parseDecoder,-) where---- base-import Control.Monad ((>=>))-import Data.Bifunctor (first)-import Data.Kind (Type)-import Prelude---- bytestring-import Data.ByteString (ByteString)---- hasql-import qualified Hasql.Decoders as Hasql---- text-import qualified Data.Text as Text---type Parser :: Type -> Type-type Parser a = ByteString -> Either String a---type Decoder :: Type -> Type-data Decoder a = Decoder-  { binary :: Hasql.Value a-    -- ^ How to deserialize from PostgreSQL's binary format.-  , text :: Parser a-    -- ^ How to deserialize from PostgreSQL's text format.-  }-  deriving stock (Functor)----- | Apply a parser to 'Decoder'.------ This can be used if the data stored in the database should only be subset of--- a given 'Decoder'. The parser is applied when deserializing rows--- returned.-parseDecoder :: (a -> Either String b) -> Decoder a -> Decoder b-parseDecoder f Decoder {binary, text} =-  Decoder-    { binary = Hasql.refine (first Text.pack . f) binary-    , text = text >=> f-    }-
− src/Rel8/Type/Encoder.hs
@@ -1,43 +0,0 @@-{-# language LambdaCase #-}-{-# language NamedFieldPuns #-}-{-# language RecordWildCards #-}-{-# language StandaloneKindSignatures #-}-{-# language StrictData #-}-{-# language DuplicateRecordFields #-}--module Rel8.Type.Encoder (-  Encoder (..),-) where---- base-import Data.Functor.Contravariant (Contravariant, (>$<), contramap)-import Data.Kind (Type)-import Prelude---- bytestring-import Data.ByteString.Builder (Builder)---- hasql-import qualified Hasql.Encoders as Hasql---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---type Encoder :: Type -> Type-data Encoder a = Encoder-  { binary :: Hasql.Value a-    -- ^ How to serialize to PostgreSQL's binary format.-  , text :: a -> Builder-    -- ^ How to serialize to PostgreSQL's text format.-  , quote :: a -> Opaleye.PrimExpr-    -- ^ How to encode a single Haskell value as an SQL expression.-  }---instance Contravariant Encoder where-  contramap f Encoder {..} = Encoder-    { binary = f >$< binary-    , text = text . f-    , quote = quote . f-    }
− src/Rel8/Type/Enum.hs
@@ -1,173 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language DataKinds #-}-{-# language DefaultSignatures #-}-{-# language DisambiguateRecordFields #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language LambdaCase #-}-{-# language RankNTypes #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language TypeFamilies #-}-{-# language TypeOperators #-}-{-# language UndecidableInstances #-}--module Rel8.Type.Enum-  ( Enum( Enum )-  , DBEnum( enumValue, enumTypeName, enumerate )-  , Enumable-  )-where---- base-import Control.Applicative ( (<|>) )-import Control.Arrow ( (&&&) )-import Data.Kind ( Constraint, Type )-import Data.Proxy ( Proxy( Proxy ) )-import GHC.Generics-  ( Generic, Rep, from, to-  , (:+:)( L1, R1 ), M1( M1 ), U1( U1 )-  , D, C, Meta( MetaCons )-  )-import GHC.TypeLits ( KnownSymbol, symbolVal )-import Prelude hiding ( Enum )---- hasql-import qualified Hasql.Decoders as Decoders-import qualified Hasql.Encoders as Encoders---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Schema.QualifiedName (QualifiedName)-import Rel8.Type ( DBType, typeInformation )-import Rel8.Type.Decoder (Decoder (..))-import Rel8.Type.Encoder (Encoder (..))-import Rel8.Type.Eq ( DBEq )-import Rel8.Type.Information ( TypeInformation(..) )-import Rel8.Type.Name (TypeName (..))-import Rel8.Type.Ord ( DBOrd, DBMax, DBMin )---- text-import Data.Text (pack)-import Data.Text.Encoding (decodeUtf8, encodeUtf8Builder)----- | A deriving-via helper type for column types that store an \"enum\" type--- (in Haskell terms, a sum type where all constructors are nullary) using a--- Postgres @enum@ type.------ Note that this should map to a specific type in your database's schema--- (explicitly created with @CREATE TYPE ... AS ENUM@). Use 'DBEnum' to--- specify the name of this Postgres type and the names of the individual--- values. If left unspecified, the names of the values of the Postgres--- @enum@ are assumed to match exactly exactly the names of the constructors--- of the Haskell type (up to and including case sensitivity).-type Enum :: Type -> Type-newtype Enum a = Enum-  { unEnum :: a-  }---instance DBEnum a => DBType (Enum a) where-  typeInformation = TypeInformation-    { encode =-        let-          toText (Enum a) = pack $ enumValue a-        in-        Encoder-          { binary = Encoders.enum toText-          , text = encodeUtf8Builder . toText-          , quote =-              Opaleye.ConstExpr .-              Opaleye.StringLit .-              enumValue @a .-              unEnum-          }-    , decode =-        let-          mapping = (pack . enumValue &&& Enum) <$> enumerate-          unrecognised = Left "enum: unrecognised value"-        in-          Decoder-            { binary = Decoders.enum (`lookup` mapping)-            , text = maybe unrecognised pure . (`lookup` mapping) . decodeUtf8-            }-    , delimiter = ','-    , typeName =-        TypeName-          { name = enumTypeName @a-          , modifiers = []-          , arrayDepth = 0-          }-    }---instance DBEnum a => DBEq (Enum a)---instance DBEnum a => DBOrd (Enum a)---instance DBEnum a => DBMax (Enum a)---instance DBEnum a => DBMin (Enum a)----- | @DBEnum@ contains the necessary metadata to describe a PostgreSQL @enum@ type.-type DBEnum :: Type -> Constraint-class DBType a => DBEnum a where-  -- | Map Haskell values to the corresponding element of the @enum@ type. The-  -- default implementation of this method will use the exact name of the-  -- Haskell constructors.-  enumValue :: a -> String--  -- | The name of the PostgreSQL @enum@ type that @a@ maps to.-  enumTypeName :: QualifiedName--  -- | List of all possible values of the enum type.-  enumerate :: [a]--  default enumValue :: Enumable a => a -> String-  enumValue = gshow @(Rep a) . from--  default enumerate :: Enumable a => [a]-  enumerate = to <$> genumerate @(Rep a)----- | Types that are sum types, where each constructor is unary (that is, has no--- fields).-type Enumable :: Type -> Constraint-class (Generic a, GEnumable (Rep a)) => Enumable a-instance (Generic a, GEnumable (Rep a)) => Enumable a---type GEnumable :: (Type -> Type) -> Constraint-class GEnumable rep where-  genumerate :: [rep x]-  gshow :: rep x -> String---instance GEnumable rep => GEnumable (M1 D meta rep) where-  genumerate = M1 <$> genumerate-  gshow (M1 rep) = gshow rep---instance (GEnumable a, GEnumable b) => GEnumable (a :+: b) where-  genumerate = L1 <$> genumerate <|> R1 <$> genumerate-  gshow = \case-    L1 a -> gshow a-    R1 a -> gshow a---instance-  ( meta ~ 'MetaCons name _fixity _isRecord-  , KnownSymbol name-  )-  => GEnumable (M1 C meta U1)- where-  genumerate = [M1 U1]-  gshow (M1 U1) = symbolVal (Proxy @name)
− src/Rel8/Type/Eq.hs
@@ -1,81 +0,0 @@-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MonoLocalBinds #-}-{-# language MultiParamTypeClasses #-}-{-# language StandaloneKindSignatures #-}-{-# language UndecidableInstances #-}--module Rel8.Type.Eq-  ( DBEq-  )-where---- aeson-import Data.Aeson ( Value )---- base-import Data.Fixed (Fixed)-import Data.Int ( Int16, Int32, Int64 )-import Data.Kind ( Constraint, Type )-import Data.List.NonEmpty ( NonEmpty )-import Prelude---- bytestring-import Data.ByteString ( ByteString )-import qualified Data.ByteString.Lazy as Lazy ( ByteString )---- case-insensitive-import Data.CaseInsensitive ( CI )---- rel8-import Rel8.Schema.Null ( Sql )-import Rel8.Type ( DBType )-import Rel8.Type.Decimal (PowerOf10)---- scientific-import Data.Scientific ( Scientific )---- text-import Data.Text ( Text )-import qualified Data.Text.Lazy as Lazy ( Text )---- time-import Data.Time.Calendar ( Day )-import Data.Time.Clock ( UTCTime )-import Data.Time.LocalTime ( CalendarDiffTime, LocalTime, TimeOfDay )---- uuid-import Data.UUID ( UUID )----- | Database types that can be compared for equality in queries. If a type is--- an instance of 'DBEq', it means we can compare expressions for equality--- using the SQL @=@ operator.-type DBEq :: Type -> Constraint-class DBType a => DBEq a---instance DBEq Bool-instance DBEq Char-instance DBEq Int16-instance DBEq Int32-instance DBEq Int64-instance PowerOf10 n => DBEq (Fixed n)-instance DBEq Float-instance DBEq Double-instance DBEq Scientific-instance DBEq UTCTime-instance DBEq Day-instance DBEq LocalTime-instance DBEq TimeOfDay-instance DBEq CalendarDiffTime-instance DBEq Text-instance DBEq Lazy.Text-instance DBEq (CI Text)-instance DBEq (CI Lazy.Text)-instance DBEq ByteString-instance DBEq Lazy.ByteString-instance DBEq UUID-instance DBEq Value-instance Sql DBEq a => DBEq [a]-instance Sql DBEq a => DBEq (NonEmpty a)
− src/Rel8/Type/Information.hs
@@ -1,67 +0,0 @@-{-# language GADTs #-}-{-# language NamedFieldPuns #-}-{-# language StandaloneKindSignatures #-}-{-# language StrictData #-}--module Rel8.Type.Information (-  TypeInformation(..),-  mapTypeInformation,-  parseTypeInformation,-) where---- base-import Data.Functor.Contravariant ((>$<))-import Data.Kind (Type)-import Prelude---- rel8-import Rel8.Type.Decoder (Decoder, parseDecoder)-import Rel8.Type.Encoder (Encoder)-import Rel8.Type.Name (TypeName)----- | @TypeInformation@ describes how to encode and decode a Haskell type to and--- from database queries. The @typeName@ is the name of the type in the--- database, which is used to accurately type literals. -type TypeInformation :: Type -> Type-data TypeInformation a = TypeInformation-  { encode :: Encoder a-    -- ^ How to serialize a Haskell value to PostgreSQL.-  , decode :: Decoder a-    -- ^ How to deserialize a PostgreSQL result back to Haskell.-  , delimiter :: Char-    -- ^ The delimiter that is used in PostgreSQL's text format in arrays of-    -- this type (this is almost always ',').-  , typeName :: TypeName-    -- ^ The name of the SQL type.-  }- ---- | Simultaneously map over how a type is both encoded and decoded, while--- retaining the name of the type. This operation is useful if you want to--- essentially @newtype@ another 'Rel8.DBType'.--- --- The mapping is required to be total. If you have a partial mapping, see--- 'parseTypeInformation'.-mapTypeInformation :: ()-  => (a -> b) -> (b -> a)-  -> TypeInformation a -> TypeInformation b-mapTypeInformation = parseTypeInformation . fmap pure----- | Apply a parser to 'TypeInformation'.--- --- This can be used if the data stored in the database should only be subset of--- a given 'TypeInformation'. The parser is applied when deserializing rows--- returned - the encoder assumes that the input data is already in the--- appropriate form.-parseTypeInformation :: ()-  => (a -> Either String b) -> (b -> a)-  -> TypeInformation a -> TypeInformation b-parseTypeInformation to from TypeInformation {encode, decode, delimiter, typeName} =-  TypeInformation-    { decode = parseDecoder to decode-    , encode = from >$< encode-    , delimiter-    , typeName-    }
− src/Rel8/Type/JSONBEncoded.hs
@@ -1,67 +0,0 @@-{-# language DisambiguateRecordFields #-}-{-# language OverloadedStrings #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Type.JSONBEncoded (-  JSONBEncoded(..),-) where---- aeson-import Data.Aeson (FromJSON, ToJSON, eitherDecodeStrict, parseJSON, toJSON)-import qualified Data.Aeson as Aeson-import qualified Data.Aeson.Text as Aeson-import Data.Aeson.Types (parseEither)---- base-import Data.Bifunctor ( first )-import Data.Functor.Contravariant ((>$<))-import Data.Kind ( Type )-import Prelude---- hasql-import qualified Hasql.Decoders as Decoders-import qualified Hasql.Encoders as Encoders---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye-import qualified Opaleye.Internal.HaskellDB.Sql.Default as Opaleye (quote)---- rel8-import Rel8.Type ( DBType(..) )-import Rel8.Type.Decoder (Decoder (..))-import Rel8.Type.Encoder (Encoder (..))-import Rel8.Type.Information ( TypeInformation(..) )---- text-import Data.Text ( pack )-import Data.Text.Lazy (unpack)----- | Like 'Rel8.JSONEncoded', but works for @jsonb@ columns.-type JSONBEncoded :: Type -> Type-newtype JSONBEncoded a = JSONBEncoded { fromJSONBEncoded :: a }-  deriving (Show, Eq, Ord)---instance (FromJSON a, ToJSON a) => DBType (JSONBEncoded a) where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = toJSON . fromJSONBEncoded >$< Encoders.jsonb-          , text = Aeson.fromEncoding . Aeson.toEncoding . fromJSONBEncoded-          , quote =-              Opaleye.ConstExpr . Opaleye.OtherLit .-              Opaleye.quote .-              unpack . Aeson.encodeToLazyText . fromJSONBEncoded-          }-    , decode =-        Decoder-          { binary =-              Decoders.refine-                (first pack . fmap JSONBEncoded . parseEither parseJSON)-                Decoders.jsonb-          , text = fmap JSONBEncoded . eitherDecodeStrict-          }-    , delimiter = ','-    , typeName = "jsonb"-    }
− src/Rel8/Type/JSONEncoded.hs
@@ -1,69 +0,0 @@-{-# language DisambiguateRecordFields #-}-{-# language StandaloneKindSignatures #-}-{-# language OverloadedStrings #-}-{-# language TypeApplications #-}--module Rel8.Type.JSONEncoded (-  JSONEncoded(..),-) where---- aeson-import Data.Aeson (FromJSON, ToJSON, eitherDecodeStrict, parseJSON, toJSON)-import qualified Data.Aeson as Aeson-import qualified Data.Aeson.Text as Aeson-import Data.Aeson.Types (parseEither)---- base-import Data.Bifunctor (first)-import Data.Functor.Contravariant ((>$<))-import Data.Kind ( Type )-import Prelude---- hasql-import qualified Hasql.Decoders as Decoders-import qualified Hasql.Encoders as Encoders---- rel8-import Rel8.Type ( DBType(..) )-import Rel8.Type.Decoder (Decoder (..))-import Rel8.Type.Encoder (Encoder (..))-import Rel8.Type.Information ( TypeInformation(..) )---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye-import qualified Opaleye.Internal.HaskellDB.Sql.Default as Opaleye ( quote )---- text-import Data.Text (pack)-import Data.Text.Lazy (unpack)----- | A deriving-via helper type for column types that store a Haskell value--- using a JSON encoding described by @aeson@'s 'ToJSON' and 'FromJSON' type--- classes.-type JSONEncoded :: Type -> Type-newtype JSONEncoded a = JSONEncoded { fromJSONEncoded :: a }-  deriving (Show, Eq, Ord)---instance (FromJSON a, ToJSON a) => DBType (JSONEncoded a) where-  typeInformation = TypeInformation-    { encode =-        Encoder-          { binary = toJSON . fromJSONEncoded >$< Encoders.json-          , text = Aeson.fromEncoding . Aeson.toEncoding . fromJSONEncoded-          , quote =-              Opaleye.ConstExpr . Opaleye.OtherLit . Opaleye.quote .-              unpack . Aeson.encodeToLazyText . fromJSONEncoded-          }-    , decode =-        Decoder-          { binary =-              Decoders.refine-                (first pack . fmap JSONEncoded . parseEither parseJSON)-                Decoders.json-          , text = fmap JSONEncoded . eitherDecodeStrict-          }-    , delimiter = ','-    , typeName = "json"-    }
− src/Rel8/Type/Monoid.hs
@@ -1,79 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language OverloadedStrings #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}-{-# language UndecidableInstances #-}--module Rel8.Type.Monoid-  ( DBMonoid( memptyExpr )-  )-where---- base-import Data.Kind ( Constraint, Type )-import Prelude hiding ( null )---- bytestring-import Data.ByteString ( ByteString )-import qualified Data.ByteString.Lazy as Lazy ( ByteString )---- case-insensitive-import Data.CaseInsensitive ( CI )---- rel8-import {-# SOURCE #-} Rel8.Expr ( Expr )-import Rel8.Expr.Array ( sempty )-import Rel8.Expr.Serialize ( litExpr )-import Rel8.Schema.Null ( Sql )-import Rel8.Type ( DBType, typeInformation )-import Rel8.Type.Semigroup ( DBSemigroup )---- text-import Data.Text ( Text )-import qualified Data.Text.Lazy as Lazy ( Text )---- time-import Data.Time.LocalTime ( CalendarDiffTime( CalendarDiffTime ) )----- | The class of 'Rel8.DBType's that form a semigroup. This class is purely a--- Rel8 concept, and exists to mirror the 'Monoid' class.-type DBMonoid :: Type -> Constraint-class DBSemigroup a => DBMonoid a where-  -- The identity for '<>.'-  memptyExpr :: Expr a---instance Sql DBType a => DBMonoid [a] where-  memptyExpr = sempty typeInformation---instance DBMonoid CalendarDiffTime where-  memptyExpr = litExpr (CalendarDiffTime 0 0)---instance DBMonoid Text where-  memptyExpr = litExpr ""---instance DBMonoid Lazy.Text where-  memptyExpr = litExpr ""---instance DBMonoid (CI Text) where-  memptyExpr = litExpr ""---instance DBMonoid (CI Lazy.Text) where-  memptyExpr = litExpr ""---instance DBMonoid ByteString where-  memptyExpr = litExpr ""---instance DBMonoid Lazy.ByteString where-  memptyExpr = litExpr ""
− src/Rel8/Type/Name.hs
@@ -1,58 +0,0 @@-{-# language RecordWildCards #-}-{-# language StrictData #-}--module Rel8.Type.Name-  ( TypeName (..)-  , showTypeName-  )-where---- base-import Data.Semigroup (mtimesDefault)-import Data.String (IsString, fromString)-import Prelude---- pretty-import Text.PrettyPrint (Doc, comma, hcat, parens, punctuate, text)---- rel8-import Rel8.Schema.QualifiedName (QualifiedName, ppQualifiedName)----- | A PostgreSQL type consists of a 'QualifiedName' (name, schema), and--- optional 'modifiers' and 'arrayDepth'. 'modifiers' will usually be @[]@,--- but a type like @numeric(6, 2)@ will have @["6", "2"]@. 'arrayDepth' is--- always @0@ for non-array types.-data TypeName = TypeName-  { name :: QualifiedName-    -- ^ The name (and schema) of the type.-  , modifiers :: [String]-    -- ^ Any modifiers applied to the underlying type.-  , arrayDepth :: Word-    -- ^ If this is an array type, the depth of that array (@1@ for @[]@, @2@-    -- for @[][]@, etc).-  }----- | Constructs 'TypeName's with 'schema' set to 'Nothing', 'modifiers' set--- to @[]@ and 'arrayDepth' set to @0@.-instance IsString TypeName where-  fromString string =-    TypeName-      { name = fromString string-      , modifiers = []-      , arrayDepth = 0-      }---ppTypeName :: TypeName -> Doc-ppTypeName TypeName {..} =-  ppQualifiedName name <> modifier <> mtimesDefault arrayDepth (text "[]")-  where-    modifier-      | null modifiers = mempty-      | otherwise = parens (hcat $ punctuate comma $ text <$> modifiers)---showTypeName :: TypeName -> String-showTypeName = show . ppTypeName
− src/Rel8/Type/Nullable.hs
@@ -1,16 +0,0 @@-{-# language GADTs #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Type.Nullable (-  NullableOrNot (..),-) where---- base-import Data.Kind (Type)-import Prelude---type NullableOrNot :: (Type -> Type) -> Type -> Type-data NullableOrNot decoder a where-  NonNullable :: decoder a -> NullableOrNot decoder a-  Nullable :: decoder a -> NullableOrNot decoder (Maybe a)
− src/Rel8/Type/Num.hs
@@ -1,65 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}-{-# language UndecidableInstances #-}--module Rel8.Type.Num-  ( DBNum, DBIntegral, DBFractional, DBFloating-  )-where---- base-import Data.Fixed (Fixed)-import Data.Int ( Int16, Int32, Int64 )-import Data.Kind ( Constraint, Type )-import Prelude---- rel8-import Rel8.Type ( DBType )-import Rel8.Type.Decimal (PowerOf10)-import Rel8.Type.Ord ( DBOrd )---- scientific-import Data.Scientific ( Scientific )----- | The class of database types that support the @+@, @*@, @-@ operators, and--- the @abs@, @negate@, @sign@ functions.-type DBNum :: Type -> Constraint-class DBType a => DBNum a-instance DBNum Int16-instance DBNum Int32-instance DBNum Int64-instance PowerOf10 n => DBNum (Fixed n)-instance DBNum Float-instance DBNum Double-instance DBNum Scientific----- | The class of database types that can be coerced to from integral--- expressions. This is a Rel8 concept, and allows us to provide--- 'Rel8.Expr.Num.fromIntegral'.-type DBIntegral :: Type -> Constraint-class (DBNum a, DBOrd a) => DBIntegral a-instance DBIntegral Int16-instance DBIntegral Int32-instance DBIntegral Int64----- | The class of database types that support the @/@ operator.-type DBFractional :: Type -> Constraint-class DBNum a => DBFractional a-instance PowerOf10 n => DBFractional (Fixed n)-instance DBFractional Float-instance DBFractional Double-instance DBFractional Scientific----- | The class of database types that support the @/@ operator.-type DBFloating :: Type -> Constraint-class DBFractional a => DBFloating a-instance DBFloating Float-instance DBFloating Double
− src/Rel8/Type/Ord.hs
@@ -1,127 +0,0 @@-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MonoLocalBinds #-}-{-# language MultiParamTypeClasses #-}-{-# language StandaloneKindSignatures #-}-{-# language UndecidableInstances #-}--module Rel8.Type.Ord-  ( DBOrd-  , DBMax, DBMin-  )-where---- base-import Data.Fixed (Fixed)-import Data.Int ( Int16, Int32, Int64 )-import Data.Kind ( Constraint, Type )-import Data.List.NonEmpty ( NonEmpty )-import Prelude---- bytestring-import Data.ByteString ( ByteString )-import qualified Data.ByteString.Lazy as Lazy ( ByteString )---- case-insensitive-import Data.CaseInsensitive ( CI )---- rel8-import Rel8.Schema.Null ( Sql )-import Rel8.Type.Decimal (PowerOf10)-import Rel8.Type.Eq ( DBEq )---- scientific-import Data.Scientific ( Scientific )---- text-import Data.Text ( Text )-import qualified Data.Text.Lazy as Lazy ( Text )---- time-import Data.Time.Calendar ( Day )-import Data.Time.Clock ( UTCTime )-import Data.Time.LocalTime ( CalendarDiffTime, LocalTime, TimeOfDay )---- uuid-import Data.UUID ( UUID )----- | The class of database types that support the @<@, @<=@, @>@ and @>=@--- operators.-type DBOrd :: Type -> Constraint-class DBEq a => DBOrd a-instance DBOrd Bool-instance DBOrd Char-instance DBOrd Int16-instance DBOrd Int32-instance DBOrd Int64-instance PowerOf10 n => DBOrd (Fixed n)-instance DBOrd Float-instance DBOrd Double-instance DBOrd Scientific-instance DBOrd UTCTime-instance DBOrd Day-instance DBOrd LocalTime-instance DBOrd TimeOfDay-instance DBOrd CalendarDiffTime-instance DBOrd Text-instance DBOrd Lazy.Text-instance DBOrd (CI Text)-instance DBOrd (CI Lazy.Text)-instance DBOrd ByteString-instance DBOrd Lazy.ByteString-instance DBOrd UUID-instance Sql DBOrd a => DBOrd [a]-instance Sql DBOrd a => DBOrd (NonEmpty a)----- | The class of database types that support the @max@ aggregation function.-type DBMax :: Type -> Constraint-class DBOrd a => DBMax a-instance DBMax Char-instance DBMax Int16-instance DBMax Int32-instance DBMax Int64-instance PowerOf10 n => DBMax (Fixed n)-instance DBMax Float-instance DBMax Double-instance DBMax Scientific-instance DBMax UTCTime-instance DBMax Day-instance DBMax LocalTime-instance DBMax TimeOfDay-instance DBMax CalendarDiffTime-instance DBMax Text-instance DBMax Lazy.Text-instance DBMax (CI Text)-instance DBMax (CI Lazy.Text)-instance DBMax ByteString-instance DBMax Lazy.ByteString-instance Sql DBMax a => DBMax [a]-instance Sql DBMax a => DBMax (NonEmpty a)----- | The class of database types that support the @min@ aggregation function.-type DBMin :: Type -> Constraint-class DBOrd a => DBMin a-instance DBMin Char-instance DBMin Int16-instance DBMin Int32-instance DBMin Int64-instance PowerOf10 n => DBMin (Fixed n)-instance DBMin Float-instance DBMin Double-instance DBMin Scientific-instance DBMin UTCTime-instance DBMin Day-instance DBMin LocalTime-instance DBMin TimeOfDay-instance DBMin CalendarDiffTime-instance DBMin Text-instance DBMin Lazy.Text-instance DBMin (CI Text)-instance DBMin (CI Lazy.Text)-instance DBMin ByteString-instance DBMin Lazy.ByteString-instance Sql DBMin a => DBMin [a]-instance Sql DBMin a => DBMin (NonEmpty a)
− src/Rel8/Type/Parser.hs
@@ -1,17 +0,0 @@-module Rel8.Type.Parser-  ( parse-  )-where---- attoparsec-import qualified Data.Attoparsec.ByteString as A---- base-import Prelude---- bytestring-import Data.ByteString (ByteString)---parse :: A.Parser a -> ByteString -> Either String a-parse parser = A.parseOnly (parser <* A.endOfInput)
− src/Rel8/Type/Parser/ByteString.hs
@@ -1,54 +0,0 @@-{-# language OverloadedStrings #-}-{-# language TypeApplications #-}--module Rel8.Type.Parser.ByteString-  ( bytestring-  )-where---- attoparsec-import qualified Data.Attoparsec.ByteString.Char8 as A---- base-import Control.Applicative ((<|>), many)-import Control.Monad (guard)-import Data.Bits ((.|.), shiftL)-import Data.Char (isOctDigit)-import Data.Foldable (fold)-import Prelude---- base16-import Data.ByteString.Base16 (decodeBase16Untyped)---- bytestring-import Data.ByteString (ByteString)-import qualified Data.ByteString.Char8 as BS---- text-import qualified Data.Text as Text---bytestring :: A.Parser ByteString-bytestring = hex <|> escape-  where-    hex = do-      digits <- "\\x" *> A.takeByteString-      either (fail . Text.unpack) pure $ decodeBase16Untyped digits-    escape = fold <$> many (escaped <|> unescaped)-      where-        unescaped = A.takeWhile1 (/= '\\')-        escaped = BS.singleton <$> (backslash <|> octal)-          where-            backslash = '\\' <$ "\\\\"-            octal = do-              a <- A.char '\\' *> digit-              b <- digit-              c <- digit-              let-                result = a `shiftL` 6 .|. b `shiftL` 3 .|. c-              guard $ result < 0o400-              pure $ toEnum result-              where-                digit = do-                  c <- A.satisfy isOctDigit-                  pure $ fromEnum c - fromEnum '0'
− src/Rel8/Type/Parser/Time.hs
@@ -1,156 +0,0 @@-{-# language OverloadedStrings #-}-{-# language TypeApplications #-}--module Rel8.Type.Parser.Time-  ( calendarDiffTime-  , day-  , localTime-  , timeOfDay-  , utcTime-  )-where---- attoparsec-import qualified Data.Attoparsec.ByteString.Char8 as A---- base-import Control.Applicative ((<|>), optional)-import Data.Bits ((.&.))-import Data.Bool (bool)-import Data.Fixed (Fixed (MkFixed), Pico, divMod')-import Data.Functor (void)-import Data.Int (Int64)-import Prelude---- bytestring-import qualified Data.ByteString as BS---- time-import Data.Time.Calendar (Day, addDays, fromGregorianValid)-import Data.Time.Clock (DiffTime, UTCTime (UTCTime))-import Data.Time.Format.ISO8601 (iso8601ParseM)-import Data.Time.LocalTime-  ( CalendarDiffTime (CalendarDiffTime)-  , LocalTime (LocalTime)-  , TimeOfDay (TimeOfDay)-  , sinceMidnight-  )---- utf8-import qualified Data.ByteString.UTF8 as UTF8---day :: A.Parser Day-day = do-  y <- A.decimal <* A.char '-'-  m <- twoDigits <* A.char '-'-  d <- twoDigits-  maybe (fail "Day: invalid date") pure $ fromGregorianValid y m d---timeOfDay :: A.Parser TimeOfDay-timeOfDay = do-  h <- twoDigits-  m <- A.char ':' *> twoDigits-  s <- A.char ':' *> secondsParser-  if h < 24 && m < 60 && s <= 60-    then pure $ TimeOfDay h m s-    else fail "TimeOfDay: invalid time"---localTime :: A.Parser LocalTime-localTime = LocalTime <$> day <* separator <*> timeOfDay-  where-    separator = A.char ' ' <|> A.char 'T'---utcTime :: A.Parser UTCTime-utcTime = do-  LocalTime date time <- localTime-  tz <- timeZone-  let-    (days, time') = (sinceMidnight time + tz) `divMod'` oneDay-      where-        oneDay = 24 * 60 * 60-    date' = addDays days date-  pure $ UTCTime date' time'---calendarDiffTime :: A.Parser CalendarDiffTime-calendarDiffTime = iso8601 <|> postgres-  where-    iso8601 = A.takeByteString >>= iso8601ParseM . UTF8.toString-    at = optional (A.char '@') *> A.skipSpace-    plural unit = A.skipSpace <* (unit <* optional "s") <* A.skipSpace-    parseMonths = sql <|> postgresql-      where-        sql = A.signed $ do-          years <- A.decimal <* A.char '-'-          months <- A.decimal <* A.skipSpace-          pure $ years * 12 + months-        postgresql = do-          at-          years <- A.signed A.decimal <* plural "year" <|> pure 0-          months <- A.signed A.decimal <* plural "mon" <|> pure 0-          pure $ years * 12 + months-    parseTime = (+) <$> parseDays <*> time-      where-        time = realToFrac <$> (sql <|> postgresql)-          where-            sql = A.signed $ do-              h <- A.signed A.decimal <* A.char ':'-              m <- twoDigits <* A.char ':'-              s <- secondsParser-              pure $ fromIntegral (((h * 60) + m) * 60) + s-            postgresql = do-              h <- A.signed A.decimal <* plural "hour" <|> pure 0-              m <- A.signed A.decimal <* plural "min" <|> pure 0-              s <- secondsParser <* plural "sec" <|> pure 0-              pure $ fromIntegral @Int (((h * 60) + m) * 60) + s-        parseDays = do-          days <- A.signed A.decimal <* (plural "days" <|> skipSpace1) <|> pure 0-          pure $ fromIntegral @Int days * 24 * 60 * 60-    postgres = do-      months <- parseMonths-      time <- parseTime-      ago <- (True <$ (A.skipSpace *> "ago")) <|> pure False-      pure $ CalendarDiffTime (bool id negate ago months) (bool id negate ago time)---secondsParser :: A.Parser Pico-secondsParser = do-  integral <- twoDigits-  mfractional <- optional (A.char '.' *> A.takeWhile1 A.isDigit)-  pure $ case mfractional of-    Nothing -> fromIntegral integral-    Just fractional -> parseFraction (fromIntegral integral) fractional- where-  parseFraction integral digits = MkFixed (fromIntegral (n * 10 ^ e))-    where-      e = max 0 (12 - BS.length digits)-      n = BS.foldl' go (integral :: Int64) (BS.take 12 digits)-        where-          go acc digit = 10 * acc + fromIntegral (fromEnum digit .&. 0xf)---twoDigits :: A.Parser Int-twoDigits = do-  u <- A.digit-  l <- A.digit-  pure $ fromEnum u .&. 0xf * 10 + fromEnum l .&. 0xf---timeZone :: A.Parser DiffTime-timeZone = 0 <$ A.char 'Z' <|> diffTime---diffTime :: A.Parser DiffTime-diffTime = A.signed $ do-  h <- twoDigits-  m <- A.char ':' *> twoDigits <|> pure 0-  s <- A.char ':' *> secondsParser <|> pure 0-  pure $ sinceMidnight $ TimeOfDay h m s---skipSpace1 :: A.Parser ()-skipSpace1 = void $ A.takeWhile1 A.isSpace
− src/Rel8/Type/ReadShow.hs
@@ -1,35 +0,0 @@-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}-{-# language ViewPatterns #-}--module Rel8.Type.ReadShow ( ReadShow(..) ) where---- base-import Data.Kind ( Type )-import Data.Proxy ( Proxy( Proxy ) )-import Data.Typeable ( Typeable, typeRep )-import Prelude -import Text.Read ( readMaybe )---- rel8-import Rel8.Type ( DBType( typeInformation ) )-import Rel8.Type.Information ( parseTypeInformation )---- text-import qualified Data.Text as Text----- | A deriving-via helper type for column types that store a Haskell value--- using a Haskell's 'Read' and 'Show' type classes.-type ReadShow :: Type -> Type-newtype ReadShow a = ReadShow { fromReadShow :: a }---instance (Read a, Show a, Typeable a) => DBType (ReadShow a) where-  typeInformation = parseTypeInformation parser printer typeInformation-    where-      parser (Text.unpack -> t) = case readMaybe t of-        Just ok -> Right $ ReadShow ok-        Nothing -> Left $ "Could not read " <> t <> " as a " <> show (typeRep (Proxy @a))-      printer = Text.pack . show . fromReadShow
− src/Rel8/Type/Semigroup.hs
@@ -1,87 +0,0 @@-{-# language BlockArguments #-}-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeFamilies #-}-{-# language UndecidableInstances #-}--module Rel8.Type.Semigroup-  ( DBSemigroup( (<>.))-  )-where---- base-import Data.Kind ( Constraint, Type )-import Data.List.NonEmpty ( NonEmpty )-import Prelude ()---- bytestring-import Data.ByteString ( ByteString )-import qualified Data.ByteString.Lazy as Lazy ( ByteString )---- case-insensitive-import Data.CaseInsensitive ( CI )---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import {-# SOURCE #-} Rel8.Expr ( Expr )-import Rel8.Expr.Array ( sappend, sappend1 )-import Rel8.Expr.Opaleye ( zipPrimExprsWith )-import Rel8.Schema.Null ( Sql )-import Rel8.Type ( DBType )---- text-import Data.Text ( Text )-import qualified Data.Text.Lazy as Lazy ( Text )---- time-import Data.Time.LocalTime ( CalendarDiffTime )----- | The class of 'Rel8.DBType's that form a semigroup. This class is purely a--- Rel8 concept, and exists to mirror the 'Semigroup' class.-type DBSemigroup :: Type -> Constraint-class DBType a => DBSemigroup a where-  -- | An associative operation.-  (<>.) :: Expr a -> Expr a -> Expr a-  infixr 6 <>.---instance Sql DBType a => DBSemigroup [a] where-  (<>.) = sappend---instance Sql DBType a => DBSemigroup (NonEmpty a) where-  (<>.) = sappend1---instance DBSemigroup CalendarDiffTime where-  (<>.) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:+))---instance DBSemigroup Text where-  (<>.) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:||))---instance DBSemigroup Lazy.Text where-  (<>.) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:||))---instance DBSemigroup (CI Text) where-  (<>.) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:||))---instance DBSemigroup (CI Lazy.Text) where-  (<>.) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:||))---instance DBSemigroup ByteString where-  (<>.) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:||))---instance DBSemigroup Lazy.ByteString where-  (<>.) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:||))
− src/Rel8/Type/String.hs
@@ -1,40 +0,0 @@-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language StandaloneKindSignatures #-}-{-# language UndecidableInstances #-}--module Rel8.Type.String-  ( DBString-  )-where---- base-import Data.Kind ( Constraint, Type )-import Prelude ()---- bytestring-import Data.ByteString ( ByteString )-import qualified Data.ByteString.Lazy as Lazy ( ByteString )---- case-insensitive-import Data.CaseInsensitive ( CI )---- rel8-import Rel8.Type ( DBType )---- text-import Data.Text ( Text )-import qualified Data.Text.Lazy as Lazy ( Text )----- | The class of data types that support the @string_agg()@ aggregation--- function.-type DBString :: Type -> Constraint-class DBType a => DBString a-instance DBString Text-instance DBString Lazy.Text-instance DBString (CI Text)-instance DBString (CI Lazy.Text)-instance DBString ByteString-instance DBString Lazy.ByteString
− src/Rel8/Type/Sum.hs
@@ -1,41 +0,0 @@-{-# language DataKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language MultiParamTypeClasses #-}-{-# language TypeFamilies #-}-{-# language StandaloneKindSignatures #-}-{-# language UndecidableInstances #-}--module Rel8.Type.Sum-  ( DBSum-  )-where---- base-import Data.Fixed (Fixed)-import Data.Int ( Int16, Int32, Int64 )-import Data.Kind ( Constraint, Type )-import Prelude---- rel8-import Rel8.Type ( DBType )-import Rel8.Type.Decimal (PowerOf10)---- scientific-import Data.Scientific ( Scientific )---- time-import Data.Time.LocalTime ( CalendarDiffTime )----- | The class of database types that support the @sum()@ aggregation function.-type DBSum :: Type -> Constraint-class DBType a => DBSum a-instance DBSum Int16-instance DBSum Int32-instance DBSum Int64-instance PowerOf10 n => DBSum (Fixed n)-instance DBSum Float-instance DBSum Double-instance DBSum Scientific-instance DBSum CalendarDiffTime
− src/Rel8/Type/Tag.hs
@@ -1,98 +0,0 @@-{-# language DataKinds #-}-{-# language DeriveAnyClass #-}-{-# language DerivingVia #-}-{-# language GeneralizedNewtypeDeriving #-}-{-# language StandaloneKindSignatures #-}--module Rel8.Type.Tag-  ( EitherTag( IsLeft, IsRight ), isLeft, isRight-  , MaybeTag( IsJust )-  , Tag( Tag )-  )-where---- base-import Data.Bool ( bool )-import Data.Kind ( Type )-import Data.Semigroup ( Min( Min ) )-import Prelude---- opaleye-import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye---- rel8-import Rel8.Expr ( Expr )-import Rel8.Expr.Eq ( (==.) )-import Rel8.Expr.Opaleye ( zipPrimExprsWith )-import Rel8.Expr.Serialize ( litExpr )-import Rel8.Type.Eq ( DBEq )-import Rel8.Type ( DBType, typeInformation )-import Rel8.Type.Information ( mapTypeInformation, parseTypeInformation )-import Rel8.Type.Monoid ( DBMonoid, memptyExpr )-import Rel8.Type.Ord ( DBOrd )-import Rel8.Type.Semigroup ( DBSemigroup, (<>.) )---- text-import Data.Text ( Text )---type EitherTag :: Type-data EitherTag = IsLeft | IsRight-  deriving stock (Eq, Ord, Read, Show, Enum, Bounded)-  deriving (Semigroup, Monoid) via (Min EitherTag)-  deriving anyclass (DBEq, DBOrd)---instance DBType EitherTag where-  typeInformation = mapTypeInformation to from typeInformation-    where-      to = bool IsLeft IsRight-      from IsLeft = False-      from IsRight = True---instance DBSemigroup EitherTag where-  (<>.) = zipPrimExprsWith (Opaleye.BinExpr Opaleye.OpAnd)---instance DBMonoid EitherTag where-  memptyExpr = litExpr mempty---isLeft :: Expr EitherTag -> Expr Bool-isLeft = (litExpr IsLeft ==.)---isRight :: Expr EitherTag -> Expr Bool-isRight = (litExpr IsRight ==.)---type MaybeTag :: Type-data MaybeTag = IsJust-  deriving stock (Eq, Ord, Read, Show, Enum, Bounded)-  deriving (Semigroup, Monoid) via (Min MaybeTag)-  deriving anyclass (DBEq, DBOrd)---instance DBType MaybeTag where-  typeInformation = parseTypeInformation to from typeInformation-    where-      to False = Left "MaybeTag can't be false"-      to True = Right IsJust-      from _ = True---instance DBSemigroup MaybeTag where-  (<>.) = zipPrimExprsWith (Opaleye.BinExpr Opaleye.OpAnd)---instance DBMonoid MaybeTag where-  memptyExpr = litExpr mempty---type Tag :: Type-newtype Tag = Tag Text-  deriving newtype-    ( Eq, Ord, Read, Show-    , DBType, DBEq, DBOrd-    )
− src/Rel8/Window.hs
@@ -1,97 +0,0 @@-{-# language DerivingVia #-}-{-# language FlexibleContexts #-}-{-# language GeneralizedNewtypeDeriving #-}-{-# language ScopedTypeVariables #-}-{-# language StandaloneKindSignatures #-}-{-# language TypeApplications #-}--module Rel8.Window-  ( Window(..)-  , Partition-  , over-  , partitionBy-  , orderPartitionBy-  )-where---- base-import Data.Functor.Const ( Const( Const ), getConst )-import Data.Functor.Contravariant ( Contravariant, contramap )-import Data.Kind ( Type )-import Prelude---- opaleye-import qualified Opaleye.Internal.Window as Opaleye-import qualified Opaleye.Internal.PackMap as Opaleye---- profunctors-import Data.Profunctor ( Profunctor )---- product-profunctors-import Data.Profunctor.Product ( ProductProfunctor, (****), purePP )---- rel8-import Rel8.Expr.Opaleye ( toColumn, toPrimExpr )-import Rel8.Order( Order( Order ) )-import Rel8.Schema.HTable ( hfield, htabulateA )-import Rel8.Table ( Columns, toColumns )-import Rel8.Table.Eq ( EqTable )---- semigroupoids-import Data.Functor.Apply ( Apply, WrappedApplicative(..) )----- | 'Window' is an applicative functor that represents expressions that--- contain--- [window functions](https://www.postgresql.org/docs/current/tutorial-window.html).--- 'Rel8.Query.Window.window' can be used to--- evaluate these expressions over a particular query.-type Window :: Type -> Type -> Type-newtype Window a b = Window (Opaleye.Windows a b)-  deriving newtype (Profunctor)-  deriving newtype (Functor, Applicative)-  deriving (Apply) via (WrappedApplicative (Window a))---instance ProductProfunctor Window where-  purePP = pure-  (****) = (<*>)----- | In PostgreSQL, window functions must specify the \"window\" or--- \"partition\" over which they operate. The syntax for this looks like:--- @SUM(salary) OVER (PARTITION BY department)@. The Rel8 type 'Partition'--- represents everything that comes after @OVER@.------ 'Partition' is a 'Monoid', so 'Window's created with 'partitionBy' and--- 'orderWindowBy' can be combined using '<>'.-type Partition :: Type -> Type-newtype Partition a = Partition (Opaleye.Window a)-  deriving newtype (Contravariant, Semigroup, Monoid)----- | 'over' adds a 'Partition' to a 'Window' expression.------ @---   'Rel8.Table.Window.cumulative' ('Rel8.Expr.Aggregate.sum' . salary) `over` 'partitionBy' department <> 'orderPartitionBy' (salary >$< 'Rel8.desc')--- @-over :: Window a b -> Partition a -> Window a b-over (Window (Opaleye.Windows (Opaleye.PackMap w))) (Partition p) =-  Window $ Opaleye.Windows $ Opaleye.PackMap $ \f ->-    w (\(o, p') -> f (o, p' <> p))-infixl 1 `over`----- | Restricts a window function to operate only the group of rows that share--- the same value(s) for the given expression(s).-partitionBy :: forall b a. EqTable b => (a -> b) -> Partition a-partitionBy f =-  Partition $ contramap (toColumns . f) $ getConst $-    htabulateA @(Columns b) $ \field ->-      Const $ Opaleye.partitionBy (toColumn . toPrimExpr . (`hfield` field))----- | Controls the order in which rows are processed by window functions. This--- does not need to match the ordering of the overall query.-orderPartitionBy :: Order a -> Partition a-orderPartitionBy (Order ordering) = Partition $ Opaleye.orderPartitionBy ordering
tests/Main.hs view
@@ -6,6 +6,7 @@ {-# language DerivingVia #-} {-# language FlexibleContexts #-} {-# language FlexibleInstances #-}+{-# language LambdaCase #-} {-# language MonoLocalBinds #-} {-# language NamedFieldPuns #-} {-# language OverloadedStrings #-}@@ -14,8 +15,6 @@ {-# language StandaloneDeriving #-} {-# language TypeApplications #-} -{-# language PartialTypeSignatures #-}- module Main   ( main   )@@ -36,7 +35,7 @@ import Data.Fixed (Centi) import Data.Functor (void) import Data.Int ( Int32, Int64 )-import Data.List ( nub, sort )+import Data.List ( isInfixOf, nub, sort ) import Data.Maybe ( catMaybes ) import Data.Ratio ((%)) import Data.Word (Word32)@@ -69,7 +68,7 @@ import qualified Hasql.Transaction.Sessions as Hasql  -- hedgehog-import Hedgehog ( annotate, failure, property, (===), forAll, cover, diff, evalM, PropertyT, TestT, test, Gen )+import Hedgehog ( annotate, assert, failure, property, (===), forAll, cover, diff, evalM, PropertyT, TestT, test, Gen ) import qualified Hedgehog.Gen as Gen import qualified Hedgehog.Range as Range @@ -83,7 +82,12 @@ import Rel8 ( Result ) import qualified Rel8 import qualified Rel8.Generic.Rel8able.Test as Rel8able-import qualified Rel8.Table.Verify as Verify+import qualified Rel8.Internal.Table.Verify as Verify+import Rel8.Range (+  Bound (Incl, Excl, Inf),+  Range (Empty, Range),+  Multirange (Multirange),+ )  -- scientific import Data.Scientific ( Scientific )@@ -156,6 +160,7 @@     , testSelectArray getTestDatabase     , testNestedMaybeTable getTestDatabase     , testEvaluate getTestDatabase+    , testSelectTruncated getTestDatabase     , testShowCreateTable getTestDatabase     ]   where@@ -277,7 +282,7 @@           statement () $ Rel8.run_ $ Rel8.insert Rel8.Insert             { into = tableSchema             , rows = Rel8.values $ map Rel8.lit rows-            , onConflict = Rel8.DoNothing+            , onConflict = Rel8.DoNothing Nothing             , returning = Rel8.NoReturning             }           statement () $ Rel8.run $ Rel8.select do@@ -335,7 +340,7 @@       statement () $ Rel8.run_ $ Rel8.insert Rel8.Insert         { into = testTableSchema         , rows = Rel8.values $ map Rel8.lit rows-        , onConflict = Rel8.DoNothing+        , onConflict = Rel8.DoNothing Nothing         , returning = Rel8.NoReturning         } @@ -585,6 +590,9 @@   , dbTypeTest "Value" genValue   , dbTypeTest "JSONEncoded" genJSONEncoded   , dbTypeTest "JSONBEncoded" genJSONBEncoded+  , dbTypeTest "Object" genObject+  , dbTypeTest "Range" genRange+  , dbTypeTest "Multirange" genMultirange   ]    where@@ -733,14 +741,91 @@      , Aeson.Number <$> genScientific      , Aeson.String <$> genText      ]-     [ Aeson.Object . Aeson.KeyMap.fromMap <$> Gen.map (Range.linear 0 10) ((,) <$> genKey <*> genValue)+     [ Aeson.Object <$> genObject      , Aeson.Array . Vector.fromList <$> Gen.list (Range.linear 0 10) genValue      ]      genJSONEncoded = Rel8.JSONEncoded <$> genValue     genJSONBEncoded = Rel8.JSONBEncoded <$> genValue +    genObject :: Gen Aeson.Object+    genObject = Aeson.KeyMap.fromMap <$> Gen.map (Range.linear 0 10) ((,) <$> genKey <*> genValue) +    genRange :: Gen (Range Scientific)+    genRange =+      Gen.choice+        [ pure Empty+        , do+            (lower, upper) <- genBounds+            pure (Range lower upper)+        ]++    genBound :: Gen a -> Gen (Bound a)+    genBound a =+      Gen.choice+        [ Incl <$> a+        , Excl <$> a+        , pure Inf+        ]++    genNum :: Gen Scientific+    genNum = genNumFrom (-1000)++    genNumFrom :: Scientific -> Gen Scientific+    genNumFrom x = (/ 10) . fromIntegral @Int @Scientific <$> Gen.integral (Range.linear i 10000)+      where+        i = round (x * 10)++    genBounds :: Gen (Bound Scientific, Bound Scientific)+    genBounds = do+      lower <- genBound genNum+      upper <- genUpperFrom lower+      pure (lower, upper)++    genUpperFrom :: Bound Scientific -> Gen (Bound Scientific)+    genUpperFrom = \case+      Inf -> genBound genNum+      Incl x -> genBoundGT x+      Excl x -> genBoundGT x+      where+        genBoundGT x+          | x' < 1000 = genBound $ genNumFrom x'+          | otherwise = pure Inf+          where+            x' = x + 0.1++    genMultirange :: Gen (Multirange Scientific)+    genMultirange = Multirange <$> do+      n <- Gen.integral (Range.linear @Int 0 10)+      if n == 0+        then pure []+        else do+          (lower, upper) <- genBounds+          ranges <- go (n - 1) upper+          pure (Range lower upper : ranges)+      where+        go n bound+          | n == 0 = pure []+          | otherwise = case bound of+              Inf -> pure []+              Incl x -> next x+              Excl x -> next x+          where+            next x+              | x' >= 1000 = pure []+              | otherwise = do+                  lower <-+                    Gen.choice+                      [ Incl <$> genNumFrom x'+                      , Excl <$> genNumFrom x'+                      ]+                  upper <- genUpperFrom lower+                  ranges <- go (n - 1) upper+                  pure (Range lower upper : ranges)+              where+                x' = x + 0.1++ testDBEq :: IO TmpPostgres.DB -> TestTree testDBEq getTestDatabase = testGroup "DBEq instances"   [ dbEqTest "Bool" Gen.bool@@ -945,7 +1030,7 @@       statement () $ Rel8.run_ $ Rel8.insert Rel8.Insert         { into = testTableSchema         , rows = Rel8.values $ map Rel8.lit $ Map.keys rows-        , onConflict = Rel8.DoNothing+        , onConflict = Rel8.DoNothing Nothing         , returning = Rel8.NoReturning         } @@ -989,7 +1074,7 @@       statement () $ Rel8.run_ $ Rel8.insert Rel8.Insert         { into = testTableSchema         , rows = Rel8.values $ map Rel8.lit rows-        , onConflict = Rel8.DoNothing+        , onConflict = Rel8.DoNothing Nothing         , returning = Rel8.NoReturning         } @@ -1029,7 +1114,7 @@               inserted <- Rel8.insert $ Rel8.Insert                 { into = testTableSchema                 , rows = values-                , onConflict = Rel8.DoNothing+                , onConflict = Rel8.DoNothing Nothing                 , returning = Rel8.Returning id                 } @@ -1047,7 +1132,7 @@               Rel8.insert $ Rel8.Insert                 { into = testTableSchema                 , rows = Rel8.values $ map Rel8.lit rows-                , onConflict = Rel8.DoNothing+                , onConflict = Rel8.DoNothing Nothing                 , returning = Rel8.NoReturning                 } @@ -1063,7 +1148,7 @@               Rel8.insert $ Rel8.Insert                 { into = testTableSchema                 , rows = Rel8.values $ map Rel8.lit rows-                , onConflict = Rel8.DoNothing+                , onConflict = Rel8.DoNothing Nothing                 , returning = Rel8.Returning id                 } @@ -1123,7 +1208,7 @@       statement () $ Rel8.run_ $ Rel8.insert Rel8.Insert         { into = uniqueTableSchema         , rows = Rel8.values $ Rel8.lit <$> as-        , onConflict = Rel8.DoNothing+        , onConflict = Rel8.DoNothing Nothing         , returning = Rel8.NoReturning         } @@ -1131,8 +1216,12 @@         { into = uniqueTableSchema         , rows = Rel8.values $ Rel8.lit <$> bs         , onConflict = Rel8.DoUpdate Rel8.Upsert-            { index = uniqueTableKey-            , predicate = Nothing+            { conflict =+                Rel8.OnIndex+                  Rel8.Index+                    { columns = uniqueTableKey+                    , predicate = Nothing+                    }             , set = \UniqueTable {uniqueTableValue} old -> old {uniqueTableValue}             , updateWhere = \_ _ -> Rel8.true             }@@ -1256,3 +1345,53 @@     normalize :: [(x, (Int64, Int64))] -> [(x, (Int64, Int64))]     normalize [] = []     normalize xs@((_, (i, _)) : _) = map (fmap (\(a, b) -> (a - i, b - i))) xs+++-- Field name is 42 chars+data LongLabelTable f = LongLabelTable+  { aFieldNameDefinitelyLongerThanThirtyCharsA :: Rel8.Column f Text+  , aFieldNameDefinitelyLongerThanThirtyCharsB :: Rel8.Column f Text+  }+  deriving stock Generic+  deriving anyclass Rel8.Rel8able++deriving stock instance Eq (LongLabelTable Result)+deriving stock instance Ord (LongLabelTable Result)+deriving stock instance Show (LongLabelTable Result)+++-- Field name is 51 chars, nested with the 42 above, we'll get more than 63,+-- triggering truncation.+data NestedForLargerThan63 f = NestedForLargerThan63+  { aFieldNameDefinitelyLongerThanThirtyCharsNestedWith :: LongLabelTable f+  }+  deriving stock Generic+  deriving anyclass Rel8.Rel8able++deriving stock instance Eq (NestedForLargerThan63 Result)+deriving stock instance Ord (NestedForLargerThan63 Result)+deriving stock instance Show (NestedForLargerThan63 Result)+++testSelectTruncated :: IO TmpPostgres.DB -> TestTree+testSelectTruncated = databasePropertyTest "select truncates long column aliases" \transaction -> do+  rows <- forAll $ Gen.list (Range.linear 0 10) ((,) <$> genText <*> genText)++  let q = Rel8.values $ map (\(tA, tB) -> NestedForLargerThan63 (LongLabelTable (Rel8.lit tA) (Rel8.lit tB))) rows+      sqlText = Rel8.showStatement (Rel8.select q)+  annotate sqlText++  -- Check that long names do not exist+  assert $ not $ "aFieldNameDefinitelyLongerThanThirtyCharsA" `isInfixOf` sqlText+  assert $ not $ "aFieldNameDefinitelyLongerThanThirtyCharsB" `isInfixOf` sqlText++  -- Find the short names+  assert $ "aFieldNameDefinitelyLongerThanThirtyCharsNestedWith/aFieldN_1_1" `isInfixOf` sqlText+  assert $ "aFieldNameDefinitelyLongerThanThirtyCharsNestedWith/aFieldN_2_1" `isInfixOf` sqlText++  transaction do+    selected <- lift do+      statement () $ Rel8.run $ Rel8.select q+    sort (map (((,) <$> aFieldNameDefinitelyLongerThanThirtyCharsA <*>  aFieldNameDefinitelyLongerThanThirtyCharsB)+      . aFieldNameDefinitelyLongerThanThirtyCharsNestedWith) selected)+      === sort rows
tests/Rel8/Generic/Rel8able/Test.hs view
@@ -24,11 +24,11 @@  -- aeson import Data.Aeson ( Value(..) )-import qualified Data.Aeson as Aeson import qualified Data.Aeson.KeyMap as Aeson  -- base import Data.Fixed ( Fixed ( MkFixed ), E2 )+import Data.Foldable ( fold ) import Data.Int ( Int16, Int32, Int64 ) import Data.Functor.Identity ( Identity(..) ) import qualified Data.List.NonEmpty as NonEmpty@@ -53,7 +53,28 @@ import qualified Hedgehog.Range as Range  -- rel8-import Rel8+import Rel8 (+  Column,+  DBType,+  Expr,+  HADT,+  HEither,+  HKD,+  HList,+  HMaybe,+  HNonEmpty,+  HThese,+  KRel8able,+  Lift,+  Name,+  QualifiedName,+  Rel8able,+  Result,+  TableSchema (TableSchema),+  ToExprs,+  namesFromLabelsWith,+ )+import qualified Rel8  -- scientific import Data.Scientific ( Scientific, fromFloatDigits )@@ -79,14 +100,13 @@ import qualified Data.UUID as UUID  -- vector-import Data.Vector ( Vector ) import qualified Data.Vector as Vector   makeSchema :: forall f. Rel8able f => QualifiedName -> TableSchema (f Name) makeSchema name = TableSchema   { name = name-  , columns = namesFromLabels @(f Name)+  , columns = namesFromLabelsWith @(f Name) (fold . NonEmpty.intersperse "/")   }  @@ -477,7 +497,7 @@   int64 <- Gen.int64 range   float <- Gen.float linearFrac   double <- Gen.double linearFrac-  scientific <- fromFloatDigits <$> Gen.realFloat linearFrac+  scientific <- fromFloatDigits @Double <$> Gen.realFloat linearFrac   utctime <- UTCTime <$> (toEnum <$> Gen.integral range) <*> fmap secondsToDiffTime (Gen.integral range)   day <- toEnum <$> Gen.integral range   localtime <- LocalTime <$> (toEnum <$> Gen.integral range) <*> timeOfDay@@ -494,7 +514,7 @@     [ Object <$> Aeson.fromMapText <$> Map.fromList <$> Gen.list range (liftA2 (,) (Gen.text range Gen.alpha) (pure Null))     , Array <$> Vector.fromList <$> Gen.list range (pure Null)     , String <$> Gen.text range Gen.alpha-    , Number <$> fromFloatDigits <$> Gen.realFloat linearFrac+    , Number <$> fromFloatDigits @Double <$> Gen.realFloat linearFrac     , Bool <$> Gen.bool     , pure Null     ]
+ tests/Rel8/TH/Rel8able/Test.hs view
@@ -0,0 +1,137 @@+{-# language ScopedTypeVariables #-}+{-# language DataKinds #-}+{-# language DeriveAnyClass #-}+{-# language DeriveGeneric #-}+{-# language DerivingStrategies #-}+{-# language DuplicateRecordFields #-}+{-# language FlexibleInstances #-}+{-# language MultiParamTypeClasses #-}+{-# language OverloadedStrings #-}+{-# language StandaloneDeriving #-}+{-# language StandaloneKindSignatures #-}+{-# language TypeApplications #-}+{-# language TypeFamilies #-}+{-# language TypeOperators #-}+{-# language RecordWildCards #-}+{-# language UndecidableInstances #-}+{-# LANGUAGE TemplateHaskell #-}++module Rel8.TH.Rel8able.Test where++-- base+import Data.Fixed ( Fixed ( MkFixed ), E2 )+import Prelude++-- rel8+import Rel8 (+  Column,+  HEither,+  HList,+  HMaybe,+  HNonEmpty,+  HThese, + )+import Rel8.TH++-- text+import Data.Text ( Text )++data TableTest f = TableTest+  { foo :: Column f Bool+  , bar :: Column f (Maybe Bool)+  }++deriveRel8able ''TableTest++data TablePair f = TablePair+  { foo :: Column f Bool+  , bars :: (Column f Text, Column f Text)+  }+  +deriveRel8able ''TablePair++data TableDuplicate f = TableDuplicate+  { foo :: TablePair f+  , bar :: TablePair f+  }++deriveRel8able ''TableDuplicate ++data TableMaybe f = TableMaybe+  { foo :: Column f [Maybe Bool]+  , bars :: HMaybe f (TablePair f, TablePair f)+  }+  +deriveRel8able ''TableMaybe++data TableEither f = TableEither+  { foo :: Column f Bool+  , bars :: HEither f (HMaybe f (TablePair f, TablePair f)) (Column f Char)+  }+  +deriveRel8able ''TableEither++data TableThese f = TableThese+  { foo :: Column f Bool+  , bars :: HThese f (TableMaybe f) (TableEither f)+  }+  +deriveRel8able ''TableThese+++data TableList f = TableList+  { foo :: Column f Bool+  , bars :: HList f (TableThese f)+  }+  +deriveRel8able ''TableList+++data TableNonEmpty f = TableNonEmpty+  { foo :: Column f Bool+  , bars :: HNonEmpty f (TableList f, TableMaybe f)+  }+  +deriveRel8able ''TableNonEmpty++data TableNest f = TableNest+  { foo :: Column f Bool+  , bars :: HList f (HMaybe f (TablePair f))+  }+  +deriveRel8able ''TableNest+++data TableTestB f = TableTestB+  { foo :: f Bool+  , bar :: f (Maybe Bool)+  }++deriveRel8able ''TableTestB++data NestedTableTestB f = NestedTableTestB+  { foo :: f Bool+  , bar :: f (Maybe Bool)+  , baz :: Column f Char+  , nest :: TableTestB f+  }+  +deriveRel8able ''NestedTableTestB++data TableNumeric f = TableNumeric+  { foo :: Column f (Fixed E2)+  }+  +deriveRel8able ''TableNumeric+++data TableChar f = TableChar+  { foo :: Column f Char+  } +deriveRel8able ''TableChar+++newtype IdRecord a f = IdRecord { recordId :: Column f a }++-- Our TH deriving code currently doesn't support type args other than f+-- deriveRel8able ''IdRecord