Compare commits
14 Commits
master
...
format-con
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14716a5191 | ||
|
|
9ad56e7de2 | ||
|
|
99f9231e49 | ||
|
|
51c546aed3 | ||
|
|
b59cf8cd7a | ||
|
|
8c19140545 | ||
|
|
34ae916bf6 | ||
|
|
17b0da892f | ||
|
|
31f7b7f6c3 | ||
|
|
ea032a9fc5 | ||
|
|
58575433ff | ||
|
|
d7a47ae8f9 | ||
|
|
e92f4e0fb0 | ||
|
|
b5de5d81c7 |
@ -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
|
||||||
|
|||||||
11
.github/PULL_REQUEST_TEMPLATE.md
vendored
11
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -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! :)
|
||||||
|
|
||||||
|
|||||||
6
.github/workflows/haskell.yml
vendored
6
.github/workflows/haskell.yml
vendored
@ -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
39
.stylish-haskell.yaml
Normal 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
|
||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
, (!=.)
|
||||||
|
, (*=.)
|
||||||
|
, (+=.)
|
||||||
|
, (-=.)
|
||||||
|
, (/<-.)
|
||||||
|
, (/=.)
|
||||||
|
, (<-.)
|
||||||
|
, (<.)
|
||||||
|
, (<=.)
|
||||||
|
, (=.)
|
||||||
|
, (==.)
|
||||||
|
, (>.)
|
||||||
|
, (>=.)
|
||||||
|
, (||.)
|
||||||
|
)
|
||||||
|
|||||||
@ -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(..)
|
||||||
|
|||||||
@ -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()`.
|
||||||
|
|||||||
@ -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 "
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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
9
style-guide.md
Normal 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.
|
||||||
@ -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")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user