Compare commits

...

14 Commits

Author SHA1 Message Date
parsonsmatt
14716a5191 sigh 2020-10-29 16:13:56 -06:00
parsonsmatt
9ad56e7de2 cabbal 2020-10-29 16:05:38 -06:00
parsonsmatt
99f9231e49 faster build perhaps 2020-10-29 16:00:39 -06:00
Matt Parsons
51c546aed3
Merge branch 'master' into format-config 2020-10-29 15:39:01 -06:00
parsonsmatt
b59cf8cd7a Merge branch 'master' into format-config 2020-10-29 15:11:45 -06:00
parsonsmatt
8c19140545 Add style guide [ci skip] 2020-10-29 07:48:53 -06:00
parsonsmatt
34ae916bf6 warnings, more tidying up 2020-10-29 07:43:05 -06:00
parsonsmatt
17b0da892f fix 2020-10-29 07:27:10 -06:00
parsonsmatt
31f7b7f6c3 fix parse error 2020-10-29 07:23:16 -06:00
parsonsmatt
ea032a9fc5 major formatting stuff 2020-10-28 23:04:02 -06:00
parsonsmatt
58575433ff Merge branch 'master' into format-config 2020-10-28 21:37:57 -06:00
parsonsmatt
d7a47ae8f9 lol 2020-10-28 13:52:07 -06:00
parsonsmatt
e92f4e0fb0 update travis 2020-10-28 13:48:36 -06:00
parsonsmatt
b5de5d81c7 Add stylish-haskell.yaml, update spacing to 4 in configs 2020-10-28 13:18:23 -06:00
19 changed files with 3060 additions and 2809 deletions

View File

@ -11,8 +11,8 @@ insert_final_newline = true
[*.{hs,md,php}] [*.{hs,md,php}]
indent_style = space indent_style = space
indent_size = 2 indent_size = 4
tab_width = 2 tab_width = 4
end_of_line = lf end_of_line = lf
charset = utf-8 charset = utf-8
trim_trailing_whitespace = true trim_trailing_whitespace = true

View File

@ -1,13 +1,14 @@
Before submitting your PR, check that you've: Before submitting your PR, check that you've:
- [ ] Bumped the version number - [ ] Bumped the version number.
- [ ] Documented new APIs with [Haddock markup](https://www.haskell.org/haddock/doc/html/index.html) - [ ] Documented new APIs with [Haddock markup](https://www.haskell.org/haddock/doc/html/index.html).
- [ ] Added [`@since` declarations](http://haskell-haddock.readthedocs.io/en/latest/markup.html#since) to the Haddock - [ ] Added [`@since` declarations](http://haskell-haddock.readthedocs.io/en/latest/markup.html#since) to the Haddock.
- [ ] Ran `stylish-haskell` and otherwise adhered to the [style guide](https://github.com/bitemyapp/esqueleto/blob/master/style-guide.yaml).
After submitting your PR: After submitting your PR:
- [ ] Update the Changelog.md file with a link to your PR - [ ] Update the Changelog.md file with a link to your PR.
- [ ] Check that CI passes (or if it fails, for reasons unrelated to your change, like CI timeouts) - [ ] Check that CI passes (or if it fails, for reasons unrelated to your change, like CI timeouts).
<!---Thanks so much for contributing! :) <!---Thanks so much for contributing! :)

View File

@ -69,7 +69,7 @@ jobs:
key: ${{ runner.os }}-${{ matrix.ghc }}-${{ hashFiles('cabal.project.freeze') }} key: ${{ runner.os }}-${{ matrix.ghc }}-${{ hashFiles('cabal.project.freeze') }}
restore-keys: | restore-keys: |
${{ runner.os }}-${{ matrix.ghc }}- ${{ runner.os }}-${{ matrix.ghc }}-
- run: cabal v2-build $CONFIG - run: cabal v2-build --disable-optimization -j $CONFIG
- run: cabal v2-test $CONFIG - run: cabal v2-test --disable-optimization -j $CONFIG
- run: cabal v2-haddock $CONFIG - run: cabal v2-haddock -j $CONFIG
- run: cabal v2-sdist - run: cabal v2-sdist

39
.stylish-haskell.yaml Normal file
View File

@ -0,0 +1,39 @@
steps:
- imports:
align: none
list_align: with_module_name
pad_module_names: false
long_list_align: new_line_multiline
empty_list_align: inherit
list_padding: 7 # length "import "
separate_lists: false
space_surround: false
- language_pragmas:
style: vertical
align: false
remove_redundant: true
- simple_align:
cases: false
top_level_patterns: false
records: false
- trailing_whitespace: {}
indent: 4
columns: 80
newline: native
language_extensions:
- BlockArguments
- DataKinds
- DeriveGeneric
- DerivingStrategies
- DerivingVia
- ExplicitForAll
- FlexibleContexts
- MultiParamTypeClasses
- NamedFieldPuns
- OverloadedStrings
- QuantifiedConstraints
- RecordWildCards
- ScopedTypeVariables
- TemplateHaskell
- TypeApplications
- ViewPatterns

View File

@ -1,7 +1,5 @@
language: c language: c
sudo: false
services: services:
- mysql - mysql
@ -25,8 +23,9 @@ env:
- GHCVER=nightly - GHCVER=nightly
jobs: jobs:
fast_finish: true
allow_failures: allow_failures:
- GHCVER=nightly - env: GHCVER=nightly
install: install:
- export STACK_YAML=stack-$GHCVER.yaml - export STACK_YAML=stack-$GHCVER.yaml

View File

@ -61,10 +61,18 @@ library
, transformers >=0.2 , transformers >=0.2
, unliftio , unliftio
, unordered-containers >=0.2 , unordered-containers >=0.2
if impl(ghc >=8.0) ghc-options:
ghc-options: -Wall -Wno-redundant-constraints -Wall
else -Wno-redundant-constraints
ghc-options: -Wall -Wincomplete-uni-patterns
-Wincomplete-record-updates
-Wpartial-fields
-Wmissing-home-modules
-Widentities
-Wredundant-constraints
-Wcpp-undef
-Wcpp-undef
-Wmonomorphism-restriction
default-language: Haskell2010 default-language: Haskell2010
test-suite mysql test-suite mysql

View File

@ -1,16 +1,15 @@
{-# LANGUAGE CPP {-# LANGUAGE CPP #-}
, DataKinds {-# LANGUAGE DataKinds #-}
, FlexibleContexts {-# LANGUAGE FlexibleContexts #-}
, FlexibleInstances {-# LANGUAGE FlexibleInstances #-}
, FunctionalDependencies {-# LANGUAGE FunctionalDependencies #-}
, GADTs {-# LANGUAGE GADTs #-}
, MultiParamTypeClasses {-# LANGUAGE MultiParamTypeClasses #-}
, TypeOperators {-# LANGUAGE OverloadedStrings #-}
, TypeFamilies {-# LANGUAGE PatternSynonyms #-}
, UndecidableInstances {-# LANGUAGE TypeFamilies #-}
, OverloadedStrings {-# LANGUAGE TypeOperators #-}
, PatternSynonyms {-# LANGUAGE UndecidableInstances #-}
#-}
-- | This module contains a new way (introduced in 3.3.3.0) of using @FROM@ in -- | This module contains a new way (introduced in 3.3.3.0) of using @FROM@ in
-- Haskell. The old method was a bit finicky and could permit runtime errors, -- Haskell. The old method was a bit finicky and could permit runtime errors,
@ -59,22 +58,103 @@ module Database.Esqueleto.Experimental
, ToAlias(..) , ToAlias(..)
, ToAliasReference(..) , ToAliasReference(..)
-- * The Normal Stuff -- * The Normal Stuff
, where_, groupBy, orderBy, rand, asc, desc, limit, offset
, distinct, distinctOn, don, distinctOnOrderBy, having, locking , where_
, sub_select, (^.), (?.) , groupBy
, val, isNothing, just, nothing, joinV, withNonNull , orderBy
, countRows, count, countDistinct , rand
, not_, (==.), (>=.), (>.), (<=.), (<.), (!=.), (&&.), (||.) , asc
, between, (+.), (-.), (/.), (*.) , desc
, random_, round_, ceiling_, floor_ , limit
, min_, max_, sum_, avg_, castNum, castNumM , offset
, coalesce, coalesceDefault
, lower_, upper_, trim_, ltrim_, rtrim_, length_, left_, right_ , distinct
, like, ilike, (%), concat_, (++.), castString , distinctOn
, subList_select, valList, justList , don
, in_, notIn, exists, notExists , distinctOnOrderBy
, set, (=.), (+=.), (-=.), (*=.), (/=.) , having
, case_, toBaseId , locking
, sub_select
, (^.)
, (?.)
, val
, isNothing
, just
, nothing
, joinV
, withNonNull
, countRows
, count
, countDistinct
, not_
, (==.)
, (>=.)
, (>.)
, (<=.)
, (<.)
, (!=.)
, (&&.)
, (||.)
, between
, (+.)
, (-.)
, (/.)
, (*.)
, random_
, round_
, ceiling_
, floor_
, min_
, max_
, sum_
, avg_
, castNum
, castNumM
, coalesce
, coalesceDefault
, lower_
, upper_
, trim_
, ltrim_
, rtrim_
, length_
, left_
, right_
, like
, ilike
, (%)
, concat_
, (++.)
, castString
, subList_select
, valList
, justList
, in_
, notIn
, exists
, notExists
, set
, (=.)
, (+=.)
, (-=.)
, (*=.)
, (/=.)
, case_
, toBaseId
, subSelect , subSelect
, subSelectMaybe , subSelectMaybe
, subSelectCount , subSelectCount
@ -132,22 +212,20 @@ module Database.Esqueleto.Experimental
-- $reexports -- $reexports
, deleteKey , deleteKey
, module Database.Esqueleto.Internal.PersistentImport , module Database.Esqueleto.Internal.PersistentImport
) ) where
where
import qualified Control.Monad.Trans.Writer as W
import qualified Control.Monad.Trans.State as S
import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Class (lift)
import qualified Control.Monad.Trans.State as S
import qualified Control.Monad.Trans.Writer as W
#if __GLASGOW_HASKELL__ < 804 #if __GLASGOW_HASKELL__ < 804
import Data.Semigroup import Data.Semigroup
#endif #endif
import Data.Proxy (Proxy(..)) import Data.Proxy (Proxy(..))
import qualified Data.Text.Lazy.Builder as TLB import qualified Data.Text.Lazy.Builder as TLB
import Database.Esqueleto.Internal.Internal hiding (From, from, on)
import Database.Esqueleto.Internal.PersistentImport import Database.Esqueleto.Internal.PersistentImport
import Database.Esqueleto.Internal.Internal hiding (from, on, From)
import GHC.TypeLits import GHC.TypeLits
-- $setup -- $setup
-- --
-- If you're already using "Database.Esqueleto", then you can get -- If you're already using "Database.Esqueleto", then you can get
@ -460,14 +538,13 @@ import GHC.TypeLits
data (:&) a b = a :& b data (:&) a b = a :& b
infixl 2 :& infixl 2 :&
data SqlSetOperation a = data SqlSetOperation a
SqlSetUnion (SqlSetOperation a) (SqlSetOperation a) = SqlSetUnion (SqlSetOperation a) (SqlSetOperation a)
| SqlSetUnionAll (SqlSetOperation a) (SqlSetOperation a) | SqlSetUnionAll (SqlSetOperation a) (SqlSetOperation a)
| SqlSetExcept (SqlSetOperation a) (SqlSetOperation a) | SqlSetExcept (SqlSetOperation a) (SqlSetOperation a)
| SqlSetIntersect (SqlSetOperation a) (SqlSetOperation a) | SqlSetIntersect (SqlSetOperation a) (SqlSetOperation a)
| SelectQueryP NeedParens (SqlQuery a) | SelectQueryP NeedParens (SqlQuery a)
-- $sql-set-operations -- $sql-set-operations
-- --
-- Data type that represents SQL set operations. This includes -- Data type that represents SQL set operations. This includes
@ -502,32 +579,28 @@ data SqlSetOperation a =
-- @ -- @
-- --
{-# DEPRECATED Union "/Since: 3.4.0.0/ - \ {-# DEPRECATED Union "/Since: 3.4.0.0/ - Use the 'union_' function instead of the 'Union' data constructor" #-}
Use the 'union_' function instead of the 'Union' data constructor" #-}
data Union a b = a `Union` b data Union a b = a `Union` b
-- | @UNION@ SQL set operation. Can be used as an infix function between 'SqlQuery' values. -- | @UNION@ SQL set operation. Can be used as an infix function between 'SqlQuery' values.
union_ :: a -> b -> Union a b union_ :: a -> b -> Union a b
union_ = Union union_ = Union
{-# DEPRECATED UnionAll "/Since: 3.4.0.0/ - \ {-# DEPRECATED UnionAll "/Since: 3.4.0.0/ - Use the 'unionAll_' function instead of the 'UnionAll' data constructor" #-}
Use the 'unionAll_' function instead of the 'UnionAll' data constructor" #-}
data UnionAll a b = a `UnionAll` b data UnionAll a b = a `UnionAll` b
-- | @UNION@ @ALL@ SQL set operation. Can be used as an infix function between 'SqlQuery' values. -- | @UNION@ @ALL@ SQL set operation. Can be used as an infix function between 'SqlQuery' values.
unionAll_ :: a -> b -> UnionAll a b unionAll_ :: a -> b -> UnionAll a b
unionAll_ = UnionAll unionAll_ = UnionAll
{-# DEPRECATED Except "/Since: 3.4.0.0/ - \ {-# DEPRECATED Except "/Since: 3.4.0.0/ - Use the 'except_' function instead of the 'Except' data constructor" #-}
Use the 'except_' function instead of the 'Except' data constructor" #-}
data Except a b = a `Except` b data Except a b = a `Except` b
-- | @EXCEPT@ SQL set operation. Can be used as an infix function between 'SqlQuery' values. -- | @EXCEPT@ SQL set operation. Can be used as an infix function between 'SqlQuery' values.
except_ :: a -> b -> Except a b except_ :: a -> b -> Except a b
except_ = Except except_ = Except
{-# DEPRECATED Intersect "/Since: 3.4.0.0/ - \ {-# DEPRECATED Intersect "/Since: 3.4.0.0/ - Use the 'intersect_' function instead of the 'Intersect' data constructor" #-}
Use the 'intersect_' function instead of the 'Intersect' data constructor" #-}
data Intersect a b = a `Intersect` b data Intersect a b = a `Intersect` b
-- | @INTERSECT@ SQL set operation. Can be used as an infix function between 'SqlQuery' values. -- | @INTERSECT@ SQL set operation. Can be used as an infix function between 'SqlQuery' values.
@ -539,14 +612,19 @@ class SetOperationT a ~ b => ToSetOperation a b | a -> b where
instance ToSetOperation (SqlSetOperation a) a where instance ToSetOperation (SqlSetOperation a) a where
toSetOperation = id toSetOperation = id
instance ToSetOperation (SqlQuery a) a where instance ToSetOperation (SqlQuery a) a where
toSetOperation = SelectQueryP Never toSetOperation = SelectQueryP Never
instance (ToSetOperation a c, ToSetOperation b c) => ToSetOperation (Union a b) c where instance (ToSetOperation a c, ToSetOperation b c) => ToSetOperation (Union a b) c where
toSetOperation (Union a b) = SqlSetUnion (toSetOperation a) (toSetOperation b) toSetOperation (Union a b) = SqlSetUnion (toSetOperation a) (toSetOperation b)
instance (ToSetOperation a c, ToSetOperation b c) => ToSetOperation (UnionAll a b) c where instance (ToSetOperation a c, ToSetOperation b c) => ToSetOperation (UnionAll a b) c where
toSetOperation (UnionAll a b) = SqlSetUnionAll (toSetOperation a) (toSetOperation b) toSetOperation (UnionAll a b) = SqlSetUnionAll (toSetOperation a) (toSetOperation b)
instance (ToSetOperation a c, ToSetOperation b c) => ToSetOperation (Except a b) c where instance (ToSetOperation a c, ToSetOperation b c) => ToSetOperation (Except a b) c where
toSetOperation (Except a b) = SqlSetExcept (toSetOperation a) (toSetOperation b) toSetOperation (Except a b) = SqlSetExcept (toSetOperation a) (toSetOperation b)
instance (ToSetOperation a c, ToSetOperation b c) => ToSetOperation (Intersect a b) c where instance (ToSetOperation a c, ToSetOperation b c) => ToSetOperation (Intersect a b) c where
toSetOperation (Intersect a b) = SqlSetIntersect (toSetOperation a) (toSetOperation b) toSetOperation (Intersect a b) = SqlSetIntersect (toSetOperation a) (toSetOperation b)
@ -558,12 +636,10 @@ type family SetOperationT a where
SetOperationT (SqlQuery a) = a SetOperationT (SqlQuery a) = a
SetOperationT (SqlSetOperation a) = a SetOperationT (SqlSetOperation a) = a
{-# DEPRECATED SelectQuery "/Since: 3.4.0.0/ - \ {-# DEPRECATED SelectQuery "/Since: 3.4.0.0/ - It is no longer necessary to tag 'SqlQuery' values with @SelectQuery@" #-}
It is no longer necessary to tag 'SqlQuery' values with @SelectQuery@" #-}
pattern SelectQuery :: SqlQuery a -> SqlSetOperation a pattern SelectQuery :: SqlQuery a -> SqlSetOperation a
pattern SelectQuery q = SelectQueryP Never q pattern SelectQuery q = SelectQueryP Never q
-- | Data type that represents the syntax of a 'JOIN' tree. In practice, -- | Data type that represents the syntax of a 'JOIN' tree. In practice,
-- only the @Table@ constructor is used directly when writing queries. For example, -- only the @Table@ constructor is used directly when writing queries. For example,
-- --
@ -688,6 +764,7 @@ type family ToFromT a where
ToFromT (RightOuterJoin a b) = TypeError (JoinErrorMsg "RightOuterJoin") ToFromT (RightOuterJoin a b) = TypeError (JoinErrorMsg "RightOuterJoin")
ToFromT (FullOuterJoin a b) = TypeError (JoinErrorMsg "FullOuterJoin") ToFromT (FullOuterJoin a b) = TypeError (JoinErrorMsg "FullOuterJoin")
data Lateral data Lateral
data NotLateral data NotLateral
@ -713,6 +790,7 @@ instance {-# OVERLAPPABLE #-} ToFrom (LeftOuterJoin a b) where
instance {-# OVERLAPPABLE #-} ToFrom (RightOuterJoin a b) where instance {-# OVERLAPPABLE #-} ToFrom (RightOuterJoin a b) where
toFrom = undefined toFrom = undefined
instance {-# OVERLAPPABLE #-} ToFrom (FullOuterJoin a b) where instance {-# OVERLAPPABLE #-} ToFrom (FullOuterJoin a b) where
toFrom = undefined toFrom = undefined
instance ( ToAlias a instance ( ToAlias a
@ -760,23 +838,32 @@ instance (ToFrom a, ToFromT a ~ a', ToFrom b, ToFromT b ~ b')
=> ToInnerJoin NotLateral a b (a' :& b') where => ToInnerJoin NotLateral a b (a' :& b') where
toInnerJoin _ lhs rhs on' = InnerJoinFrom (toFrom lhs) (toFrom rhs, on') toInnerJoin _ lhs rhs on' = InnerJoinFrom (toFrom lhs) (toFrom rhs, on')
instance ( ToFrom a instance
( ToFrom a
, ToFromT a ~ a' , ToFromT a ~ a'
, ToInnerJoin (IsLateral b) a b b' , ToInnerJoin (IsLateral b) a b b'
) => ToFrom (InnerJoin a (b, b' -> SqlExpr (Value Bool))) where )
=>
ToFrom (InnerJoin a (b, b' -> SqlExpr (Value Bool)))
where
toFrom (InnerJoin lhs (rhs, on')) = toFrom (InnerJoin lhs (rhs, on')) =
let let toProxy :: b -> Proxy (IsLateral b)
toProxy :: b -> Proxy (IsLateral b)
toProxy _ = Proxy toProxy _ = Proxy
in toInnerJoin (toProxy rhs) lhs rhs on' in
toInnerJoin (toProxy rhs) lhs rhs on'
instance ( ToFrom a instance
( ToFrom a
, ToFrom b , ToFrom b
, ToFromT (CrossJoin a b) ~ (ToFromT a :& ToFromT b) , ToFromT (CrossJoin a b) ~ (ToFromT a :& ToFromT b)
) => ToFrom (CrossJoin a b) where )
=>
ToFrom (CrossJoin a b)
where
toFrom (CrossJoin lhs rhs) = CrossJoinFrom (toFrom lhs) (toFrom rhs) toFrom (CrossJoin lhs rhs) = CrossJoinFrom (toFrom lhs) (toFrom rhs)
instance {-# OVERLAPPING #-} instance {-# OVERLAPPING #-}
( ToFrom a ( ToFrom a
, ToFromT a ~ a' , ToFromT a ~ a'
, SqlSelect b r , SqlSelect b r
@ -808,15 +895,20 @@ instance ( ToFrom a
) => ToLeftJoin NotLateral a b (a' :& mb) where ) => ToLeftJoin NotLateral a b (a' :& mb) where
toLeftJoin _ lhs rhs on' = LeftJoinFrom (toFrom lhs) (toFrom rhs, on') toLeftJoin _ lhs rhs on' = LeftJoinFrom (toFrom lhs) (toFrom rhs, on')
instance ( ToLeftJoin (IsLateral b) a b b' instance
) => ToFrom (LeftOuterJoin a (b, b' -> SqlExpr (Value Bool))) where ( ToLeftJoin (IsLateral b) a b b'
)
=>
ToFrom (LeftOuterJoin a (b, b' -> SqlExpr (Value Bool)))
where
toFrom (LeftOuterJoin lhs (rhs, on')) = toFrom (LeftOuterJoin lhs (rhs, on')) =
let let toProxy :: b -> Proxy (IsLateral b)
toProxy :: b -> Proxy (IsLateral b)
toProxy _ = Proxy toProxy _ = Proxy
in toLeftJoin (toProxy rhs) lhs rhs on' in
toLeftJoin (toProxy rhs) lhs rhs on'
instance ( ToFrom a instance
( ToFrom a
, ToFromT a ~ a' , ToFromT a ~ a'
, ToFrom b , ToFrom b
, ToFromT b ~ b' , ToFromT b ~ b'
@ -825,18 +917,27 @@ instance ( ToFrom a
, ToMaybe b' , ToMaybe b'
, mb ~ ToMaybeT b' , mb ~ ToMaybeT b'
, ErrorOnLateral b , ErrorOnLateral b
) => ToFrom (FullOuterJoin a (b, (ma :& mb) -> SqlExpr (Value Bool))) where )
toFrom (FullOuterJoin lhs (rhs, on')) = FullJoinFrom (toFrom lhs) (toFrom rhs, on') =>
ToFrom (FullOuterJoin a (b, (ma :& mb) -> SqlExpr (Value Bool)))
where
toFrom (FullOuterJoin lhs (rhs, on')) =
FullJoinFrom (toFrom lhs) (toFrom rhs, on')
instance ( ToFrom a instance
( ToFrom a
, ToFromT a ~ a' , ToFromT a ~ a'
, ToMaybe a' , ToMaybe a'
, ma ~ ToMaybeT a' , ma ~ ToMaybeT a'
, ToFrom b , ToFrom b
, ToFromT b ~ b' , ToFromT b ~ b'
, ErrorOnLateral b , ErrorOnLateral b
) => ToFrom (RightOuterJoin a (b, (ma :& b') -> SqlExpr (Value Bool))) where )
toFrom (RightOuterJoin lhs (rhs, on')) = RightJoinFrom (toFrom lhs) (toFrom rhs, on') =>
ToFrom (RightOuterJoin a (b, (ma :& b') -> SqlExpr (Value Bool)))
where
toFrom (RightOuterJoin lhs (rhs, on')) =
RightJoinFrom (toFrom lhs) (toFrom rhs, on')
type family Nullable a where type family Nullable a where
Nullable (Maybe a) = a Nullable (Maybe a) = a
@ -873,47 +974,68 @@ instance (ToMaybe a, ToMaybe b) => ToMaybe (a :& b) where
instance (ToMaybe a, ToMaybe b) => ToMaybe (a,b) where instance (ToMaybe a, ToMaybe b) => ToMaybe (a,b) where
toMaybe (a, b) = (toMaybe a, toMaybe b) toMaybe (a, b) = (toMaybe a, toMaybe b)
instance ( ToMaybe a instance
( ToMaybe a
, ToMaybe b , ToMaybe b
, ToMaybe c , ToMaybe c
) => ToMaybe (a,b,c) where )
=>
ToMaybe (a,b,c)
where
toMaybe = to3 . toMaybe . from3 toMaybe = to3 . toMaybe . from3
instance ( ToMaybe a instance
( ToMaybe a
, ToMaybe b , ToMaybe b
, ToMaybe c , ToMaybe c
, ToMaybe d , ToMaybe d
) => ToMaybe (a,b,c,d) where )
=>
ToMaybe (a,b,c,d)
where
toMaybe = to4 . toMaybe . from4 toMaybe = to4 . toMaybe . from4
instance ( ToMaybe a instance
( ToMaybe a
, ToMaybe b , ToMaybe b
, ToMaybe c , ToMaybe c
, ToMaybe d , ToMaybe d
, ToMaybe e , ToMaybe e
) => ToMaybe (a,b,c,d,e) where )
=>
ToMaybe (a,b,c,d,e)
where
toMaybe = to5 . toMaybe . from5 toMaybe = to5 . toMaybe . from5
instance ( ToMaybe a instance
( ToMaybe a
, ToMaybe b , ToMaybe b
, ToMaybe c , ToMaybe c
, ToMaybe d , ToMaybe d
, ToMaybe e , ToMaybe e
, ToMaybe f , ToMaybe f
) => ToMaybe (a,b,c,d,e,f) where )
=>
ToMaybe (a,b,c,d,e,f)
where
toMaybe = to6 . toMaybe . from6 toMaybe = to6 . toMaybe . from6
instance ( ToMaybe a instance
( ToMaybe a
, ToMaybe b , ToMaybe b
, ToMaybe c , ToMaybe c
, ToMaybe d , ToMaybe d
, ToMaybe e , ToMaybe e
, ToMaybe f , ToMaybe f
, ToMaybe g , ToMaybe g
) => ToMaybe (a,b,c,d,e,f,g) where )
=>
ToMaybe (a,b,c,d,e,f,g)
where
toMaybe = to7 . toMaybe . from7 toMaybe = to7 . toMaybe . from7
instance ( ToMaybe a instance
( ToMaybe a
, ToMaybe b , ToMaybe b
, ToMaybe c , ToMaybe c
, ToMaybe d , ToMaybe d
@ -921,7 +1043,10 @@ instance ( ToMaybe a
, ToMaybe f , ToMaybe f
, ToMaybe g , ToMaybe g
, ToMaybe h , ToMaybe h
) => ToMaybe (a,b,c,d,e,f,g,h) where )
=>
ToMaybe (a,b,c,d,e,f,g,h)
where
toMaybe = to8 . toMaybe . from8 toMaybe = to8 . toMaybe . from8
-- | 'FROM' clause, used to bring entities into scope. -- | 'FROM' clause, used to bring entities into scope.
@ -1006,12 +1131,10 @@ from parts = do
SqlSetIntersect o1 o2 -> doSetOperation "INTERSECT" info o1 o2 SqlSetIntersect o1 o2 -> doSetOperation "INTERSECT" info o1 o2
doSetOperation operationText info o1 o2 = doSetOperation operationText info o1 o2 =
let let (q1, v1) = operationToSql o1 info
(q1, v1) = operationToSql o1 info
(q2, v2) = operationToSql o2 info (q2, v2) = operationToSql o2 info
in (q1 <> " " <> operationText <> " " <> q2, v1 <> v2) in (q1 <> " " <> operationText <> " " <> q2, v1 <> v2)
runFrom (InnerJoinFrom leftPart (rightPart, on')) = do runFrom (InnerJoinFrom leftPart (rightPart, on')) = do
(leftVal, leftFrom) <- runFrom leftPart (leftVal, leftFrom) <- runFrom leftPart
(rightVal, rightFrom) <- runFrom rightPart (rightVal, rightFrom) <- runFrom rightPart
@ -1053,7 +1176,9 @@ from parts = do
let ret = (toMaybe leftVal) :& (toMaybe rightVal) let ret = (toMaybe leftVal) :& (toMaybe rightVal)
pure $ (ret, FromJoin leftFrom FullOuterJoinKind rightFrom (Just (on' ret))) pure $ (ret, FromJoin leftFrom FullOuterJoinKind rightFrom (Just (on' ret)))
fromSubQuery :: ( SqlSelect a r fromSubQuery
::
( SqlSelect a r
, ToAlias a , ToAlias a
, ToAliasReference a , ToAliasReference a
) )
@ -1072,8 +1197,6 @@ fromSubQuery subqueryType subquery = do
ref <- toAliasReference subqueryAlias aliasedValue ref <- toAliasReference subqueryAlias aliasedValue
pure (ref , FromQuery subqueryAlias (\info -> toRawSql SELECT info aliasedQuery) subqueryType) pure (ref , FromQuery subqueryAlias (\info -> toRawSql SELECT info aliasedQuery) subqueryType)
-- | @WITH@ clause used to introduce a [Common Table Expression (CTE)](https://en.wikipedia.org/wiki/Hierarchical_and_recursive_queries_in_SQL#Common_table_expression). -- | @WITH@ clause used to introduce a [Common Table Expression (CTE)](https://en.wikipedia.org/wiki/Hierarchical_and_recursive_queries_in_SQL#Common_table_expression).
-- CTEs are supported in most modern SQL engines and can be useful -- CTEs are supported in most modern SQL engines and can be useful
-- in performance tuning. In Esqueleto, CTEs should be used as a -- in performance tuning. In Esqueleto, CTEs should be used as a
@ -1243,7 +1366,6 @@ instance ( ToAlias a
) => ToAlias (a,b,c,d,e,f,g,h) where ) => ToAlias (a,b,c,d,e,f,g,h) where
toAlias x = to8 <$> (toAlias $ from8 x) toAlias x = to8 <$> (toAlias $ from8 x)
{-# DEPRECATED ToAliasReferenceT "This type alias doesn't do anything. Please delete it. Will be removed in the next release." #-} {-# DEPRECATED ToAliasReferenceT "This type alias doesn't do anything. Please delete it. Will be removed in the next release." #-}
type ToAliasReferenceT a = a type ToAliasReferenceT a = a
@ -1265,6 +1387,7 @@ instance ToAliasReference (SqlExpr (Entity a)) where
instance ToAliasReference (SqlExpr (Maybe (Entity a))) where instance ToAliasReference (SqlExpr (Maybe (Entity a))) where
toAliasReference s (EMaybe e) = EMaybe <$> toAliasReference s e toAliasReference s (EMaybe e) = EMaybe <$> toAliasReference s e
instance (ToAliasReference a, ToAliasReference b) => ToAliasReference (a, b) where instance (ToAliasReference a, ToAliasReference b) => ToAliasReference (a, b) where
toAliasReference ident (a,b) = (,) <$> (toAliasReference ident a) <*> (toAliasReference ident b) toAliasReference ident (a,b) = (,) <$> (toAliasReference ident a) <*> (toAliasReference ident b)
@ -1325,5 +1448,6 @@ class RecursiveCteUnion a where
instance RecursiveCteUnion (a -> b -> Union a b) where instance RecursiveCteUnion (a -> b -> Union a b) where
unionKeyword _ = "\nUNION\n" unionKeyword _ = "\nUNION\n"
instance RecursiveCteUnion (a -> b -> UnionAll a b) where instance RecursiveCteUnion (a -> b -> UnionAll a b) where
unionKeyword _ = "\nUNION ALL\n" unionKeyword _ = "\nUNION ALL\n"

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,20 @@
{-# LANGUAGE DeriveDataTypeable {-# LANGUAGE DeriveDataTypeable #-}
, EmptyDataDecls {-# LANGUAGE EmptyDataDecls #-}
, FlexibleContexts {-# LANGUAGE FlexibleContexts #-}
, FlexibleInstances {-# LANGUAGE FlexibleInstances #-}
, FunctionalDependencies {-# LANGUAGE FunctionalDependencies #-}
, MultiParamTypeClasses {-# LANGUAGE GADTs #-}
, TypeFamilies {-# LANGUAGE MultiParamTypeClasses #-}
, UndecidableInstances {-# LANGUAGE TypeFamilies #-}
, GADTs {-# LANGUAGE UndecidableInstances #-}
#-}
-- | This is an internal module, anything exported by this module -- | This is an internal module, anything exported by this module
-- may change without a major version bump. Please use only -- may change without a major version bump. Please use only
-- "Database.Esqueleto" if possible. -- "Database.Esqueleto" if possible.
--
-- This module is deprecated as of 3.4.0.1, and will be removed in 3.5.0.0.
module Database.Esqueleto.Internal.Language module Database.Esqueleto.Internal.Language
{-# DEPRECATED "Use Database.Esqueleto.Internal.Internal instead. This module will be removed in 3.5.0.0 " #-}
( -- * The pretty face ( -- * The pretty face
from from
, Value(..) , Value(..)
@ -41,22 +44,90 @@ module Database.Esqueleto.Internal.Language
, when_ , when_
, then_ , then_
, else_ , else_
, where_, on, groupBy, orderBy, rand, asc, desc, limit, offset , where_
, distinct, distinctOn, don, distinctOnOrderBy, having, locking , on
, sub_select, (^.), (?.) , groupBy
, val, isNothing, just, nothing, joinV, withNonNull , orderBy
, countRows, count, countDistinct , rand
, not_, (==.), (>=.), (>.), (<=.), (<.), (!=.), (&&.), (||.) , asc
, between, (+.), (-.), (/.), (*.) , desc
, random_, round_, ceiling_, floor_ , limit
, min_, max_, sum_, avg_, castNum, castNumM , offset
, coalesce, coalesceDefault , distinct
, lower_, upper_, trim_, ltrim_, rtrim_, length_, left_, right_ , distinctOn
, like, ilike, (%), concat_, (++.), castString , don
, subList_select, valList, justList , distinctOnOrderBy
, in_, notIn, exists, notExists , having
, set, (=.), (+=.), (-=.), (*=.), (/=.) , locking
, case_, toBaseId, (<#), (<&>) , sub_select
, (^.)
, (?.)
, val
, isNothing
, just
, nothing
, joinV
, withNonNull
, countRows
, count
, countDistinct
, not_
, (==.)
, (>=.)
, (>.)
, (<=.)
, (<.)
, (!=.)
, (&&.)
, (||.)
, between
, (+.)
, (-.)
, (/.)
, (*.)
, random_
, round_
, ceiling_
, floor_
, min_
, max_
, sum_
, avg_
, castNum
, castNumM
, coalesce
, coalesceDefault
, lower_
, upper_
, trim_
, ltrim_
, rtrim_
, length_
, left_
, right_
, like
, ilike
, (%)
, concat_
, (++.)
, castString
, subList_select
, valList
, justList
, in_
, notIn
, exists
, notExists
, set
, (=.)
, (+=.)
, (-=.)
, (*=.)
, (/=.)
, case_
, toBaseId
, (<#)
, (<&>)
, subSelect , subSelect
, subSelectMaybe , subSelectMaybe
, subSelectCount , subSelectCount
@ -65,5 +136,5 @@ module Database.Esqueleto.Internal.Language
, subSelectUnsafe , subSelectUnsafe
) where ) where
import Database.Esqueleto.Internal.PersistentImport
import Database.Esqueleto.Internal.Internal import Database.Esqueleto.Internal.Internal
import Database.Esqueleto.Internal.PersistentImport

View File

@ -142,9 +142,36 @@ module Database.Esqueleto.Internal.PersistentImport
) where ) where
import Database.Persist.Sql hiding import Database.Persist.Sql hiding
( BackendSpecificFilter, Filter(..), PersistQuery, SelectOpt(..) ( BackendSpecificFilter
, Update(..), delete, deleteWhereCount, updateWhereCount, selectList , Filter(..)
, selectKeysList, deleteCascadeWhere, (=.), (+=.), (-=.), (*=.), (/=.) , PersistQuery
, (==.), (!=.), (<.), (>.), (<=.), (>=.), (<-.), (/<-.), (||.) , SelectOpt(..)
, listToJSON, mapToJSON, getPersistMap, limitOffsetOrder, selectSource , Update(..)
, update , count ) , count
, delete
, deleteCascadeWhere
, deleteWhereCount
, getPersistMap
, limitOffsetOrder
, listToJSON
, mapToJSON
, selectKeysList
, selectList
, selectSource
, update
, updateWhereCount
, (!=.)
, (*=.)
, (+=.)
, (-=.)
, (/<-.)
, (/=.)
, (<-.)
, (<.)
, (<=.)
, (=.)
, (==.)
, (>.)
, (>=.)
, (||.)
)

View File

@ -1,31 +1,27 @@
{-# LANGUAGE DeriveDataTypeable {-# LANGUAGE CPP #-}
, EmptyDataDecls {-# LANGUAGE ConstraintKinds #-}
, FlexibleContexts {-# LANGUAGE DeriveDataTypeable #-}
, FlexibleInstances {-# LANGUAGE EmptyDataDecls #-}
, FunctionalDependencies {-# LANGUAGE FlexibleContexts #-}
, MultiParamTypeClasses {-# LANGUAGE FlexibleInstances #-}
, TypeFamilies {-# LANGUAGE FunctionalDependencies #-}
, UndecidableInstances {-# LANGUAGE GADTs #-}
, GADTs {-# LANGUAGE InstanceSigs #-}
#-} {-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ConstraintKinds {-# LANGUAGE OverloadedStrings #-}
, EmptyDataDecls {-# LANGUAGE Rank2Types #-}
, FlexibleContexts {-# LANGUAGE ScopedTypeVariables #-}
, FlexibleInstances {-# LANGUAGE TypeFamilies #-}
, FunctionalDependencies {-# LANGUAGE UndecidableInstances #-}
, GADTs
, MultiParamTypeClasses
, OverloadedStrings
, UndecidableInstances
, ScopedTypeVariables
, InstanceSigs
, Rank2Types
, CPP
#-}
-- | This is an internal module, anything exported by this module -- | This is an internal module, anything exported by this module
-- may change without a major version bump. Please use only -- may change without a major version bump. Please use only
-- "Database.Esqueleto" if possible. -- "Database.Esqueleto" if possible.
--
-- This module is deprecated as of 3.4.0.1, and will be removed in 3.5.0.0.
module Database.Esqueleto.Internal.Sql module Database.Esqueleto.Internal.Sql
{-# DEPRECATED "Use Database.Esqueleto.Internal.Internal instead. This module will be removed in 3.5.0.0 " #-}
( -- * The pretty face ( -- * The pretty face
SqlQuery SqlQuery
, SqlExpr(..) , SqlExpr(..)

View File

@ -1,14 +1,14 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
-- | This module contain MySQL-specific functions. -- | This module contain MySQL-specific functions.
-- --
-- /Since: 2.2.8/ -- @since 2.2.8
module Database.Esqueleto.MySQL module Database.Esqueleto.MySQL
( random_ ( random_
) where ) where
import Database.Esqueleto.Internal.Language hiding (random_) import Database.Esqueleto.Internal.Internal hiding (random_)
import Database.Esqueleto.Internal.PersistentImport import Database.Esqueleto.Internal.PersistentImport
import Database.Esqueleto.Internal.Sql
-- | (@random()@) Split out into database specific modules -- | (@random()@) Split out into database specific modules
-- because MySQL uses `rand()`. -- because MySQL uses `rand()`.

View File

@ -1,11 +1,13 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings {-# LANGUAGE GADTs #-}
, GADTs, CPP, Rank2Types {-# LANGUAGE OverloadedStrings #-}
, ScopedTypeVariables {-# LANGUAGE Rank2Types #-}
#-} {-# LANGUAGE ScopedTypeVariables #-}
-- | This module contain PostgreSQL-specific functions. -- | This module contain PostgreSQL-specific functions.
-- --
-- /Since: 2.2.8/ -- @since: 2.2.8
module Database.Esqueleto.PostgreSQL module Database.Esqueleto.PostgreSQL
( AggMode(..) ( AggMode(..)
, arrayAggDistinct , arrayAggDistinct
@ -31,29 +33,24 @@ module Database.Esqueleto.PostgreSQL
#if __GLASGOW_HASKELL__ < 804 #if __GLASGOW_HASKELL__ < 804
import Data.Semigroup import Data.Semigroup
#endif #endif
import qualified Data.Text.Internal.Builder as TLB import Control.Arrow (first, (***))
import Data.Time.Clock (UTCTime)
import Database.Esqueleto.Internal.Language hiding (random_)
import Database.Esqueleto.Internal.PersistentImport hiding (upsert, upsertBy)
import Database.Esqueleto.Internal.Sql
import Database.Esqueleto.Internal.Internal (EsqueletoError(..), CompositeKeyError(..),
UnexpectedCaseError(..), SetClause, Ident(..),
uncommas, FinalResult(..), toUniqueDef,
KnowResult, renderUpdates, UnexpectedValueError(..))
import Database.Persist.Class (OnlyOneUniqueKey)
import Data.List.NonEmpty ( NonEmpty( (:|) ) )
import Data.Int (Int64)
import Data.Proxy (Proxy(..))
import Control.Arrow ((***), first)
import Control.Exception (throw) import Control.Exception (throw)
import Control.Monad (void) import Control.Monad (void)
import Control.Monad.IO.Class (MonadIO(..)) import Control.Monad.IO.Class (MonadIO(..))
import qualified Control.Monad.Trans.Reader as R import qualified Control.Monad.Trans.Reader as R
import Data.Int (Int64)
import Data.List.NonEmpty (NonEmpty((:|)))
import Data.Proxy (Proxy(..))
import qualified Data.Text.Internal.Builder as TLB
import Data.Time.Clock (UTCTime)
import Database.Esqueleto.Internal.Internal hiding (random_)
import Database.Esqueleto.Internal.PersistentImport hiding (upsert, upsertBy)
import Database.Persist.Class (OnlyOneUniqueKey)
-- | (@random()@) Split out into database specific modules -- | (@random()@) Split out into database specific modules
-- because MySQL uses `rand()`. -- because MySQL uses `rand()`.
-- --
-- /Since: 2.6.0/ -- @since 2.6.0
random_ :: (PersistField a, Num a) => SqlExpr (Value a) random_ :: (PersistField a, Num a) => SqlExpr (Value a)
random_ = unsafeSqlValue "RANDOM()" random_ = unsafeSqlValue "RANDOM()"
@ -69,7 +66,8 @@ maybeArray ::
maybeArray x = coalesceDefault [x] (emptyArray) maybeArray x = coalesceDefault [x] (emptyArray)
-- | Aggregate mode -- | Aggregate mode
data AggMode = AggModeAll -- ^ ALL data AggMode
= AggModeAll -- ^ ALL
| AggModeDistinct -- ^ DISTINCT | AggModeDistinct -- ^ DISTINCT
deriving (Show) deriving (Show)
@ -77,24 +75,26 @@ data AggMode = AggModeAll -- ^ ALL
-- --
-- /Do/ /not/ use this function directly, instead define a new function and give -- /Do/ /not/ use this function directly, instead define a new function and give
-- it a type (see `unsafeSqlBinOp`) -- it a type (see `unsafeSqlBinOp`)
unsafeSqlAggregateFunction :: unsafeSqlAggregateFunction
UnsafeSqlFunctionArgument a :: UnsafeSqlFunctionArgument a
=> TLB.Builder => TLB.Builder
-> AggMode -> AggMode
-> a -> a
-> [OrderByClause] -> [OrderByClause]
-> SqlExpr (Value b) -> SqlExpr (Value b)
unsafeSqlAggregateFunction name mode args orderByClauses = unsafeSqlAggregateFunction name mode args orderByClauses = ERaw Never $ \info ->
ERaw Never $ \info ->
let (orderTLB, orderVals) = makeOrderByNoNewline info orderByClauses let (orderTLB, orderVals) = makeOrderByNoNewline info orderByClauses
-- Don't add a space if we don't have order by clauses -- Don't add a space if we don't have order by clauses
orderTLBSpace = case orderByClauses of orderTLBSpace =
case orderByClauses of
[] -> "" [] -> ""
(_:_) -> " " (_:_) -> " "
(argsTLB, argsVals) = (argsTLB, argsVals) =
uncommas' $ map (\(ERaw _ f) -> f info) $ toArgList args uncommas' $ map (\(ERaw _ f) -> f info) $ toArgList args
aggMode = case mode of aggMode =
AggModeAll -> "" -- ALL is the default, so we don't need to case mode of
AggModeAll -> ""
-- ALL is the default, so we don't need to
-- specify it -- specify it
AggModeDistinct -> "DISTINCT " AggModeDistinct -> "DISTINCT "
in ( name <> parens (aggMode <> argsTLB <> orderTLBSpace <> orderTLB) in ( name <> parens (aggMode <> argsTLB <> orderTLBSpace <> orderTLB)
@ -103,8 +103,8 @@ unsafeSqlAggregateFunction name mode args orderByClauses =
--- | (@array_agg@) Concatenate input values, including @NULL@s, --- | (@array_agg@) Concatenate input values, including @NULL@s,
--- into an array. --- into an array.
arrayAggWith :: arrayAggWith
AggMode :: AggMode
-> SqlExpr (Value a) -> SqlExpr (Value a)
-> [OrderByClause] -> [OrderByClause]
-> SqlExpr (Value (Maybe [a])) -> SqlExpr (Value (Maybe [a]))
@ -118,18 +118,17 @@ arrayAgg x = arrayAggWith AggModeAll x []
-- | (@array_agg@) Concatenate distinct input values, including @NULL@s, into -- | (@array_agg@) Concatenate distinct input values, including @NULL@s, into
-- an array. -- an array.
-- --
-- /Since: 2.5.3/ -- @since 2.5.3
arrayAggDistinct :: arrayAggDistinct
(PersistField a, PersistField [a]) :: (PersistField a, PersistField [a])
=> SqlExpr (Value a) => SqlExpr (Value a)
-> SqlExpr (Value (Maybe [a])) -> SqlExpr (Value (Maybe [a]))
arrayAggDistinct x = arrayAggWith AggModeDistinct x [] arrayAggDistinct x = arrayAggWith AggModeDistinct x []
-- | (@array_remove@) Remove all elements equal to the given value from the -- | (@array_remove@) Remove all elements equal to the given value from the
-- array. -- array.
-- --
-- /Since: 2.5.3/ -- @since 2.5.3
arrayRemove :: SqlExpr (Value [a]) -> SqlExpr (Value a) -> SqlExpr (Value [a]) arrayRemove :: SqlExpr (Value [a]) -> SqlExpr (Value a) -> SqlExpr (Value [a])
arrayRemove arr elem' = unsafeSqlFunction "array_remove" (arr, elem') arrayRemove arr elem' = unsafeSqlFunction "array_remove" (arr, elem')
@ -154,7 +153,7 @@ stringAggWith mode expr delim os =
-- | (@string_agg@) Concatenate input values separated by a -- | (@string_agg@) Concatenate input values separated by a
-- delimiter. -- delimiter.
-- --
-- /Since: 2.2.8/ -- @since 2.2.8
stringAgg :: stringAgg ::
SqlString s SqlString s
=> SqlExpr (Value s) -- ^ Input values. => SqlExpr (Value s) -- ^ Input values.
@ -165,18 +164,21 @@ stringAgg expr delim = stringAggWith AggModeAll expr delim []
-- | (@chr@) Translate the given integer to a character. (Note the result will -- | (@chr@) Translate the given integer to a character. (Note the result will
-- depend on the character set of your database.) -- depend on the character set of your database.)
-- --
-- /Since: 2.2.11/ -- @since 2.2.11
chr :: SqlString s => SqlExpr (Value Int) -> SqlExpr (Value s) chr :: SqlString s => SqlExpr (Value Int) -> SqlExpr (Value s)
chr = unsafeSqlFunction "chr" chr = unsafeSqlFunction "chr"
now_ :: SqlExpr (Value UTCTime) now_ :: SqlExpr (Value UTCTime)
now_ = unsafeSqlFunction "NOW" () now_ = unsafeSqlFunction "NOW" ()
upsert :: (MonadIO m, upsert
PersistEntity record, ::
OnlyOneUniqueKey record, ( MonadIO m
PersistRecordBackend record SqlBackend, , PersistEntity record
IsPersistBackend (PersistEntityBackend record)) , OnlyOneUniqueKey record
, PersistRecordBackend record SqlBackend
, IsPersistBackend (PersistEntityBackend record)
)
=> record => record
-- ^ new record to insert -- ^ new record to insert
-> [SqlExpr (Update record)] -> [SqlExpr (Update record)]
@ -187,9 +189,12 @@ upsert record updates = do
uniqueKey <- onlyUnique record uniqueKey <- onlyUnique record
upsertBy uniqueKey record updates upsertBy uniqueKey record updates
upsertBy :: (MonadIO m, upsertBy
PersistEntity record, ::
IsPersistBackend (PersistEntityBackend record)) (MonadIO m
, PersistEntity record
, IsPersistBackend (PersistEntityBackend record)
)
=> Unique record => Unique record
-- ^ uniqueness constraint to find by -- ^ uniqueness constraint to find by
-> record -> record
@ -245,29 +250,30 @@ upsertBy uniqueKey record updates = do
-- the conflicting value is updated to the current plus the excluded. -- the conflicting value is updated to the current plus the excluded.
-- --
-- @since 3.1.3 -- @since 3.1.3
insertSelectWithConflict :: forall a m val. ( insertSelectWithConflict
FinalResult a, :: forall a m val
KnowResult a ~ (Unique val), . (FinalResult a, KnowResult a ~ Unique val, MonadIO m, PersistEntity val)
MonadIO m, => a
PersistEntity val) => -- ^ Unique constructor or a unique, this is used just to get the name of
a -- the postgres constraint, the value(s) is(are) never used, so if you have
-- ^ Unique constructor or a unique, this is used just to get the name of the postgres constraint, the value(s) is(are) never used, so if you have a unique "MyUnique 0", "MyUnique undefined" would work as well. -- a unique "MyUnique 0", "MyUnique undefined" would work as well.
-> SqlQuery (SqlExpr (Insertion val)) -> SqlQuery (SqlExpr (Insertion val))
-- ^ Insert query. -- ^ Insert query.
-> (SqlExpr (Entity val) -> SqlExpr (Entity val) -> [SqlExpr (Update val)]) -> (SqlExpr (Entity val) -> SqlExpr (Entity val) -> [SqlExpr (Update val)])
-- ^ A list of updates to be applied in case of the constraint being violated. The expression takes the current and excluded value to produce the updates. -- ^ A list of updates to be applied in case of the constraint being
-- violated. The expression takes the current and excluded value to produce
-- the updates.
-> SqlWriteT m () -> SqlWriteT m ()
insertSelectWithConflict unique query = void . insertSelectWithConflictCount unique query insertSelectWithConflict unique query =
void . insertSelectWithConflictCount unique query
-- | Same as 'insertSelectWithConflict' but returns the number of rows affected. -- | Same as 'insertSelectWithConflict' but returns the number of rows affected.
-- --
-- @since 3.1.3 -- @since 3.1.3
insertSelectWithConflictCount :: forall a val m. ( insertSelectWithConflictCount
FinalResult a, :: forall a val m
KnowResult a ~ (Unique val), . (FinalResult a, KnowResult a ~ Unique val, MonadIO m, PersistEntity val)
MonadIO m, => a
PersistEntity val) =>
a
-> SqlQuery (SqlExpr (Insertion val)) -> SqlQuery (SqlExpr (Insertion val))
-> (SqlExpr (Entity val) -> SqlExpr (Entity val) -> [SqlExpr (Update val)]) -> (SqlExpr (Entity val) -> SqlExpr (Entity val) -> [SqlExpr (Update val)])
-> SqlWriteT m Int64 -> SqlWriteT m Int64
@ -289,7 +295,7 @@ insertSelectWithConflictCount unique query conflictQuery = do
constraint = TLB.fromText . unDBName . uniqueDBName $ uniqueDef constraint = TLB.fromText . unDBName . uniqueDBName $ uniqueDef
renderedUpdates :: (BackendCompatible SqlBackend backend) => backend -> (TLB.Builder, [PersistValue]) renderedUpdates :: (BackendCompatible SqlBackend backend) => backend -> (TLB.Builder, [PersistValue])
renderedUpdates conn = renderUpdates conn updates renderedUpdates conn = renderUpdates conn updates
conflict conn = (foldr1 mappend ([ conflict conn = (mconcat ([
TLB.fromText "ON CONFLICT ON CONSTRAINT \"", TLB.fromText "ON CONFLICT ON CONSTRAINT \"",
constraint, constraint,
TLB.fromText "\" DO " TLB.fromText "\" DO "

View File

@ -1,4 +1,5 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-| {-|
This module contains PostgreSQL-specific JSON functions. This module contains PostgreSQL-specific JSON functions.
@ -135,17 +136,15 @@ module Database.Esqueleto.PostgreSQL.JSON
) where ) where
import Data.Text (Text) import Data.Text (Text)
import Database.Esqueleto.Internal.Language hiding ((?.), (-.), (||.)) import Database.Esqueleto.Internal.Language hiding ((-.), (?.), (||.))
import Database.Esqueleto.Internal.PersistentImport import Database.Esqueleto.Internal.PersistentImport
import Database.Esqueleto.Internal.Sql import Database.Esqueleto.Internal.Sql
import Database.Esqueleto.PostgreSQL.JSON.Instances import Database.Esqueleto.PostgreSQL.JSON.Instances
infixl 6 ->., ->>., #>., #>>. infixl 6 ->., ->>., #>., #>>.
infixl 6 @>., <@., ?., ?|., ?&. infixl 6 @>., <@., ?., ?|., ?&.
infixl 6 ||., -., --., #-. infixl 6 ||., -., --., #-.
-- | /Requires PostgreSQL version >= 9.3/ -- | /Requires PostgreSQL version >= 9.3/
-- --
-- This function extracts the jsonb value from a JSON array or object, -- This function extracts the jsonb value from a JSON array or object,

View File

@ -4,6 +4,8 @@
{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# language DerivingStrategies #-}
module Database.Esqueleto.PostgreSQL.JSON.Instances where module Database.Esqueleto.PostgreSQL.JSON.Instances where
import Data.Aeson (FromJSON(..), ToJSON(..), encode, eitherDecodeStrict) import Data.Aeson (FromJSON(..), ToJSON(..), encode, eitherDecodeStrict)
@ -18,15 +20,12 @@ import Database.Esqueleto.Internal.PersistentImport
import Database.Esqueleto.Internal.Sql (SqlExpr) import Database.Esqueleto.Internal.Sql (SqlExpr)
import GHC.Generics (Generic) import GHC.Generics (Generic)
-- | Newtype wrapper around any type with a JSON representation. -- | Newtype wrapper around any type with a JSON representation.
-- --
-- @since 3.1.0 -- @since 3.1.0
newtype JSONB a = JSONB { unJSONB :: a } newtype JSONB a = JSONB { unJSONB :: a }
deriving deriving stock
( Generic ( Generic
, FromJSON
, ToJSON
, Eq , Eq
, Foldable , Foldable
, Functor , Functor
@ -35,6 +34,10 @@ newtype JSONB a = JSONB { unJSONB :: a }
, Show , Show
, Traversable , Traversable
) )
deriving newtype
( FromJSON
, ToJSON
)
-- | 'SqlExpr' of a NULL-able 'JSONB' value. Hence the 'Maybe'. -- | 'SqlExpr' of a NULL-able 'JSONB' value. Hence the 'Maybe'.
-- --
@ -60,7 +63,8 @@ jsonbVal = just . val . JSONB
-- JSONKey "name" -- JSONKey "name"
-- --
-- NOTE: DO NOT USE ANY OF THE 'Num' METHODS ON THIS TYPE! -- NOTE: DO NOT USE ANY OF THE 'Num' METHODS ON THIS TYPE!
data JSONAccessor = JSONIndex Int data JSONAccessor
= JSONIndex Int
| JSONKey Text | JSONKey Text
deriving (Generic, Eq, Show) deriving (Generic, Eq, Show)

View File

@ -1,14 +1,14 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
-- | This module contain SQLite-specific functions. -- | This module contain SQLite-specific functions.
-- --
-- /Since: 2.2.8/ -- @since 2.2.8
module Database.Esqueleto.SQLite module Database.Esqueleto.SQLite
( random_ ( random_
) where ) where
import Database.Esqueleto.Internal.Language hiding (random_) import Database.Esqueleto.Internal.Internal hiding (random_)
import Database.Esqueleto.Internal.PersistentImport import Database.Esqueleto.Internal.PersistentImport
import Database.Esqueleto.Internal.Sql
-- | (@random()@) Split out into database specific modules -- | (@random()@) Split out into database specific modules
-- because MySQL uses `rand()`. -- because MySQL uses `rand()`.

9
style-guide.md Normal file
View File

@ -0,0 +1,9 @@
# Style Guide
- Please use `stylish-haskell` on the project to keep imports consistent and
clean. We have a custom [`.stylish-haskell.yaml`](.stylish-haskell.yaml) file.
You can run `stylish-haskell` from vim with `:%! stylish-haskell`.
- Four space indent.
- Prefer indentation over any other form of alignment.
- If text goes off the screen due to four space indentation, factor out
functions and values into names to reduce indentation.

View File

@ -1,26 +1,27 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-unused-binds #-} {-# OPTIONS_GHC -fno-warn-unused-binds #-}
{-# OPTIONS_GHC -fno-warn-deprecations #-} {-# OPTIONS_GHC -fno-warn-deprecations #-}
{-# LANGUAGE ConstraintKinds
, CPP, DerivingStrategies, StandaloneDeriving
, TypeApplications
, PartialTypeSignatures
, UndecidableInstances
, EmptyDataDecls
, FlexibleContexts
, FlexibleInstances
, DeriveGeneric
, GADTs
, GeneralizedNewtypeDeriving
, MultiParamTypeClasses
, OverloadedStrings
, QuasiQuotes
, Rank2Types
, TemplateHaskell
, TypeFamilies
, ScopedTypeVariables
, TypeSynonymInstances
#-}
module Common.Test module Common.Test
( tests ( tests
, testLocking , testLocking
@ -60,17 +61,18 @@ module Common.Test
, Key(..) , Key(..)
) where ) where
import Control.Monad (forM_, replicateM, replicateM_, void)
import Control.Monad.Catch (MonadCatch)
import Control.Monad.Reader (ask)
import Data.Either import Data.Either
import Data.Time import Data.Time
import Control.Monad (forM_, replicateM, replicateM_, void)
import Control.Monad.Reader (ask)
import Control.Monad.Catch (MonadCatch)
#if __GLASGOW_HASKELL__ >= 806 #if __GLASGOW_HASKELL__ >= 806
import Control.Monad.Fail (MonadFail) import Control.Monad.Fail (MonadFail)
#endif #endif
import Control.Monad.IO.Class (MonadIO(liftIO)) import Control.Monad.IO.Class (MonadIO(liftIO))
import Control.Monad.Logger (MonadLogger(..), NoLoggingT, runNoLoggingT) import Control.Monad.Logger (MonadLogger(..), NoLoggingT, runNoLoggingT)
import Control.Monad.Trans.Reader (ReaderT) import Control.Monad.Trans.Reader (ReaderT)
import qualified Data.Attoparsec.Text as AP
import Data.Char (toLower, toUpper) import Data.Char (toLower, toUpper)
import Data.Monoid ((<>)) import Data.Monoid ((<>))
import Database.Esqueleto import Database.Esqueleto
@ -79,18 +81,17 @@ import qualified Database.Esqueleto.Experimental as Experimental
import Database.Persist.TH import Database.Persist.TH
import Test.Hspec import Test.Hspec
import UnliftIO import UnliftIO
import qualified Data.Attoparsec.Text as AP
import Data.Conduit (ConduitT, (.|), runConduit) import Data.Conduit (ConduitT, runConduit, (.|))
import qualified Data.Conduit.List as CL import qualified Data.Conduit.List as CL
import qualified Data.List as L import qualified Data.List as L
import qualified Data.Set as S import qualified Data.Set as S
import qualified Data.Text as Text import qualified Data.Text as Text
import qualified Data.Text.Lazy.Builder as TLB
import qualified Data.Text.Internal.Lazy as TL import qualified Data.Text.Internal.Lazy as TL
import qualified Data.Text.Lazy.Builder as TLB
import qualified Database.Esqueleto.Internal.ExprParser as P
import qualified Database.Esqueleto.Internal.Sql as EI import qualified Database.Esqueleto.Internal.Sql as EI
import qualified UnliftIO.Resource as R import qualified UnliftIO.Resource as R
import qualified Database.Esqueleto.Internal.ExprParser as P
-- Test schema -- Test schema
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistUpperCase| share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistUpperCase|
@ -326,18 +327,17 @@ testSelect run = do
testSubSelect :: Run -> Spec testSubSelect :: Run -> Spec
testSubSelect run = do testSubSelect run = do
let let setup :: MonadIO m => SqlPersistT m ()
setup :: MonadIO m => SqlPersistT m ()
setup = do setup = do
_ <- insert $ Numbers 1 2 _ <- insert $ Numbers 1 2
_ <- insert $ Numbers 2 4 _ <- insert $ Numbers 2 4
_ <- insert $ Numbers 3 5 _ <- insert $ Numbers 3 5
_ <- insert $ Numbers 6 7 _ <- insert $ Numbers 6 7
pure () pure ()
describe "subSelect" $ do describe "subSelect" $ do
it "is safe for queries that may return multiple results" $ do it "is safe for queries that may return multiple results" $ do
let let query =
query =
from $ \n -> do from $ \n -> do
orderBy [asc (n ^. NumbersInt)] orderBy [asc (n ^. NumbersInt)]
pure (n ^. NumbersInt) pure (n ^. NumbersInt)
@ -360,8 +360,7 @@ testSubSelect run = do
v `shouldBe` [Value 1] v `shouldBe` [Value 1]
it "is safe for queries that may not return anything" $ do it "is safe for queries that may not return anything" $ do
let let query =
query =
from $ \n -> do from $ \n -> do
orderBy [asc (n ^. NumbersInt)] orderBy [asc (n ^. NumbersInt)]
limit 1 limit 1
@ -386,8 +385,7 @@ testSubSelect run = do
describe "subSelectList" $ do describe "subSelectList" $ do
it "is safe on empty databases as well as good databases" $ do it "is safe on empty databases as well as good databases" $ do
let let query =
query =
from $ \n -> do from $ \n -> do
where_ $ n ^. NumbersInt `in_` do where_ $ n ^. NumbersInt `in_` do
subSelectList $ subSelectList $
@ -408,11 +406,8 @@ testSubSelect run = do
describe "subSelectMaybe" $ do describe "subSelectMaybe" $ do
it "is equivalent to joinV . subSelect" $ do it "is equivalent to joinV . subSelect" $ do
let let query
query :: (SqlQuery (SqlExpr (Value (Maybe Int))) -> SqlExpr (Value (Maybe Int)))
:: ( SqlQuery (SqlExpr (Value (Maybe Int)))
-> SqlExpr (Value (Maybe Int))
)
-> SqlQuery (SqlExpr (Value (Maybe Int))) -> SqlQuery (SqlExpr (Value (Maybe Int)))
query selector = query selector =
from $ \n -> do from $ \n -> do
@ -497,12 +492,10 @@ testSubSelect run = do
Right xs -> Right xs ->
xs `shouldBe` [] xs `shouldBe` []
testSelectSource :: Run -> Spec testSelectSource :: Run -> Spec
testSelectSource run = do testSelectSource run = do
describe "selectSource" $ do describe "selectSource" $ do
it "works for a simple example" $ it "works for a simple example" $ run $ do
run $ do
let query = selectSource $ let query = selectSource $
from $ \person -> from $ \person ->
return person return person
@ -510,8 +503,7 @@ testSelectSource run = do
ret <- runConduit $ query .| CL.consume ret <- runConduit $ query .| CL.consume
liftIO $ ret `shouldBe` [ p1e ] liftIO $ ret `shouldBe` [ p1e ]
it "can run a query many times" $ it "can run a query many times" $ run $ do
run $ do
let query = selectSource $ let query = selectSource $
from $ \person -> from $ \person ->
return person return person
@ -524,57 +516,57 @@ testSelectSource run = do
it "works on repro" $ do it "works on repro" $ do
let selectPerson :: R.MonadResource m => String -> ConduitT () (Key Person) (SqlPersistT m) () let selectPerson :: R.MonadResource m => String -> ConduitT () (Key Person) (SqlPersistT m) ()
selectPerson name = do selectPerson name = do
let source = selectSource $ from $ \person -> do let source =
selectSource $ from $ \person -> do
where_ $ person ^. PersonName ==. val name where_ $ person ^. PersonName ==. val name
return $ person ^. PersonId return $ person ^. PersonId
source .| CL.map unValue source .| CL.map unValue
run $ do run $ do
p1e <- insert' p1 p1e <- insert' p1
p2e <- insert' p2 p2e <- insert' p2
r1 <- runConduit $ r1 <- runConduit $ selectPerson (personName p1) .| CL.consume
selectPerson (personName p1) .| CL.consume r2 <- runConduit $ selectPerson (personName p2) .| CL.consume
r2 <- runConduit $
selectPerson (personName p2) .| CL.consume
liftIO $ do liftIO $ do
r1 `shouldBe` [ entityKey p1e ] r1 `shouldBe` [ entityKey p1e ]
r2 `shouldBe` [ entityKey p2e ] r2 `shouldBe` [ entityKey p2e ]
testSelectFrom :: Run -> Spec testSelectFrom :: Run -> Spec
testSelectFrom run = do testSelectFrom run = do
describe "select/from" $ do describe "select/from" $ do
it "works for a simple example" $ it "works for a simple example" $ run $ do
run $ do
p1e <- insert' p1 p1e <- insert' p1
ret <- select $ ret <-
select $
from $ \person -> from $ \person ->
return person return person
liftIO $ ret `shouldBe` [ p1e ] liftIO $ ret `shouldBe` [ p1e ]
it "works for a simple self-join (one entity)" $ it "works for a simple self-join (one entity)" $ run $ do
run $ do
p1e <- insert' p1 p1e <- insert' p1
ret <- select $ ret <-
select $
from $ \(person1, person2) -> from $ \(person1, person2) ->
return (person1, person2) return (person1, person2)
liftIO $ ret `shouldBe` [ (p1e, p1e) ] liftIO $ ret `shouldBe` [ (p1e, p1e) ]
it "works for a simple self-join (two entities)" $ it "works for a simple self-join (two entities)" $ run $ do
run $ do
p1e <- insert' p1 p1e <- insert' p1
p2e <- insert' p2 p2e <- insert' p2
ret <- select $ ret <-
select $
from $ \(person1, person2) -> from $ \(person1, person2) ->
return (person1, person2) return (person1, person2)
liftIO $ ret `shouldSatisfy` sameElementsAs [ (p1e, p1e) liftIO $
ret
`shouldSatisfy`
sameElementsAs
[ (p1e, p1e)
, (p1e, p2e) , (p1e, p2e)
, (p2e, p1e) , (p2e, p1e)
, (p2e, p2e) ] , (p2e, p2e)
]
it "works for a self-join via sub_select" $ run $ do
it "works for a self-join via sub_select" $
run $ do
p1k <- insert p1 p1k <- insert p1
p2k <- insert p2 p2k <- insert p2
_f1k <- insert (Follow p1k p2k) _f1k <- insert (Follow p1k p2k)
@ -589,8 +581,7 @@ testSelectFrom run = do
return followA return followA
liftIO $ length ret `shouldBe` 2 liftIO $ length ret `shouldBe` 2
it "works for a self-join via exists" $ it "works for a self-join via exists" $ run $ do
run $ do
p1k <- insert p1 p1k <- insert p1
p2k <- insert p2 p2k <- insert p2
_f1k <- insert (Follow p1k p2k) _f1k <- insert (Follow p1k p2k)
@ -604,8 +595,7 @@ testSelectFrom run = do
liftIO $ length ret `shouldBe` 2 liftIO $ length ret `shouldBe` 2
it "works for a simple projection" $ it "works for a simple projection" $ run $ do
run $ do
p1k <- insert p1 p1k <- insert p1
p2k <- insert p2 p2k <- insert p2
ret <- select $ ret <- select $
@ -614,8 +604,7 @@ testSelectFrom run = do
liftIO $ ret `shouldBe` [ (Value p1k, Value (personName p1)) liftIO $ ret `shouldBe` [ (Value p1k, Value (personName p1))
, (Value p2k, Value (personName p2)) ] , (Value p2k, Value (personName p2)) ]
it "works for a simple projection with a simple implicit self-join" $ it "works for a simple projection with a simple implicit self-join" $ run $ do
run $ do
_ <- insert p1 _ <- insert p1
_ <- insert p2 _ <- insert p2
ret <- select $ ret <- select $
@ -627,31 +616,35 @@ testSelectFrom run = do
, (Value (personName p2), Value (personName p1)) , (Value (personName p2), Value (personName p1))
, (Value (personName p2), Value (personName p2)) ] , (Value (personName p2), Value (personName p2)) ]
it "works with many kinds of LIMITs and OFFSETs" $ it "works with many kinds of LIMITs and OFFSETs" $ run $ do
run $ do
[p1e, p2e, p3e, p4e] <- mapM insert' [p1, p2, p3, p4] [p1e, p2e, p3e, p4e] <- mapM insert' [p1, p2, p3, p4]
let people = from $ \p -> do let people =
from $ \p -> do
orderBy [asc (p ^. PersonName)] orderBy [asc (p ^. PersonName)]
return p return p
ret1 <- select $ do ret1 <-
select $ do
p <- people p <- people
limit 2 limit 2
limit 1 limit 1
return p return p
liftIO $ ret1 `shouldBe` [ p1e ] liftIO $ ret1 `shouldBe` [ p1e ]
ret2 <- select $ do ret2 <-
select $ do
p <- people p <- people
limit 1 limit 1
limit 2 limit 2
return p return p
liftIO $ ret2 `shouldBe` [ p1e, p4e ] liftIO $ ret2 `shouldBe` [ p1e, p4e ]
ret3 <- select $ do ret3 <-
select $ do
p <- people p <- people
offset 3 offset 3
offset 2 offset 2
return p return p
liftIO $ ret3 `shouldBe` [ p3e, p2e ] liftIO $ ret3 `shouldBe` [ p3e, p2e ]
ret4 <- select $ do ret4 <-
select $ do
p <- people p <- people
offset 3 offset 3
limit 5 limit 5
@ -661,7 +654,8 @@ testSelectFrom run = do
limit 2 limit 2
return p return p
liftIO $ ret4 `shouldBe` [ p4e, p3e ] liftIO $ ret4 `shouldBe` [ p4e, p3e ]
ret5 <- select $ do ret5 <-
select $ do
p <- people p <- people
offset 1000 offset 1000
limit 1 limit 1
@ -670,8 +664,7 @@ testSelectFrom run = do
return p return p
liftIO $ ret5 `shouldBe` [ p1e, p4e, p3e, p2e ] liftIO $ ret5 `shouldBe` [ p1e, p4e, p3e, p2e ]
it "works with non-id primary key" $ it "works with non-id primary key" $ run $ do
run $ do
let fc = Frontcover number "" let fc = Frontcover number ""
number = 101 number = 101
Right thePk = keyFromValues [toPersistValue number] Right thePk = keyFromValues [toPersistValue number]
@ -681,8 +674,7 @@ testSelectFrom run = do
ret `shouldBe` fc ret `shouldBe` fc
fcPk `shouldBe` thePk fcPk `shouldBe` thePk
it "works when returning a custom non-composite primary key from a query" $ it "works when returning a custom non-composite primary key from a query" $ run $ do
run $ do
let name = "foo" let name = "foo"
t = Tag name t = Tag name
Right thePk = keyFromValues [toPersistValue name] Right thePk = keyFromValues [toPersistValue name]
@ -692,15 +684,12 @@ testSelectFrom run = do
ret `shouldBe` thePk ret `shouldBe` thePk
thePk `shouldBe` tagPk thePk `shouldBe` tagPk
it "works when returning a composite primary key from a query" $ it "works when returning a composite primary key from a query" $ run $ do
run $ do
let p = Point 10 20 "" let p = Point 10 20 ""
thePk <- insert p thePk <- insert p
[Value ppk] <- select $ from $ \p' -> return (p'^.PointId) [Value ppk] <- select $ from $ \p' -> return (p'^.PointId)
liftIO $ ppk `shouldBe` thePk liftIO $ ppk `shouldBe` thePk
testSelectJoin :: Run -> Spec testSelectJoin :: Run -> Spec
testSelectJoin run = do testSelectJoin run = do
describe "select:JOIN" $ do describe "select:JOIN" $ do
@ -883,10 +872,8 @@ testSelectJoin run = do
liftIO $ (entityVal <$> ps) `shouldBe` [p1] liftIO $ (entityVal <$> ps) `shouldBe` [p1]
testSelectSubQuery :: Run -> Spec testSelectSubQuery :: Run -> Spec
testSelectSubQuery run = do testSelectSubQuery run = describe "select subquery" $ do
describe "select subquery" $ do it "works" $ run $ do
it "works" $ do
run $ do
_ <- insert' p1 _ <- insert' p1
let q = do let q = do
p <- Experimental.from $ Table @Person p <- Experimental.from $ Table @Person
@ -894,8 +881,7 @@ testSelectSubQuery run = do
ret <- select $ Experimental.from q ret <- select $ Experimental.from q
liftIO $ ret `shouldBe` [ (Value $ personName p1, Value $ personAge p1) ] liftIO $ ret `shouldBe` [ (Value $ personName p1, Value $ personAge p1) ]
it "supports sub-selecting Maybe entities" $ do it "supports sub-selecting Maybe entities" $ run $ do
run $ do
l1e <- insert' l1 l1e <- insert' l1
l3e <- insert' l3 l3e <- insert' l3
l1Deeds <- mapM (\k -> insert' $ Deed k (entityKey l1e)) (map show [1..3 :: Int]) l1Deeds <- mapM (\k -> insert' $ Deed k (entityKey l1e)) (map show [1..3 :: Int])
@ -909,8 +895,7 @@ testSelectSubQuery run = do
pure (lords, deeds) pure (lords, deeds)
liftIO $ ret `shouldMatchList` ((l3e, Nothing) : l1WithDeeds) liftIO $ ret `shouldMatchList` ((l3e, Nothing) : l1WithDeeds)
it "lets you order by alias" $ do it "lets you order by alias" $ run $ do
run $ do
_ <- insert' p1 _ <- insert' p1
_ <- insert' p3 _ <- insert' p3
let q = do let q = do
@ -923,8 +908,7 @@ testSelectSubQuery run = do
ret <- select q ret <- select q
liftIO $ ret `shouldBe` [ Value $ personName p3, Value $ personName p1 ] liftIO $ ret `shouldBe` [ Value $ personName p3, Value $ personName p1 ]
it "supports groupBy" $ do it "supports groupBy" $ run $ do
run $ do
l1k <- insert l1 l1k <- insert l1
l3k <- insert l3 l3k <- insert l3
mapM_ (\k -> insert $ Deed k l1k) (map show [1..3 :: Int]) mapM_ (\k -> insert $ Deed k l1k) (map show [1..3 :: Int])
@ -945,8 +929,7 @@ testSelectSubQuery run = do
liftIO $ ret `shouldMatchList` [ (Value l3k, Value 7) liftIO $ ret `shouldMatchList` [ (Value l3k, Value 7)
, (Value l1k, Value 3) ] , (Value l1k, Value 3) ]
it "Can count results of aggregate query" $ do it "Can count results of aggregate query" $ run $ do
run $ do
l1k <- insert l1 l1k <- insert l1
l3k <- insert l3 l3k <- insert l3
mapM_ (\k -> insert $ Deed k l1k) (map show [1..3 :: Int]) mapM_ (\k -> insert $ Deed k l1k) (map show [1..3 :: Int])
@ -967,8 +950,7 @@ testSelectSubQuery run = do
liftIO $ ret `shouldMatchList` [ (Value 1) ] liftIO $ ret `shouldMatchList` [ (Value 1) ]
it "joins on subqueries" $ do it "joins on subqueries" $ run $ do
run $ do
l1k <- insert l1 l1k <- insert l1
l3k <- insert l3 l3k <- insert l3
mapM_ (\k -> insert $ Deed k l1k) (map show [1..3 :: Int]) mapM_ (\k -> insert $ Deed k l1k) (map show [1..3 :: Int])
@ -985,8 +967,7 @@ testSelectSubQuery run = do
liftIO $ ret `shouldMatchList` [ (Value l3k, Value 7) liftIO $ ret `shouldMatchList` [ (Value l3k, Value 7)
, (Value l1k, Value 3) ] , (Value l1k, Value 3) ]
it "flattens maybe values" $ do it "flattens maybe values" $ run $ do
run $ do
l1k <- insert l1 l1k <- insert l1
l3k <- insert l3 l3k <- insert l3
let q = do let q = do
@ -1001,8 +982,7 @@ testSelectSubQuery run = do
(ret :: [(Value (Key Lord), Value (Maybe Int))]) <- select q (ret :: [(Value (Key Lord), Value (Maybe Int))]) <- select q
liftIO $ ret `shouldMatchList` [ (Value l3k, Value (lordDogs l3)) liftIO $ ret `shouldMatchList` [ (Value l3k, Value (lordDogs l3))
, (Value l1k, Value (lordDogs l1)) ] , (Value l1k, Value (lordDogs l1)) ]
it "unions" $ do it "unions" $ run $ do
run $ do
_ <- insert p1 _ <- insert p1
_ <- insert p2 _ <- insert p2
let q = Experimental.from $ let q = Experimental.from $
@ -1024,10 +1004,8 @@ testSelectSubQuery run = do
liftIO $ names `shouldMatchList` [ (Value $ personName p1) liftIO $ names `shouldMatchList` [ (Value $ personName p1)
, (Value $ personName p2) ] , (Value $ personName p2) ]
testSelectWhere :: Run -> Spec testSelectWhere :: Run -> Spec
testSelectWhere run = do testSelectWhere run = describe "select where_" $ do
describe "select where_" $ do it "works for a simple example with (==.)" $ run $ do
it "works for a simple example with (==.)" $
run $ do
p1e <- insert' p1 p1e <- insert' p1
_ <- insert' p2 _ <- insert' p2
_ <- insert' p3 _ <- insert' p3
@ -1037,8 +1015,7 @@ testSelectWhere run = do
return p return p
liftIO $ ret `shouldBe` [ p1e ] liftIO $ ret `shouldBe` [ p1e ]
it "works for a simple example with (==.) and (||.)" $ it "works for a simple example with (==.) and (||.)" $ run $ do
run $ do
p1e <- insert' p1 p1e <- insert' p1
p2e <- insert' p2 p2e <- insert' p2
_ <- insert' p3 _ <- insert' p3
@ -1048,8 +1025,7 @@ testSelectWhere run = do
return p return p
liftIO $ ret `shouldBe` [ p1e, p2e ] liftIO $ ret `shouldBe` [ p1e, p2e ]
it "works for a simple example with (>.) [uses val . Just]" $ it "works for a simple example with (>.) [uses val . Just]" $ run $ do
run $ do
p1e <- insert' p1 p1e <- insert' p1
_ <- insert' p2 _ <- insert' p2
_ <- insert' p3 _ <- insert' p3
@ -1059,8 +1035,7 @@ testSelectWhere run = do
return p return p
liftIO $ ret `shouldBe` [ p1e ] liftIO $ ret `shouldBe` [ p1e ]
it "works for a simple example with (>.) and not_ [uses just . val]" $ it "works for a simple example with (>.) and not_ [uses just . val]" $ run $ do
run $ do
_ <- insert' p1 _ <- insert' p1
_ <- insert' p2 _ <- insert' p2
p3e <- insert' p3 p3e <- insert' p3
@ -1071,8 +1046,7 @@ testSelectWhere run = do
liftIO $ ret `shouldBe` [ p3e ] liftIO $ ret `shouldBe` [ p3e ]
describe "when using between" $ do describe "when using between" $ do
it "works for a simple example with [uses just . val]" $ it "works for a simple example with [uses just . val]" $ run $ do
run $ do
p1e <- insert' p1 p1e <- insert' p1
_ <- insert' p2 _ <- insert' p2
_ <- insert' p3 _ <- insert' p3
@ -1081,8 +1055,7 @@ testSelectWhere run = do
where_ ((p ^. PersonAge) `between` (just $ val 20, just $ val 40)) where_ ((p ^. PersonAge) `between` (just $ val 20, just $ val 40))
return p return p
liftIO $ ret `shouldBe` [ p1e ] liftIO $ ret `shouldBe` [ p1e ]
it "works for a proyected fields value" $ it "works for a proyected fields value" $ run $ do
run $ do
_ <- insert' p1 >> insert' p2 >> insert' p3 _ <- insert' p1 >> insert' p2 >> insert' p3
ret <- ret <-
select $ select $
@ -1093,8 +1066,7 @@ testSelectWhere run = do
(p ^. PersonAge, p ^. PersonWeight) (p ^. PersonAge, p ^. PersonWeight)
liftIO $ ret `shouldBe` [] liftIO $ ret `shouldBe` []
describe "when projecting composite keys" $ do describe "when projecting composite keys" $ do
it "works when using composite keys with val" $ it "works when using composite keys with val" $ run $ do
run $ do
insert_ $ Point 1 2 "" insert_ $ Point 1 2 ""
ret <- ret <-
select $ select $
@ -1105,8 +1077,7 @@ testSelectWhere run = do
( val $ PointKey 1 2 ( val $ PointKey 1 2
, val $ PointKey 5 6 ) , val $ PointKey 5 6 )
liftIO $ ret `shouldBe` [()] liftIO $ ret `shouldBe` [()]
it "works when using ECompositeKey constructor" $ it "works when using ECompositeKey constructor" $ run $ do
run $ do
insert_ $ Point 1 2 "" insert_ $ Point 1 2 ""
ret <- ret <-
select $ select $
@ -1118,8 +1089,7 @@ testSelectWhere run = do
, EI.ECompositeKey $ const ["5", "6"] ) , EI.ECompositeKey $ const ["5", "6"] )
liftIO $ ret `shouldBe` [] liftIO $ ret `shouldBe` []
it "works with avg_" $ it "works with avg_" $ run $ do
run $ do
_ <- insert' p1 _ <- insert' p1
_ <- insert' p2 _ <- insert' p2
_ <- insert' p3 _ <- insert' p3
@ -1145,8 +1115,7 @@ testSelectWhere run = do
return $ joinV $ min_ (p ^. PersonAge) return $ joinV $ min_ (p ^. PersonAge)
liftIO $ ret `shouldBe` [ Value $ Just (17 :: Int) ] liftIO $ ret `shouldBe` [ Value $ Just (17 :: Int) ]
it "works with max_" $ it "works with max_" $ run $ do
run $ do
_ <- insert' p1 _ <- insert' p1
_ <- insert' p2 _ <- insert' p2
_ <- insert' p3 _ <- insert' p3
@ -1156,8 +1125,7 @@ testSelectWhere run = do
return $ joinV $ max_ (p ^. PersonAge) return $ joinV $ max_ (p ^. PersonAge)
liftIO $ ret `shouldBe` [ Value $ Just (36 :: Int) ] liftIO $ ret `shouldBe` [ Value $ Just (36 :: Int) ]
it "works with lower_" $ it "works with lower_" $ run $ do
run $ do
p1e <- insert' p1 p1e <- insert' p1
p2e@(Entity _ bob) <- insert' $ Person "bob" (Just 36) Nothing 1 p2e@(Entity _ bob) <- insert' $ Person "bob" (Just 36) Nothing 1
@ -1175,13 +1143,11 @@ testSelectWhere run = do
return p return p
liftIO $ ret2 `shouldBe` [ p2e ] liftIO $ ret2 `shouldBe` [ p2e ]
it "works with round_" $ it "works with round_" $ run $ do
run $ do
ret <- select $ return $ round_ (val (16.2 :: Double)) ret <- select $ return $ round_ (val (16.2 :: Double))
liftIO $ ret `shouldBe` [ Value (16 :: Double) ] liftIO $ ret `shouldBe` [ Value (16 :: Double) ]
it "works with isNothing" $ it "works with isNothing" $ run $ do
run $ do
_ <- insert' p1 _ <- insert' p1
p2e <- insert' p2 p2e <- insert' p2
_ <- insert' p3 _ <- insert' p3
@ -1191,8 +1157,7 @@ testSelectWhere run = do
return p return p
liftIO $ ret `shouldBe` [ p2e ] liftIO $ ret `shouldBe` [ p2e ]
it "works with not_ . isNothing" $ it "works with not_ . isNothing" $ run $ do
run $ do
p1e <- insert' p1 p1e <- insert' p1
_ <- insert' p2 _ <- insert' p2
ret <- select $ ret <- select $
@ -1223,8 +1188,7 @@ testSelectWhere run = do
, (p4e, f42, p2e) , (p4e, f42, p2e)
, (p2e, f21, p1e) ] , (p2e, f21, p1e) ]
it "works for a many-to-many explicit join" $ it "works for a many-to-many explicit join" $ run $ do
run $ do
p1e@(Entity p1k _) <- insert' p1 p1e@(Entity p1k _) <- insert' p1
p2e@(Entity p2k _) <- insert' p2 p2e@(Entity p2k _) <- insert' p2
_ <- insert' p3 _ <- insert' p3
@ -1256,8 +1220,7 @@ testSelectWhere run = do
-- we only care that we don't have a SQL error -- we only care that we don't have a SQL error
True `shouldBe` True True `shouldBe` True
it "works for a many-to-many explicit join with LEFT OUTER JOINs" $ it "works for a many-to-many explicit join with LEFT OUTER JOINs" $ run $ do
run $ do
p1e@(Entity p1k _) <- insert' p1 p1e@(Entity p1k _) <- insert' p1
p2e@(Entity p2k _) <- insert' p2 p2e@(Entity p2k _) <- insert' p2
p3e <- insert' p3 p3e <- insert' p3
@ -1279,8 +1242,7 @@ testSelectWhere run = do
, (p3e, Nothing, Nothing) , (p3e, Nothing, Nothing)
, (p2e, Just f21, Just p1e) ] , (p2e, Just f21, Just p1e) ]
it "works with a composite primary key" $ it "works with a composite primary key" $ run $ do
run $ do
let p = Point x y "" let p = Point x y ""
x = 10 x = 10
y = 15 y = 15
@ -1293,13 +1255,9 @@ testSelectWhere run = do
ret `shouldBe` p ret `shouldBe` p
pPk `shouldBe` thePk pPk `shouldBe` thePk
testSelectOrderBy :: Run -> Spec testSelectOrderBy :: Run -> Spec
testSelectOrderBy run = do testSelectOrderBy run = describe "select/orderBy" $ do
describe "select/orderBy" $ do it "works with a single ASC field" $ run $ do
it "works with a single ASC field" $
run $ do
p1e <- insert' p1 p1e <- insert' p1
p2e <- insert' p2 p2e <- insert' p2
p3e <- insert' p3 p3e <- insert' p3
@ -1309,8 +1267,7 @@ testSelectOrderBy run = do
return p return p
liftIO $ ret `shouldBe` [ p1e, p3e, p2e ] liftIO $ ret `shouldBe` [ p1e, p3e, p2e ]
it "works with a sub_select" $ it "works with a sub_select" $ run $ do
run $ do
[p1k, p2k, p3k, p4k] <- mapM insert [p1, p2, p3, p4] [p1k, p2k, p3k, p4k] <- mapM insert [p1, p2, p3, p4]
[b1k, b2k, b3k, b4k] <- mapM (insert . BlogPost "") [p1k, p2k, p3k, p4k] [b1k, b2k, b3k, b4k] <- mapM (insert . BlogPost "") [p1k, p2k, p3k, p4k]
ret <- select $ ret <- select $
@ -1323,8 +1280,7 @@ testSelectOrderBy run = do
return (b ^. BlogPostId) return (b ^. BlogPostId)
liftIO $ ret `shouldBe` (Value <$> [b2k, b3k, b4k, b1k]) liftIO $ ret `shouldBe` (Value <$> [b2k, b3k, b4k, b1k])
it "works on a composite primary key" $ it "works on a composite primary key" $ run $ do
run $ do
let ps = [Point 2 1 "", Point 1 2 ""] let ps = [Point 2 1 "", Point 1 2 ""]
mapM_ insert ps mapM_ insert ps
eps <- select $ eps <- select $
@ -1334,10 +1290,8 @@ testSelectOrderBy run = do
liftIO $ map entityVal eps `shouldBe` reverse ps liftIO $ map entityVal eps `shouldBe` reverse ps
testAscRandom :: SqlExpr (Value Double) -> Run -> Spec testAscRandom :: SqlExpr (Value Double) -> Run -> Spec
testAscRandom rand' run = testAscRandom rand' run = describe "random_" $
describe "random_" $ it "asc random_ works" $ run $ do
it "asc random_ works" $
run $ do
_p1e <- insert' p1 _p1e <- insert' p1
_p2e <- insert' p2 _p2e <- insert' p2
_p3e <- insert' p3 _p3e <- insert' p3
@ -1382,10 +1336,8 @@ testSelectDistinct run = do
testCoasleceDefault :: Run -> Spec testCoasleceDefault :: Run -> Spec
testCoasleceDefault run = do testCoasleceDefault run = describe "coalesce/coalesceDefault" $ do
describe "coalesce/coalesceDefault" $ do it "works on a simple example" $ run $ do
it "works on a simple example" $
run $ do
mapM_ insert' [p1, p2, p3, p4, p5] mapM_ insert' [p1, p2, p3, p4, p5]
ret1 <- select $ ret1 <- select $
from $ \p -> do from $ \p -> do
@ -1409,8 +1361,7 @@ testCoasleceDefault run = do
, Value 5 , Value 5
] ]
it "works with sub-queries" $ it "works with sub-queries" $ run $ do
run $ do
p1id <- insert p1 p1id <- insert p1
p2id <- insert p2 p2id <- insert p2
p3id <- insert p3 p3id <- insert p3
@ -1432,12 +1383,9 @@ testCoasleceDefault run = do
] ]
testDelete :: Run -> Spec testDelete :: Run -> Spec
testDelete run = do testDelete run = describe "delete" $ do
describe "delete" $ it "works on a simple example" $ run $ do
it "works on a simple example" $
run $ do
p1e <- insert' p1 p1e <- insert' p1
p2e <- insert' p2 p2e <- insert' p2
p3e <- insert' p3 p3e <- insert' p3
@ -1458,14 +1406,9 @@ testDelete run = do
ret3 <- getAll ret3 <- getAll
liftIO $ (n, ret3) `shouldBe` (2, []) liftIO $ (n, ret3) `shouldBe` (2, [])
testUpdate :: Run -> Spec testUpdate :: Run -> Spec
testUpdate run = do testUpdate run = describe "update" $ do
describe "update" $ do it "works with a subexpression having COUNT(*)" $ run $ do
it "works with a subexpression having COUNT(*)" $
run $ do
p1k <- insert p1 p1k <- insert p1
p2k <- insert p2 p2k <- insert p2
p3k <- insert p3 p3k <- insert p3
@ -1503,8 +1446,7 @@ testUpdate run = do
ret `shouldBe` Point newX newY [] ret `shouldBe` Point newX newY []
-} -}
it "GROUP BY works with COUNT" $ it "GROUP BY works with COUNT" $ run $ do
run $ do
p1k <- insert p1 p1k <- insert p1
p2k <- insert p2 p2k <- insert p2
p3k <- insert p3 p3k <- insert p3
@ -1521,8 +1463,7 @@ testUpdate run = do
, (Entity p1k p1, Value 3) , (Entity p1k p1, Value 3)
, (Entity p3k p3, Value 7) ] , (Entity p3k p3, Value 7) ]
it "GROUP BY works with COUNT and InnerJoin" $ it "GROUP BY works with COUNT and InnerJoin" $ run $ do
run $ do
l1k <- insert l1 l1k <- insert l1
l3k <- insert l3 l3k <- insert l3
mapM_ (\k -> insert $ Deed k l1k) (map show [1..3 :: Int]) mapM_ (\k -> insert $ Deed k l1k) (map show [1..3 :: Int])
@ -1537,8 +1478,7 @@ testUpdate run = do
liftIO $ ret `shouldMatchList` [ (Value l3k, Value 7) liftIO $ ret `shouldMatchList` [ (Value l3k, Value 7)
, (Value l1k, Value 3) ] , (Value l1k, Value 3) ]
it "GROUP BY works with nested tuples" $ do it "GROUP BY works with nested tuples" $ run $ do
run $ do
l1k <- insert l1 l1k <- insert l1
l3k <- insert l3 l3k <- insert l3
mapM_ (\k -> insert $ Deed k l1k) (map show [1..3 :: Int]) mapM_ (\k -> insert $ Deed k l1k) (map show [1..3 :: Int])
@ -1551,8 +1491,8 @@ testUpdate run = do
groupBy ((lord ^. LordId, lord ^. LordDogs), deed ^. DeedContract) groupBy ((lord ^. LordId, lord ^. LordDogs), deed ^. DeedContract)
return (lord ^. LordId, count $ deed ^. DeedId) return (lord ^. LordId, count $ deed ^. DeedId)
liftIO $ length ret `shouldBe` 10 liftIO $ length ret `shouldBe` 10
it "GROUP BY works with HAVING" $
run $ do it "GROUP BY works with HAVING" $ run $ do
p1k <- insert p1 p1k <- insert p1
_p2k <- insert p2 _p2k <- insert p2
p3k <- insert p3 p3k <- insert p3
@ -1569,7 +1509,6 @@ testUpdate run = do
liftIO $ ret `shouldBe` [ (Entity p1k p1, Value (3 :: Int)) liftIO $ ret `shouldBe` [ (Entity p1k p1, Value (3 :: Int))
, (Entity p3k p3, Value 7) ] , (Entity p3k p3, Value 7) ]
-- we only care that this compiles. check that SqlWriteT doesn't fail on -- we only care that this compiles. check that SqlWriteT doesn't fail on
-- updates. -- updates.
testSqlWriteT :: MonadIO m => SqlWriteT m () testSqlWriteT :: MonadIO m => SqlWriteT m ()
@ -1597,10 +1536,8 @@ testSqlReadT =
return (lord ^. LordId, count $ deed ^. DeedId) return (lord ^. LordId, count $ deed ^. DeedId)
testListOfValues :: Run -> Spec testListOfValues :: Run -> Spec
testListOfValues run = do testListOfValues run = describe "lists of values" $ do
describe "lists of values" $ do it "IN works for valList" $ run $ do
it "IN works for valList" $
run $ do
p1k <- insert p1 p1k <- insert p1
p2k <- insert p2 p2k <- insert p2
_p3k <- insert p3 _p3k <- insert p3
@ -1611,8 +1548,7 @@ testListOfValues run = do
liftIO $ ret `shouldBe` [ Entity p1k p1 liftIO $ ret `shouldBe` [ Entity p1k p1
, Entity p2k p2 ] , Entity p2k p2 ]
it "IN works for valList (null list)" $ it "IN works for valList (null list)" $ run $ do
run $ do
_p1k <- insert p1 _p1k <- insert p1
_p2k <- insert p2 _p2k <- insert p2
_p3k <- insert p3 _p3k <- insert p3
@ -1622,8 +1558,7 @@ testListOfValues run = do
return p return p
liftIO $ ret `shouldBe` [] liftIO $ ret `shouldBe` []
it "IN works for subList_select" $ it "IN works for subList_select" $ run $ do
run $ do
p1k <- insert p1 p1k <- insert p1
_p2k <- insert p2 _p2k <- insert p2
p3k <- insert p3 p3k <- insert p3
@ -1639,8 +1574,7 @@ testListOfValues run = do
return p return p
liftIO $ L.sort ret `shouldBe` L.sort [Entity p1k p1, Entity p3k p3] liftIO $ L.sort ret `shouldBe` L.sort [Entity p1k p1, Entity p3k p3]
it "NOT IN works for subList_select" $ it "NOT IN works for subList_select" $ run $ do
run $ do
p1k <- insert p1 p1k <- insert p1
p2k <- insert p2 p2k <- insert p2
p3k <- insert p3 p3k <- insert p3
@ -1655,8 +1589,7 @@ testListOfValues run = do
return p return p
liftIO $ ret `shouldBe` [ Entity p2k p2 ] liftIO $ ret `shouldBe` [ Entity p2k p2 ]
it "EXISTS works for subList_select" $ it "EXISTS works for subList_select" $ run $ do
run $ do
p1k <- insert p1 p1k <- insert p1
_p2k <- insert p2 _p2k <- insert p2
p3k <- insert p3 p3k <- insert p3
@ -1672,8 +1605,7 @@ testListOfValues run = do
liftIO $ ret `shouldBe` [ Entity p1k p1 liftIO $ ret `shouldBe` [ Entity p1k p1
, Entity p3k p3 ] , Entity p3k p3 ]
it "EXISTS works for subList_select" $ it "EXISTS works for subList_select" $ run $ do
run $ do
p1k <- insert p1 p1k <- insert p1
p2k <- insert p2 p2k <- insert p2
p3k <- insert p3 p3k <- insert p3
@ -1687,25 +1619,15 @@ testListOfValues run = do
return p return p
liftIO $ ret `shouldBe` [ Entity p2k p2 ] liftIO $ ret `shouldBe` [ Entity p2k p2 ]
testListFields :: Run -> Spec testListFields :: Run -> Spec
testListFields run = do testListFields run = describe "list fields" $ do
describe "list fields" $ do
-- <https://github.com/prowdsponsor/esqueleto/issues/100> -- <https://github.com/prowdsponsor/esqueleto/issues/100>
it "can update list fields" $ it "can update list fields" $ run $ do
run $ do
cclist <- insert $ CcList [] cclist <- insert $ CcList []
update $ \p -> do update $ \p -> do
set p [ CcListNames =. val ["fred"]] set p [ CcListNames =. val ["fred"]]
where_ (p ^. CcListId ==. val cclist) where_ (p ^. CcListId ==. val cclist)
testInsertsBySelect :: Run -> Spec testInsertsBySelect :: Run -> Spec
testInsertsBySelect run = do testInsertsBySelect run = do
describe "inserts by select" $ do describe "inserts by select" $ do
@ -1943,18 +1865,18 @@ testRenderSql run = do
expr `shouldBe` "? = ?" expr `shouldBe` "? = ?"
describe "EEntity Ident behavior" $ do describe "EEntity Ident behavior" $ do
let let render :: SqlExpr (Entity val) -> Text.Text
render :: SqlExpr (Entity val) -> Text.Text
render (EI.EEntity (EI.I ident)) = ident render (EI.EEntity (EI.I ident)) = ident
it "renders sensibly" $ do render _ = error "guess we gotta handle this in the test suite now"
results <- run $ do it "renders sensibly" $ run $ do
_ <- insert $ Foo 2 _ <- insert $ Foo 2
_ <- insert $ Foo 3 _ <- insert $ Foo 3
_ <- insert $ Person "hello" Nothing Nothing 3 _ <- insert $ Person "hello" Nothing Nothing 3
select $ results <- select $
from $ \(a `LeftOuterJoin` b) -> do from $ \(a `LeftOuterJoin` b) -> do
on $ a ^. FooName ==. b ^. PersonFavNum on $ a ^. FooName ==. b ^. PersonFavNum
pure (val (render a), val (render b)) pure (val (render a), val (render b))
liftIO $
head results head results
`shouldBe` `shouldBe`
(Value "Foo", Value "Person") (Value "Foo", Value "Person")