on master help sign in
Eliminate the need for Array1D (i.e., unify with [])

To implement the `DBType` instance for `[]`, we wrapped the underlying Postgres array with `ROW()`. This is to allow nesting `[]` inside `[]` (Postgres treats a bare `foo[][]` as a multidimensional array). However, instead of unconditionally wrapping the list itself with `ROW()`, we could instead wrap individual list elements. And even better, we can wrap them *conditionally*, i.e., only if they have an array type (e.g., `foo[]`). This makes our lists much closer to Postgres arrays, and eliminates the need for `Array1D`. It also means our lists can be concatenated with a bare `||` operator; no need for the flaky `(foo).f1` unwrapping step.

commit447508578df1290ddd14495f18181d2098cb92c4 authorShane O'Brien <shane.obrien@circuithub.com> dateMon 14 Jun 2021, 11:51 (5 years ago) parentbdb75e6
13 files changed+83−217
rel8.cabal−1 src/Rel8.hs−4 src/Rel8/Aggregate/Legacy.hs+6−3 src/Rel8/Expr/Aggregate.hs+22−20 src/Rel8/Expr/Array.hs+6−6 src/Rel8/Expr/Text.hs+1−2 src/Rel8/Query/List.hs+1−1 src/Rel8/Table/Aggregate.hs+6−4 src/Rel8/Table/List.hs+1−2 src/Rel8/Type/Array.hs+34−26 src/Rel8/Type/Array1D.hs−139 src/Rel8/Type/Monoid.hs+2−2 src/Rel8/Type/Semigroup.hs+4−7
rel8.cabal−1
@@ -168,7 +168,6 @@ library
168168
169169 Rel8.Type
170170 Rel8.Type.Array
171− Rel8.Type.Array1D
172171 Rel8.Type.Composite
173172 Rel8.Type.Eq
174173 Rel8.Type.Enum
src/Rel8.hs−4
@@ -218,7 +218,6 @@ module Rel8
218218 , countRows
219219 , groupBy
220220 , headAgg
221− , array1DAggExpr
222221 , listAgg, listAggExpr
223222 , nonEmptyAgg, nonEmptyAggExpr
224223 , DBMax, max
@@ -272,8 +271,6 @@ module Rel8
272271 -- TODO
273272 -- These need organizing, but are reachable from Rel8's documentation so we
274273 -- do need to export and document them.
275− , Array1D( Array1D )
276− , NotArray
277274 , Nullable
278275 , NotNull
279276 , HTable
@@ -358,7 +355,6 @@ import Rel8.Table.Rel8able ()
358355import Rel8.Table.Serialize
359356import Rel8.Table.These
360357import Rel8.Type
361−import Rel8.Type.Array1D
362358import Rel8.Type.Composite
363359import Rel8.Type.Eq
364360import Rel8.Type.Enum
src/Rel8/Aggregate/Legacy.hs+6−3
@@ -1,6 +1,7 @@
11{-# language AllowAmbiguousTypes #-}
22{-# language DataKinds #-}
33{-# language FlexibleContexts #-}
4+{-# language NamedFieldPuns #-}
45{-# language RankNTypes #-}
56{-# language ScopedTypeVariables #-}
67{-# language StandaloneKindSignatures #-}
@@ -37,7 +38,8 @@ import Rel8.Expr ( Col( E ), Expr )
3738import Rel8.Expr.Aggregate
3839 ( groupByExpr
3940 , headAggExpr
40− , listAggExpr, nonEmptyAggExpr
41+ , slistAggExpr
42+ , snonEmptyAggExpr
4143 )
4244import Rel8.Generic.Construction ( GGAggregate', ggaggregate' )
4345import Rel8.Generic.Table ( GAlgebra )
@@ -48,6 +50,7 @@ import Rel8.Schema.Dict ( Dict( Dict ) )
4850import Rel8.Schema.HTable ( hmap, hfield, htabulate )
4951import Rel8.Schema.HTable.Vectorize ( hvectorize )
5052import Rel8.Schema.Kind ( Rel8able )
53+import Rel8.Schema.Spec ( SSpec( SSpec, info ) )
5154import Rel8.Table ( toColumns, fromColumns )
5255import Rel8.Table.ADT ( ConstructableADT, ADT( ADT ), ADTRep )
5356import Rel8.Table.Eq ( EqTable, eqTable )
@@ -105,7 +108,7 @@ headAgg = fromColumns . hmap (\(E a) -> A $ headAggExpr a) . toColumns
105108listAgg :: Aggregates aggregates exprs => exprs -> ListTable aggregates
106109listAgg (toColumns -> exprs) = fromColumns $
107110 hvectorize
108− (\_ (Identity (E a)) -> A $ listAggExpr a)
111+ (\SSpec {info} (Identity (E a)) -> A $ slistAggExpr info a)
109112 (pure exprs)
110113
111114
@@ -113,7 +116,7 @@ listAgg (toColumns -> exprs) = fromColumns $
113116nonEmptyAgg :: Aggregates aggregates exprs => exprs -> NonEmptyTable aggregates
114117nonEmptyAgg (toColumns -> exprs) = fromColumns $
115118 hvectorize
116− (\_ (Identity (E a)) -> A $ nonEmptyAggExpr a)
119+ (\SSpec {info} (Identity (E a)) -> A $ snonEmptyAggExpr info a)
117120 (pure exprs)
118121
119122
src/Rel8/Expr/Aggregate.hs+22−20
@@ -13,7 +13,8 @@ module Rel8.Expr.Aggregate
1313 , stringAgg
1414 , groupByExpr
1515 , headAggExpr
16− , array1DAggExpr, listAggExpr, nonEmptyAggExpr
16+ , listAggExpr, nonEmptyAggExpr
17+ , slistAggExpr, snonEmptyAggExpr
1718 )
1819where
1920
@@ -37,10 +38,11 @@ import Rel8.Expr.Opaleye
3738 )
3839import Rel8.Expr.Null ( null )
3940import Rel8.Expr.Serialize ( litExpr )
40−import Rel8.Schema.Null ( Sql )
41−import Rel8.Type.Array ( fromPrimArray )
42−import Rel8.Type.Array1D ( Array1D, NotArray )
41+import Rel8.Schema.Null ( Sql, Unnullify )
42+import Rel8.Type ( DBType, typeInformation )
43+import Rel8.Type.Array ( wrap )
4344import Rel8.Type.Eq ( DBEq )
45+import Rel8.Type.Information ( TypeInformation )
4446import Rel8.Type.Num ( DBNum )
4547import Rel8.Type.Ord ( DBMax, DBMin )
4648import Rel8.Type.String ( DBString )
@@ -168,35 +170,35 @@ headAggExpr = unsafeMakeAggregate toPrimExpr from $ Just
168170 one = Opaleye.ConstExpr (Opaleye.NumericLit 1)
169171
170172
171−-- | Collect expressions values as an array.
172−array1DAggExpr :: NotArray a => Expr a -> Aggregate (Expr (Array1D a))
173−array1DAggExpr = unsafeMakeAggregate toPrimExpr fromPrimExpr $ Just
174− Aggregator
175− { operation = Opaleye.AggrArr
176− , ordering = []
177− , distinction = Opaleye.AggrAll
178− }
173+-- | Collect expressions values as a list.
174+listAggExpr :: Sql DBType a => Expr a -> Aggregate (Expr [a])
175+listAggExpr = slistAggExpr typeInformation
179176
180177
181−-- | Collect expressions values as a list.
182−listAggExpr :: Expr a -> Aggregate (Expr [a])
183−listAggExpr = unsafeMakeAggregate toPrimExpr from $ Just
178+-- | Collect expressions values as a non-empty list.
179+nonEmptyAggExpr :: Sql DBType a => Expr a -> Aggregate (Expr (NonEmpty a))
180+nonEmptyAggExpr = snonEmptyAggExpr typeInformation
181+
182+
183+slistAggExpr :: ()
184+ => TypeInformation (Unnullify a) -> Expr a -> Aggregate (Expr [a])
185+slistAggExpr info = unsafeMakeAggregate to fromPrimExpr $ Just
184186 Aggregator
185187 { operation = Opaleye.AggrArr
186188 , ordering = []
187189 , distinction = Opaleye.AggrAll
188190 }
189191 where
190− from = fromPrimExpr . fromPrimArray
192+ to = wrap info . toPrimExpr
191193
192194
193−-- | Collect expressions values as a non-empty list.
194−nonEmptyAggExpr :: Expr a -> Aggregate (Expr (NonEmpty a))
195−nonEmptyAggExpr = unsafeMakeAggregate toPrimExpr from $ Just
195+snonEmptyAggExpr :: ()
196+ => TypeInformation (Unnullify a) -> Expr a -> Aggregate (Expr (NonEmpty a))
197+snonEmptyAggExpr info = unsafeMakeAggregate to fromPrimExpr $ Just
196198 Aggregator
197199 { operation = Opaleye.AggrArr
198200 , ordering = []
199201 , distinction = Opaleye.AggrAll
200202 }
201203 where
202− from = fromPrimExpr . fromPrimArray
204+ to = wrap info . toPrimExpr
src/Rel8/Expr/Array.hs+6−6
@@ -25,21 +25,21 @@ import Rel8.Expr.Opaleye
2525 , zipPrimExprsWith
2626 )
2727import Rel8.Type ( DBType, typeInformation )
28−import Rel8.Type.Array ( array, zipPrimArraysWith )
28+import Rel8.Type.Array ( array )
2929import Rel8.Type.Information ( TypeInformation(..) )
30−import Rel8.Schema.Null ( Unnullify, Nullity, Sql )
30+import Rel8.Schema.Null ( Unnullify, Sql )
3131
3232
3333sappend :: Expr [a] -> Expr [a] -> Expr [a]
34−sappend = zipPrimExprsWith (zipPrimArraysWith (Opaleye.BinExpr (Opaleye.:||)))
34+sappend = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:||))
3535
3636
3737sappend1 :: Expr (NonEmpty a) -> Expr (NonEmpty a) -> Expr (NonEmpty a)
38−sappend1 = zipPrimExprsWith (zipPrimArraysWith (Opaleye.BinExpr (Opaleye.:||)))
38+sappend1 = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:||))
3939
4040
41−sempty :: Nullity a -> TypeInformation (Unnullify a) -> Expr [a]
42−sempty _ info = fromPrimExpr $ array info []
41+sempty :: TypeInformation (Unnullify a) -> Expr [a]
42+sempty info = fromPrimExpr $ array info []
4343
4444
4545slistOf :: TypeInformation (Unnullify a) -> [Expr a] -> Expr [a]
src/Rel8/Expr/Text.hs+1−2
@@ -32,7 +32,6 @@ import Data.ByteString ( ByteString )
3232-- rel8
3333import Rel8.Expr ( Expr )
3434import Rel8.Expr.Function ( binaryOperator, function, nullaryFunction )
35−import Rel8.Type.Array1D ( Array1D )
3635
3736-- text
3837import Data.Text (Text)
@@ -218,7 +217,7 @@ regexpReplace a b c Nothing = function "regexp_replace" a b c
218217
219218-- | Corresponds to the @regexp_split_to_array@ function.
220219regexpSplitToArray :: ()
221− => Expr Text -> Expr Text -> Maybe (Expr Text) -> Expr (Array1D Text)
220+ => Expr Text -> Expr Text -> Maybe (Expr Text) -> Expr [Text]
222221regexpSplitToArray a b (Just c) = function "regexp_split_to_array" a b c
223222regexpSplitToArray a b Nothing = function "regexp_split_to_array" a b
224223
src/Rel8/Query/List.hs+1−1
@@ -55,5 +55,5 @@ manyExpr = fmap (maybeTable mempty id) . optional . aggregate . fmap listAggExpr
5555
5656
5757-- | A version of 'many' specialised to single expressions.
58−someExpr :: Query (Expr a) -> Query (Expr (NonEmpty a))
58+someExpr :: Sql DBType a => Query (Expr a) -> Query (Expr (NonEmpty a))
5959someExpr = aggregate . fmap nonEmptyAggExpr
src/Rel8/Table/Aggregate.hs+6−4
@@ -1,4 +1,5 @@
11{-# language FlexibleContexts #-}
2+{-# language NamedFieldPuns #-}
23{-# language ScopedTypeVariables #-}
34{-# language TypeApplications #-}
45{-# language TypeFamilies #-}
@@ -21,12 +22,13 @@ import Rel8.Expr ( Expr, Col( E ) )
2122import Rel8.Expr.Aggregate
2223 ( groupByExpr
2324 , headAggExpr
24− , listAggExpr
25− , nonEmptyAggExpr
25+ , slistAggExpr
26+ , snonEmptyAggExpr
2627 )
2728import Rel8.Schema.Dict ( Dict( Dict ) )
2829import Rel8.Schema.HTable ( hfield, hmap, htabulate )
2930import Rel8.Schema.HTable.Vectorize ( hvectorize )
31+import Rel8.Schema.Spec ( SSpec( SSpec, info ) )
3032import Rel8.Table ( Table, toColumns, fromColumns )
3133import Rel8.Table.Eq ( EqTable, eqTable )
3234import Rel8.Table.List ( ListTable )
@@ -66,7 +68,7 @@ headAgg = fromColumns . hmap (\(E a) -> A $ headAggExpr a) . toColumns
6668listAgg :: Table Expr a => a -> Aggregate (ListTable a)
6769listAgg (toColumns -> exprs) = fromColumns $
6870 hvectorize
69− (\_ (Identity (E a)) -> A $ listAggExpr a)
71+ (\SSpec {info} (Identity (E a)) -> A $ slistAggExpr info a)
7072 (pure exprs)
7173
7274
@@ -74,5 +76,5 @@ listAgg (toColumns -> exprs) = fromColumns $
7476nonEmptyAgg :: Table Expr a => a -> Aggregate (NonEmptyTable a)
7577nonEmptyAgg (toColumns -> exprs) = fromColumns $
7678 hvectorize
77− (\_ (Identity (E a)) -> A $ nonEmptyAggExpr a)
79+ (\SSpec {info} (Identity (E a)) -> A $ snonEmptyAggExpr info a)
7880 (pure exprs)
src/Rel8/Table/List.hs+1−2
@@ -116,8 +116,7 @@ instance Table Expr a => Semigroup (ListTable a) where
116116
117117
118118instance Table Expr a => Monoid (ListTable a) where
119− mempty = ListTable $ hempty $ \nullability info ->
120− E (sempty nullability info)
119+ mempty = ListTable $ hempty $ \_ -> E . sempty
121120
122121
123122listTable :: Table Expr a => [a] -> ListTable a
src/Rel8/Type/Array.hs+34−26
@@ -1,12 +1,13 @@
11{-# language GADTs #-}
2+{-# language LambdaCase #-}
23{-# language NamedFieldPuns #-}
34{-# language OverloadedStrings #-}
5+{-# language ViewPatterns #-}
46
57module Rel8.Type.Array
6− ( array
8+ ( array, wrap
79 , listTypeInformation
810 , nonEmptyTypeInformation
9− , fromPrimArray, toPrimArray, zipPrimArraysWith
1011 )
1112where
1213
@@ -28,10 +29,9 @@ import Rel8.Type.Information ( TypeInformation(..), parseTypeInformation )
2829
2930array :: Foldable f
3031 => TypeInformation a -> f Opaleye.PrimExpr -> Opaleye.PrimExpr
31−array TypeInformation {typeName} =
32− fromPrimArray .
33− Opaleye.CastExpr (typeName <> "[]") .
34− Opaleye.ArrayExpr . toList
32+array info =
33+ Opaleye.CastExpr (arrayType info <> "[]") .
34+ Opaleye.ArrayExpr . map (wrap info) . toList
3535{-# INLINABLE array #-}
3636
3737
@@ -39,19 +39,17 @@ listTypeInformation :: ()
3939 => Nullity a
4040 -> TypeInformation (Unnullify a)
4141 -> TypeInformation [a]
42−listTypeInformation nullity info =
43− case info of
44− TypeInformation{ encode, decode } -> TypeInformation
45− { decode = row $ case nullity of
46− Null -> Hasql.listArray (Hasql.nullable decode)
47− NotNull -> Hasql.listArray (Hasql.nonNullable decode)
48− , encode = case nullity of
49− Null -> array info . fmap (maybe null encode)
50− NotNull -> array info . fmap encode
51− , typeName = "record"
52− }
42+listTypeInformation nullity info@TypeInformation {encode, decode} =
43+ TypeInformation
44+ { decode = case nullity of
45+ Null -> Hasql.listArray (Hasql.nullable (unwrap info decode))
46+ NotNull -> Hasql.listArray (Hasql.nonNullable (unwrap info decode))
47+ , encode = case nullity of
48+ Null -> Opaleye.ArrayExpr . fmap (wrap info . maybe null encode)
49+ NotNull -> Opaleye.ArrayExpr . fmap (wrap info . encode)
50+ , typeName = arrayType info <> "[]"
51+ }
5352 where
54− row = Hasql.composite . Hasql.field . Hasql.nonNullable
5553 null = Opaleye.ConstExpr Opaleye.NullLit
5654
5755
@@ -66,15 +64,25 @@ nonEmptyTypeInformation nullity =
6664 message = "failed to decode NonEmptyList: got empty list"
6765
6866
69−fromPrimArray :: Opaleye.PrimExpr -> Opaleye.PrimExpr
70−fromPrimArray = Opaleye.UnExpr (Opaleye.UnOpOther "ROW")
67+isArray :: TypeInformation a -> Bool
68+isArray = \case
69+ (reverse . typeName -> ']' : '[' : _) -> True
70+ _ -> False
7171
7272
73−toPrimArray :: Opaleye.PrimExpr -> Opaleye.PrimExpr
74−toPrimArray a = Opaleye.CompositeExpr a "f1"
73+arrayType :: TypeInformation a -> String
74+arrayType info
75+ | isArray info = "record"
76+ | otherwise = typeName info
7577
7678
77−zipPrimArraysWith :: ()
78− => (Opaleye.PrimExpr -> Opaleye.PrimExpr -> Opaleye.PrimExpr)
79− -> Opaleye.PrimExpr -> Opaleye.PrimExpr -> Opaleye.PrimExpr
80−zipPrimArraysWith f a b = fromPrimArray (f (toPrimArray a) (toPrimArray b))
79+wrap :: TypeInformation a -> Opaleye.PrimExpr -> Opaleye.PrimExpr
80+wrap info
81+ | isArray info = Opaleye.UnExpr (Opaleye.UnOpOther "ROW")
82+ | otherwise = id
83+
84+
85+unwrap :: TypeInformation a -> Hasql.Value x -> Hasql.Value x
86+unwrap info
87+ | isArray info = Hasql.composite . Hasql.field . Hasql.nonNullable
88+ | otherwise = id
src/Rel8/Type/Array1D.hsdeleted−139
@@ -1,139 +0,0 @@
1−{-# language DataKinds #-}
2−{-# language DeriveTraversable #-}
3−{-# language DerivingStrategies #-}
4−{-# language FlexibleContexts #-}
5−{-# language FlexibleInstances #-}
6−{-# language GeneralizedNewtypeDeriving #-}
7−{-# language NamedFieldPuns #-}
8−{-# language StandaloneKindSignatures #-}
9−{-# language TypeFamilies #-}
10−{-# language UndecidableInstances #-}
11−
12−{-# options_ghc -fno-warn-redundant-constraints #-}
13−
14−module Rel8.Type.Array1D
15− ( Array1D( Array1D )
16− , NotArray
17− , getArray1D
18− )
19−where
20−
21−-- aeson
22−import Data.Aeson
23− ( ToJSON
24− , ToJSON1
25− , ToJSONKey
26− , FromJSON
27− , FromJSON1
28− , FromJSONKey
29− )
30−
31−-- base
32−import Control.Applicative ( Alternative, (<|>) )
33−import Control.Monad ( MonadPlus )
34−import Data.Functor.Classes ( Eq1, Ord1, Read1, Show1 )
35−import Data.Kind ( Type )
36−import GHC.Exts ( IsList )
37−import Prelude hiding ( null )
38−
39−-- hasql
40−import qualified Hasql.Decoders as Hasql
41−
42−-- opaleye
43−import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
44−
45−-- rel8
46−import Rel8.Expr.Opaleye ( zipPrimExprsWith )
47−import Rel8.Expr.Serialize ( litExpr )
48−import Rel8.Schema.Null ( Unnullify, Nullity( Null, NotNull ), Sql, nullable )
49−import Rel8.Type ( DBType, typeInformation )
50−import Rel8.Type.Eq ( DBEq )
51−import Rel8.Type.Information ( TypeInformation(..) )
52−import Rel8.Type.Monoid ( DBMonoid, memptyExpr )
53−import Rel8.Type.Ord ( DBMax, DBMin, DBOrd )
54−import Rel8.Type.Semigroup ( DBSemigroup, (<>.) )
55−
56−-- semigroupoids
57−import Data.Functor.Alt ( Alt, (<!>) )
58−import Data.Functor.Apply ( Apply )
59−import Data.Functor.Bind ( Bind )
60−import Data.Functor.Plus ( Plus )
61−
62−-- semialign
63−import Data.Align ( Align )
64−import Data.Semialign ( Semialign )
65−import Data.Zip ( Repeat, Unzip, Zip )
66−
67−
68−-- | A one dimensional array.
69−newtype Array1D a = Array1D [a]
70− deriving stock Traversable
71− deriving newtype
72− ( Eq, Ord, Read, Show, Semigroup, Monoid, IsList
73− , Functor, Foldable
74− , Eq1, Ord1, Read1, Show1
75− , FromJSON1, ToJSON1, FromJSON, FromJSONKey, ToJSON, ToJSONKey
76− , Apply, Applicative, Alternative, Plus, Bind, Monad, MonadPlus
77− , Align, Semialign, Repeat, Unzip, Zip
78− )
79−
80−
81−instance Alt Array1D where
82− (<!>) = (<|>)
83−
84−
85−getArray1D :: Array1D a -> [a]
86−getArray1D (Array1D a) = a
87−
88−
89−type IsArray1D :: Type -> Bool
90−type family IsArray1D a where
91− IsArray1D (Array1D _) = 'True
92− IsArray1D _ = 'False
93−
94−
95−class IsArray1D a ~ 'False => NotArray a
96−instance IsArray1D a ~ 'False => NotArray a
97−
98−
99−array1DTypeInformation :: Sql NotArray a
100− => Nullity a
101− -> TypeInformation (Unnullify a)
102− -> TypeInformation (Array1D a)
103−array1DTypeInformation nullity info =
104− case info of
105− TypeInformation{ encode, decode, typeName } -> TypeInformation
106− { decode = case nullity of
107− Null -> Array1D <$> Hasql.listArray (Hasql.nullable decode)
108− NotNull -> Array1D <$> Hasql.listArray (Hasql.nonNullable decode)
109− , encode = case nullity of
110− Null -> Opaleye.ArrayExpr . fmap (maybe null encode) . getArray1D
111− NotNull -> Opaleye.ArrayExpr . fmap encode . getArray1D
112− , typeName = typeName <> "[]"
113− }
114− where
115− null = Opaleye.ConstExpr Opaleye.NullLit
116−
117−
118−instance (Sql DBType a, Sql NotArray a) => DBType (Array1D a) where
119− typeInformation = array1DTypeInformation nullable typeInformation
120−
121−
122−instance (Sql DBEq a, Sql NotArray a) => DBEq (Array1D a)
123−
124−
125−instance (Sql DBOrd a, Sql NotArray a) => DBOrd (Array1D a)
126−
127−
128−instance (Sql DBMax a, Sql NotArray a) => DBMax (Array1D a)
129−
130−
131−instance (Sql DBMin a, Sql NotArray a) => DBMin (Array1D a)
132−
133−
134−instance (Sql DBType a, Sql NotArray a) => DBSemigroup (Array1D a) where
135− (<>.) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:||))
136−
137−
138−instance (Sql DBType a, Sql NotArray a) => DBMonoid (Array1D a) where
139− memptyExpr = litExpr mempty
src/Rel8/Type/Monoid.hs+2−2
@@ -27,7 +27,7 @@ import Data.CaseInsensitive ( CI )
2727import {-# SOURCE #-} Rel8.Expr ( Expr )
2828import Rel8.Expr.Array ( sempty )
2929import Rel8.Expr.Serialize ( litExpr )
30−import Rel8.Schema.Null ( Sql, nullable )
30+import Rel8.Schema.Null ( Sql )
3131import Rel8.Type ( DBType, typeInformation )
3232import Rel8.Type.Semigroup ( DBSemigroup )
3333
@@ -48,7 +48,7 @@ class DBSemigroup a => DBMonoid a where
4848
4949
5050instance Sql DBType a => DBMonoid [a] where
51− memptyExpr = sempty nullable typeInformation
51+ memptyExpr = sempty typeInformation
5252
5353
5454instance DBMonoid CalendarDiffTime where
src/Rel8/Type/Semigroup.hs+4−7
@@ -13,10 +13,9 @@ module Rel8.Type.Semigroup
1313where
1414
1515-- base
16−import Data.Function ( on )
1716import Data.Kind ( Constraint, Type )
1817import Data.List.NonEmpty ( NonEmpty )
19−import Prelude
18+import Prelude ()
2019
2120-- bytestring
2221import Data.ByteString ( ByteString )
@@ -30,10 +29,10 @@ import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
3029
3130-- rel8
3231import {-# SOURCE #-} Rel8.Expr ( Expr )
32+import Rel8.Expr.Array ( sappend, sappend1 )
3333import Rel8.Expr.Opaleye ( zipPrimExprsWith )
3434import Rel8.Schema.Null ( Sql )
3535import Rel8.Type ( DBType )
36−import Rel8.Type.Array ( fromPrimArray, toPrimArray )
3736
3837-- text
3938import Data.Text ( Text )
@@ -53,13 +52,11 @@ class DBType a => DBSemigroup a where
5352
5453
5554instance Sql DBType a => DBSemigroup [a] where
56− (<>.) = zipPrimExprsWith do
57− (fromPrimArray .) . Opaleye.BinExpr (Opaleye.:||) `on` toPrimArray
55+ (<>.) = sappend
5856
5957
6058instance Sql DBType a => DBSemigroup (NonEmpty a) where
61− (<>.) = zipPrimExprsWith do
62− (fromPrimArray .) . Opaleye.BinExpr (Opaleye.:||) `on` toPrimArray
59+ (<>.) = sappend1
6360
6461
6562instance DBSemigroup CalendarDiffTime where