Compare commits
21 Commits
master
...
matt/persi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
303c65f187 | ||
|
|
6a6a63cb97 | ||
|
|
7bc4fdd3d4 | ||
|
|
8748923faa | ||
|
|
086dfb1f1e | ||
|
|
2ed58e3659 | ||
|
|
d2d52566bb | ||
|
|
cf7a6e50ae | ||
|
|
776d15a8fb | ||
|
|
56e0d7afe7 | ||
|
|
4388cccbce | ||
|
|
c8bfd619e9 | ||
|
|
651380fc80 | ||
|
|
3fdf631404 | ||
|
|
053420d3de | ||
|
|
3292b7a7a0 | ||
|
|
7bd4a524fd | ||
|
|
2b5da6ab6f | ||
|
|
4a546d2698 | ||
|
|
9ac73d93dc | ||
|
|
c8916cb493 |
@ -487,5 +487,6 @@ user which can access it:
|
|||||||
```
|
```
|
||||||
mysql> CREATE DATABASE esqutest;
|
mysql> CREATE DATABASE esqutest;
|
||||||
mysql> CREATE USER 'travis'@'localhost';
|
mysql> CREATE USER 'travis'@'localhost';
|
||||||
|
mysql> ALTER USER 'travis'@'localhost' IDENTIFIED BY 'esqutest';
|
||||||
mysql> GRANT ALL ON esqutest.* TO 'travis';
|
mysql> GRANT ALL ON esqutest.* TO 'travis';
|
||||||
```
|
```
|
||||||
|
|||||||
@ -1 +1,25 @@
|
|||||||
packages: .
|
packages: .
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/yesodweb/persistent
|
||||||
|
tag: 03e794f618b9b8daa5ae9c3a4edfe792642df55c
|
||||||
|
subdir: persistent
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/yesodweb/persistent
|
||||||
|
tag: 03e794f618b9b8daa5ae9c3a4edfe792642df55c
|
||||||
|
subdir: persistent-postgresql
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/yesodweb/persistent
|
||||||
|
tag: 03e794f618b9b8daa5ae9c3a4edfe792642df55c
|
||||||
|
subdir: persistent-mysql
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/yesodweb/persistent
|
||||||
|
tag: 03e794f618b9b8daa5ae9c3a4edfe792642df55c
|
||||||
|
subdir: persistent-sqlite
|
||||||
|
|||||||
@ -1,3 +1,9 @@
|
|||||||
|
3.4.2.0
|
||||||
|
=======
|
||||||
|
- @parsonsmatt
|
||||||
|
- [#243](https://github.com/bitemyapp/esqueleto/pull/243)
|
||||||
|
- Support `persistent-2.12`
|
||||||
|
|
||||||
3.4.1.1
|
3.4.1.1
|
||||||
=======
|
=======
|
||||||
- @MaxGabriel
|
- @MaxGabriel
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
cabal-version: 1.12
|
cabal-version: 1.12
|
||||||
|
|
||||||
name: esqueleto
|
name: esqueleto
|
||||||
version: 3.4.1.1
|
version: 3.4.2.0
|
||||||
synopsis: Type-safe EDSL for SQL queries on persistent backends.
|
synopsis: Type-safe EDSL for SQL queries on persistent backends.
|
||||||
description: @esqueleto@ is a bare bones, type-safe EDSL for SQL queries that works with unmodified @persistent@ SQL backends. Its language closely resembles SQL, so you don't have to learn new concepts, just new syntax, and it's fairly easy to predict the generated SQL and optimize it for your backend. Most kinds of errors committed when writing SQL are caught as compile-time errors---although it is possible to write type-checked @esqueleto@ queries that fail at runtime.
|
description: @esqueleto@ is a bare bones, type-safe EDSL for SQL queries that works with unmodified @persistent@ SQL backends. Its language closely resembles SQL, so you don't have to learn new concepts, just new syntax, and it's fairly easy to predict the generated SQL and optimize it for your backend. Most kinds of errors committed when writing SQL are caught as compile-time errors---although it is possible to write type-checked @esqueleto@ queries that fail at runtime.
|
||||||
.
|
.
|
||||||
@ -53,7 +53,7 @@ library
|
|||||||
, conduit >=1.3
|
, conduit >=1.3
|
||||||
, containers
|
, containers
|
||||||
, monad-logger
|
, monad-logger
|
||||||
, persistent >=2.10.0 && <2.12
|
, persistent >=2.12 && <2.13
|
||||||
, resourcet >=1.2
|
, resourcet >=1.2
|
||||||
, tagged >=0.2
|
, tagged >=0.2
|
||||||
, text >=0.11 && <1.3
|
, text >=0.11 && <1.3
|
||||||
@ -100,7 +100,6 @@ test-suite mysql
|
|||||||
, mysql-simple
|
, mysql-simple
|
||||||
, persistent
|
, persistent
|
||||||
, persistent-mysql
|
, persistent-mysql
|
||||||
, persistent-template
|
|
||||||
, resourcet >=1.2
|
, resourcet >=1.2
|
||||||
, tagged >=0.2
|
, tagged >=0.2
|
||||||
, text >=0.11 && <1.3
|
, text >=0.11 && <1.3
|
||||||
@ -135,7 +134,6 @@ test-suite postgresql
|
|||||||
, mtl
|
, mtl
|
||||||
, persistent
|
, persistent
|
||||||
, persistent-postgresql
|
, persistent-postgresql
|
||||||
, persistent-template
|
|
||||||
, postgresql-libpq
|
, postgresql-libpq
|
||||||
, postgresql-simple
|
, postgresql-simple
|
||||||
, resourcet >=1.2
|
, resourcet >=1.2
|
||||||
@ -171,7 +169,6 @@ test-suite sqlite
|
|||||||
, mtl
|
, mtl
|
||||||
, persistent
|
, persistent
|
||||||
, persistent-sqlite
|
, persistent-sqlite
|
||||||
, persistent-template
|
|
||||||
, resourcet >=1.2
|
, resourcet >=1.2
|
||||||
, tagged >=0.2
|
, tagged >=0.2
|
||||||
, text >=0.11 && <1.3
|
, text >=0.11 && <1.3
|
||||||
|
|||||||
@ -11,7 +11,7 @@ module Blog
|
|||||||
|
|
||||||
import Control.Monad.Base (MonadBase (..))
|
import Control.Monad.Base (MonadBase (..))
|
||||||
import Control.Monad.IO.Unlift (MonadUnliftIO(..), wrappedWithRunInIO)
|
import Control.Monad.IO.Unlift (MonadUnliftIO(..), wrappedWithRunInIO)
|
||||||
import Control.Monad.Logger (MonadLogger, NoLoggingT (..))
|
import Control.Monad.Logger (MonadLoggerIO, MonadLogger, NoLoggingT (..))
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Control.Monad.Trans.Control (ComposeSt, MonadBaseControl (..),
|
import Control.Monad.Trans.Control (ComposeSt, MonadBaseControl (..),
|
||||||
MonadTransControl (..),
|
MonadTransControl (..),
|
||||||
@ -26,6 +26,7 @@ newtype BlogT m a = BlogT { unBlogT :: NoLoggingT (ReaderT ConnectionString m) a
|
|||||||
, MonadLogger
|
, MonadLogger
|
||||||
, MonadReader ConnectionString
|
, MonadReader ConnectionString
|
||||||
, MonadIO
|
, MonadIO
|
||||||
|
, MonadLoggerIO
|
||||||
)
|
)
|
||||||
|
|
||||||
instance MonadUnliftIO m => MonadUnliftIO (BlogT m) where
|
instance MonadUnliftIO m => MonadUnliftIO (BlogT m) where
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import Control.Monad (void)
|
|||||||
import Control.Monad (forM_)
|
import Control.Monad (forM_)
|
||||||
import Control.Monad.IO.Class (MonadIO, liftIO)
|
import Control.Monad.IO.Class (MonadIO, liftIO)
|
||||||
import Control.Monad.IO.Unlift (MonadUnliftIO)
|
import Control.Monad.IO.Unlift (MonadUnliftIO)
|
||||||
import Control.Monad.Logger (MonadLogger)
|
import Control.Monad.Logger (MonadLogger, MonadLoggerIO)
|
||||||
import Control.Monad.Reader (MonadReader(..), runReaderT)
|
import Control.Monad.Reader (MonadReader(..), runReaderT)
|
||||||
import Control.Monad.Trans.Control (MonadBaseControl)
|
import Control.Monad.Trans.Control (MonadBaseControl)
|
||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
@ -165,6 +165,7 @@ runDB :: (MonadReader ConnectionString m,
|
|||||||
MonadIO m,
|
MonadIO m,
|
||||||
MonadBaseControl IO m,
|
MonadBaseControl IO m,
|
||||||
MonadUnliftIO m,
|
MonadUnliftIO m,
|
||||||
|
MonadLoggerIO m,
|
||||||
MonadLogger m)
|
MonadLogger m)
|
||||||
=> SqlPersistT m a -> m a
|
=> SqlPersistT m a -> m a
|
||||||
runDB query = do
|
runDB query = do
|
||||||
|
|||||||
@ -227,6 +227,7 @@ import qualified Data.Text.Lazy.Builder as TLB
|
|||||||
import Database.Esqueleto.Internal.Internal hiding (From, from, on)
|
import Database.Esqueleto.Internal.Internal hiding (From, from, on)
|
||||||
import Database.Esqueleto.Internal.PersistentImport
|
import Database.Esqueleto.Internal.PersistentImport
|
||||||
import GHC.TypeLits
|
import GHC.TypeLits
|
||||||
|
import Database.Persist (EntityNameDB(..))
|
||||||
|
|
||||||
-- $setup
|
-- $setup
|
||||||
--
|
--
|
||||||
@ -1040,7 +1041,7 @@ from parts = do
|
|||||||
runFrom :: From a -> SqlQuery (a, FromClause)
|
runFrom :: From a -> SqlQuery (a, FromClause)
|
||||||
runFrom e@Table = do
|
runFrom e@Table = do
|
||||||
let ed = entityDef $ getVal e
|
let ed = entityDef $ getVal e
|
||||||
ident <- newIdentFor (entityDB ed)
|
ident <- newIdentFor . DBName . unEntityNameDB $ entityDB ed
|
||||||
let entity = EEntity ident
|
let entity = EEntity ident
|
||||||
pure $ (entity, FromStart ident ed)
|
pure $ (entity, FromStart ident ed)
|
||||||
where
|
where
|
||||||
|
|||||||
@ -43,7 +43,7 @@ parseOnExpr sqlBackend text = do
|
|||||||
-- with postgresql, mysql, and sqlite backends.
|
-- with postgresql, mysql, and sqlite backends.
|
||||||
mkEscapeChar :: SqlBackend -> Either String Char
|
mkEscapeChar :: SqlBackend -> Either String Char
|
||||||
mkEscapeChar sqlBackend =
|
mkEscapeChar sqlBackend =
|
||||||
case Text.uncons (connEscapeName sqlBackend (DBName "")) of
|
case Text.uncons (connEscapeRawName sqlBackend "") of
|
||||||
Nothing ->
|
Nothing ->
|
||||||
Left "Failed to get an escape character from the SQL backend."
|
Left "Failed to get an escape character from the SQL backend."
|
||||||
Just (c, _) ->
|
Just (c, _) ->
|
||||||
|
|||||||
@ -56,6 +56,7 @@ import Data.Typeable (Typeable)
|
|||||||
import Database.Esqueleto.Internal.ExprParser (TableAccess(..), parseOnExpr)
|
import Database.Esqueleto.Internal.ExprParser (TableAccess(..), parseOnExpr)
|
||||||
import Database.Esqueleto.Internal.PersistentImport
|
import Database.Esqueleto.Internal.PersistentImport
|
||||||
import qualified Database.Persist
|
import qualified Database.Persist
|
||||||
|
import Database.Persist (FieldNameDB(..), EntityNameDB(..))
|
||||||
import Database.Persist.Sql.Util
|
import Database.Persist.Sql.Util
|
||||||
( entityColumnCount
|
( entityColumnCount
|
||||||
, entityColumnNames
|
, entityColumnNames
|
||||||
@ -64,6 +65,7 @@ import Database.Persist.Sql.Util
|
|||||||
, parseEntityValues
|
, parseEntityValues
|
||||||
)
|
)
|
||||||
import Text.Blaze.Html (Html)
|
import Text.Blaze.Html (Html)
|
||||||
|
import Data.Coerce (coerce)
|
||||||
|
|
||||||
-- | (Internal) Start a 'from' query with an entity. 'from'
|
-- | (Internal) Start a 'from' query with an entity. 'from'
|
||||||
-- does two kinds of magic using 'fromStart', 'fromJoin' and
|
-- does two kinds of magic using 'fromStart', 'fromJoin' and
|
||||||
@ -86,11 +88,14 @@ fromStart
|
|||||||
=> SqlQuery (SqlExpr (PreprocessedFrom (SqlExpr (Entity a))))
|
=> SqlQuery (SqlExpr (PreprocessedFrom (SqlExpr (Entity a))))
|
||||||
fromStart = do
|
fromStart = do
|
||||||
let ed = entityDef (Proxy :: Proxy a)
|
let ed = entityDef (Proxy :: Proxy a)
|
||||||
ident <- newIdentFor (entityDB ed)
|
ident <- newIdentFor (coerce $ entityDB ed)
|
||||||
let ret = EEntity ident
|
let ret = EEntity ident
|
||||||
f' = FromStart ident ed
|
f' = FromStart ident ed
|
||||||
return (EPreprocessedFrom ret f')
|
return (EPreprocessedFrom ret f')
|
||||||
|
|
||||||
|
-- | Copied from @persistent@
|
||||||
|
newtype DBName = DBName { unDBName :: T.Text }
|
||||||
|
|
||||||
-- | (Internal) Same as 'fromStart', but entity may be missing.
|
-- | (Internal) Same as 'fromStart', but entity may be missing.
|
||||||
fromStartMaybe
|
fromStartMaybe
|
||||||
:: ( PersistEntity a
|
:: ( PersistEntity a
|
||||||
@ -568,7 +573,7 @@ e ^. field
|
|||||||
]
|
]
|
||||||
fieldIdent =
|
fieldIdent =
|
||||||
case e of
|
case e of
|
||||||
EEntity _ -> fromDBName info (fieldDB fieldDef)
|
EEntity _ -> fromDBName info (coerce $ fieldDB fieldDef)
|
||||||
EAliasedEntity baseI _ -> useIdent info $ aliasedEntityColumnIdent baseI fieldDef
|
EAliasedEntity baseI _ -> useIdent info $ aliasedEntityColumnIdent baseI fieldDef
|
||||||
EAliasedEntityReference a b ->
|
EAliasedEntityReference a b ->
|
||||||
error $ unwords
|
error $ unwords
|
||||||
@ -1805,7 +1810,7 @@ instance Show FromClause where
|
|||||||
|
|
||||||
where
|
where
|
||||||
dummy = SqlBackend
|
dummy = SqlBackend
|
||||||
{ connEscapeName = \(DBName x) -> x
|
{ connEscapeRawName = id
|
||||||
}
|
}
|
||||||
render' = T.unpack . renderExpr dummy
|
render' = T.unpack . renderExpr dummy
|
||||||
|
|
||||||
@ -2124,7 +2129,7 @@ instance ToSomeValues (SqlExpr (Value a)) where
|
|||||||
fieldName
|
fieldName
|
||||||
:: (PersistEntity val, PersistField typ)
|
:: (PersistEntity val, PersistField typ)
|
||||||
=> IdentInfo -> EntityField val typ -> TLB.Builder
|
=> IdentInfo -> EntityField val typ -> TLB.Builder
|
||||||
fieldName info = fromDBName info . fieldDB . persistFieldDef
|
fieldName info = fromDBName info . coerce . fieldDB . persistFieldDef
|
||||||
|
|
||||||
-- FIXME: Composite/non-id pKS not supported on set
|
-- FIXME: Composite/non-id pKS not supported on set
|
||||||
setAux
|
setAux
|
||||||
@ -2140,7 +2145,7 @@ sub :: PersistField a => Mode -> SqlQuery (SqlExpr (Value a)) -> SqlExpr (Value
|
|||||||
sub mode query = ERaw Parens $ \info -> toRawSql mode info query
|
sub mode query = ERaw Parens $ \info -> toRawSql mode info query
|
||||||
|
|
||||||
fromDBName :: IdentInfo -> DBName -> TLB.Builder
|
fromDBName :: IdentInfo -> DBName -> TLB.Builder
|
||||||
fromDBName (conn, _) = TLB.fromText . connEscapeName conn
|
fromDBName (conn, _) = TLB.fromText . connEscapeRawName conn . unDBName
|
||||||
|
|
||||||
existsHelper :: SqlQuery () -> SqlExpr (Value Bool)
|
existsHelper :: SqlQuery () -> SqlExpr (Value Bool)
|
||||||
existsHelper = sub SELECT . (>> return true)
|
existsHelper = sub SELECT . (>> return true)
|
||||||
@ -2900,7 +2905,7 @@ makeFrom info mode fs = ret
|
|||||||
(useIdent info ident, mempty)
|
(useIdent info ident, mempty)
|
||||||
|
|
||||||
base ident@(I identText) def =
|
base ident@(I identText) def =
|
||||||
let db@(DBName dbText) = entityDB def
|
let db@(DBName dbText) = coerce $ entityDB def
|
||||||
in ( fromDBName info db <>
|
in ( fromDBName info db <>
|
||||||
if dbText == identText
|
if dbText == identText
|
||||||
then mempty
|
then mempty
|
||||||
@ -3030,7 +3035,7 @@ valueReferenceToRawSql sourceIdent columnIdentF info =
|
|||||||
|
|
||||||
aliasedEntityColumnIdent :: Ident -> FieldDef -> Ident
|
aliasedEntityColumnIdent :: Ident -> FieldDef -> Ident
|
||||||
aliasedEntityColumnIdent (I baseIdent) field =
|
aliasedEntityColumnIdent (I baseIdent) field =
|
||||||
I (baseIdent <> "_" <> (unDBName $ fieldDB field))
|
I (baseIdent <> "_" <> (unDBName $ coerce $ fieldDB field))
|
||||||
|
|
||||||
aliasedColumnName :: Ident -> IdentInfo -> T.Text -> TLB.Builder
|
aliasedColumnName :: Ident -> IdentInfo -> T.Text -> TLB.Builder
|
||||||
aliasedColumnName (I baseIdent) info columnName =
|
aliasedColumnName (I baseIdent) info columnName =
|
||||||
@ -3064,11 +3069,11 @@ instance SqlSelect (SqlExpr InsertFinal) InsertFinal where
|
|||||||
sqlInsertInto info (EInsertFinal (EInsert p _)) =
|
sqlInsertInto info (EInsertFinal (EInsert p _)) =
|
||||||
let fields =
|
let fields =
|
||||||
uncommas $
|
uncommas $
|
||||||
map (fromDBName info . fieldDB) $
|
map (fromDBName info . coerce . fieldDB) $
|
||||||
entityFields $
|
entityFields $
|
||||||
entityDef p
|
entityDef p
|
||||||
table =
|
table =
|
||||||
fromDBName info . entityDB . entityDef $ p
|
fromDBName info . DBName . coerce . entityDB . entityDef $ p
|
||||||
in
|
in
|
||||||
("INSERT INTO " <> table <> parens fields <> "\n", [])
|
("INSERT INTO " <> table <> parens fields <> "\n", [])
|
||||||
sqlSelectCols info (EInsertFinal (EInsert _ f)) = f info
|
sqlSelectCols info (EInsertFinal (EInsert _ f)) = f info
|
||||||
@ -3084,8 +3089,8 @@ instance SqlSelect () () where
|
|||||||
|
|
||||||
unescapedColumnNames :: EntityDef -> [DBName]
|
unescapedColumnNames :: EntityDef -> [DBName]
|
||||||
unescapedColumnNames ent =
|
unescapedColumnNames ent =
|
||||||
(if hasCompositeKey ent then id else ( fieldDB (entityId ent) :))
|
(if hasCompositeKey ent then id else ( coerce (fieldDB (entityId ent)) :))
|
||||||
$ map fieldDB (entityFields ent)
|
$ map (coerce . fieldDB) (entityFields ent)
|
||||||
|
|
||||||
-- | You may return an 'Entity' from a 'select' query.
|
-- | You may return an 'Entity' from a 'select' query.
|
||||||
instance PersistEntity a => SqlSelect (SqlExpr (Entity a)) (Entity a) where
|
instance PersistEntity a => SqlSelect (SqlExpr (Entity a)) (Entity a) where
|
||||||
|
|||||||
@ -53,7 +53,6 @@ module Database.Esqueleto.Internal.PersistentImport
|
|||||||
rawQuery,
|
rawQuery,
|
||||||
rawQueryRes,
|
rawQueryRes,
|
||||||
rawSql,
|
rawSql,
|
||||||
askLogFunc,
|
|
||||||
close',
|
close',
|
||||||
createSqlPool,
|
createSqlPool,
|
||||||
liftSqlPersistMPool,
|
liftSqlPersistMPool,
|
||||||
@ -118,7 +117,6 @@ module Database.Esqueleto.Internal.PersistentImport
|
|||||||
Attr,
|
Attr,
|
||||||
Checkmark(..),
|
Checkmark(..),
|
||||||
CompositeDef(..),
|
CompositeDef(..),
|
||||||
DBName(..),
|
|
||||||
EmbedEntityDef(..),
|
EmbedEntityDef(..),
|
||||||
EmbedFieldDef(..),
|
EmbedFieldDef(..),
|
||||||
EntityDef(..),
|
EntityDef(..),
|
||||||
@ -127,7 +125,6 @@ module Database.Esqueleto.Internal.PersistentImport
|
|||||||
FieldType(..),
|
FieldType(..),
|
||||||
ForeignDef(..),
|
ForeignDef(..),
|
||||||
ForeignFieldDef,
|
ForeignFieldDef,
|
||||||
HaskellName(..),
|
|
||||||
IsNullable(..),
|
IsNullable(..),
|
||||||
OnlyUniqueException(..),
|
OnlyUniqueException(..),
|
||||||
PersistException(..),
|
PersistException(..),
|
||||||
|
|||||||
@ -47,6 +47,7 @@ import Data.Time.Clock (UTCTime)
|
|||||||
import Database.Esqueleto.Internal.Internal hiding (random_)
|
import Database.Esqueleto.Internal.Internal hiding (random_)
|
||||||
import Database.Esqueleto.Internal.PersistentImport hiding (upsert, upsertBy)
|
import Database.Esqueleto.Internal.PersistentImport hiding (upsert, upsertBy)
|
||||||
import Database.Persist.Class (OnlyOneUniqueKey)
|
import Database.Persist.Class (OnlyOneUniqueKey)
|
||||||
|
import Database.Persist (ConstraintNameDB(..), EntityNameDB(..))
|
||||||
|
|
||||||
-- | (@random()@) Split out into database specific modules
|
-- | (@random()@) Split out into database specific modules
|
||||||
-- because MySQL uses `rand()`.
|
-- because MySQL uses `rand()`.
|
||||||
@ -306,10 +307,10 @@ insertSelectWithConflictCount unique query conflictQuery = do
|
|||||||
updates = conflictQuery entCurrent entExcluded
|
updates = conflictQuery entCurrent entExcluded
|
||||||
combine (tlb1,vals1) (tlb2,vals2) = (builderToText (tlb1 `mappend` tlb2), vals1 ++ vals2)
|
combine (tlb1,vals1) (tlb2,vals2) = (builderToText (tlb1 `mappend` tlb2), vals1 ++ vals2)
|
||||||
entExcluded = EEntity $ I "excluded"
|
entExcluded = EEntity $ I "excluded"
|
||||||
tableName = unDBName . entityDB . entityDef
|
tableName = unEntityNameDB . entityDB . entityDef
|
||||||
entCurrent = EEntity $ I (tableName proxy)
|
entCurrent = EEntity $ I (tableName proxy)
|
||||||
uniqueDef = toUniqueDef unique
|
uniqueDef = toUniqueDef unique
|
||||||
constraint = TLB.fromText . unDBName . uniqueDBName $ uniqueDef
|
constraint = TLB.fromText . unConstraintNameDB . 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 = (mconcat ([
|
conflict conn = (mconcat ([
|
||||||
|
|||||||
@ -87,7 +87,7 @@ instance IsString JSONAccessor where
|
|||||||
|
|
||||||
-- | @since 3.1.0
|
-- | @since 3.1.0
|
||||||
instance (FromJSON a, ToJSON a) => PersistField (JSONB a) where
|
instance (FromJSON a, ToJSON a) => PersistField (JSONB a) where
|
||||||
toPersistValue = PersistDbSpecific . BSL.toStrict . encode . unJSONB
|
toPersistValue = PersistLiteralEscaped . BSL.toStrict . encode . unJSONB
|
||||||
fromPersistValue pVal = fmap JSONB $ case pVal of
|
fromPersistValue pVal = fmap JSONB $ case pVal of
|
||||||
PersistByteString bs -> first (badParse $ TE.decodeUtf8 bs) $ eitherDecodeStrict bs
|
PersistByteString bs -> first (badParse $ TE.decodeUtf8 bs) $ eitherDecodeStrict bs
|
||||||
PersistText t -> first (badParse t) $ eitherDecodeStrict (TE.encodeUtf8 t)
|
PersistText t -> first (badParse t) $ eitherDecodeStrict (TE.encodeUtf8 t)
|
||||||
|
|||||||
@ -5,8 +5,11 @@ packages:
|
|||||||
- 'examples'
|
- 'examples'
|
||||||
|
|
||||||
extra-deps:
|
extra-deps:
|
||||||
- persistent-2.11.0.0
|
- git: https://www.github.com/yesodweb/persistent
|
||||||
- persistent-template-2.9.1.0
|
commit: 03e794f618b9b8daa5ae9c3a4edfe792642df55c
|
||||||
- persistent-mysql-2.10.3
|
subdirs:
|
||||||
- persistent-postgresql-2.11.0.0
|
- persistent
|
||||||
- persistent-sqlite-2.11.0.0
|
- persistent-template
|
||||||
|
- persistent-mysql
|
||||||
|
- persistent-postgresql
|
||||||
|
- persistent-sqlite
|
||||||
|
|||||||
@ -71,7 +71,7 @@ import Data.Time
|
|||||||
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 (MonadLoggerIO(..), MonadLogger(..), NoLoggingT, runNoLoggingT)
|
||||||
import Control.Monad.Trans.Reader (ReaderT)
|
import Control.Monad.Trans.Reader (ReaderT)
|
||||||
import qualified Data.Attoparsec.Text as AP
|
import qualified Data.Attoparsec.Text as AP
|
||||||
import Data.Char (toLower, toUpper)
|
import Data.Char (toLower, toUpper)
|
||||||
@ -2507,6 +2507,7 @@ insert' v = flip Entity v <$> insert v
|
|||||||
|
|
||||||
type RunDbMonad m = ( MonadUnliftIO m
|
type RunDbMonad m = ( MonadUnliftIO m
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
|
, MonadLoggerIO m
|
||||||
, MonadLogger m
|
, MonadLogger m
|
||||||
, MonadCatch m )
|
, MonadCatch m )
|
||||||
|
|
||||||
|
|||||||
@ -1,27 +1,30 @@
|
|||||||
{-# LANGUAGE ScopedTypeVariables
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
, FlexibleContexts
|
{-# LANGUAGE RankNTypes #-}
|
||||||
, RankNTypes
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
, TypeFamilies
|
{-# LANGUAGE TypeApplications #-}
|
||||||
, TypeApplications
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
#-}
|
|
||||||
|
|
||||||
module Main (main) where
|
module Main (main) where
|
||||||
|
|
||||||
|
import Control.Applicative
|
||||||
import Control.Monad (void)
|
import Control.Monad (void)
|
||||||
import Control.Monad.IO.Class (MonadIO(liftIO))
|
import Control.Monad.IO.Class (MonadIO(liftIO))
|
||||||
import Control.Monad.Logger (runStderrLoggingT, runNoLoggingT)
|
import Control.Monad.Logger (runNoLoggingT, runStderrLoggingT)
|
||||||
import Control.Monad.Trans.Reader (ReaderT)
|
import Control.Monad.Trans.Reader (ReaderT)
|
||||||
import Database.Persist.MySQL ( withMySQLConn
|
import qualified Control.Monad.Trans.Resource as R
|
||||||
, connectHost
|
|
||||||
, connectDatabase
|
|
||||||
, connectUser
|
|
||||||
, connectPassword
|
|
||||||
, connectPort
|
|
||||||
, defaultConnectInfo)
|
|
||||||
import Database.Esqueleto
|
import Database.Esqueleto
|
||||||
import Database.Esqueleto.Experimental hiding (from, on)
|
import Database.Esqueleto.Experimental hiding (from, on)
|
||||||
import qualified Database.Esqueleto.Experimental as Experimental
|
import qualified Database.Esqueleto.Experimental as Experimental
|
||||||
import qualified Control.Monad.Trans.Resource as R
|
import Database.Persist.MySQL
|
||||||
|
( connectDatabase
|
||||||
|
, connectHost
|
||||||
|
, connectPassword
|
||||||
|
, connectPort
|
||||||
|
, connectUser
|
||||||
|
, defaultConnectInfo
|
||||||
|
, withMySQLConn
|
||||||
|
)
|
||||||
|
import System.Environment
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
|
|
||||||
import Common.Test
|
import Common.Test
|
||||||
@ -237,12 +240,31 @@ migrateIt = do
|
|||||||
|
|
||||||
|
|
||||||
withConn :: RunDbMonad m => (SqlBackend -> R.ResourceT m a) -> m a
|
withConn :: RunDbMonad m => (SqlBackend -> R.ResourceT m a) -> m a
|
||||||
withConn =
|
withConn f = do
|
||||||
R.runResourceT .
|
ci <- liftIO isCI
|
||||||
withMySQLConn defaultConnectInfo
|
let connInfo
|
||||||
{ connectHost = "127.0.0.1"
|
| ci =
|
||||||
, connectUser = "travis"
|
defaultConnectInfo
|
||||||
, connectPassword = "esqutest"
|
{ connectHost = "127.0.0.1"
|
||||||
, connectDatabase = "esqutest"
|
, connectUser = "travis"
|
||||||
, connectPort = 33306
|
, connectPassword = "esqutest"
|
||||||
}
|
, connectDatabase = "esqutest"
|
||||||
|
, connectPort = 33306
|
||||||
|
}
|
||||||
|
| otherwise =
|
||||||
|
defaultConnectInfo
|
||||||
|
{ connectHost = "localhost"
|
||||||
|
, connectUser = "travis"
|
||||||
|
, connectPassword = "esqutest"
|
||||||
|
, connectDatabase = "esqutest"
|
||||||
|
, connectPort = 3306
|
||||||
|
}
|
||||||
|
R.runResourceT $ withMySQLConn connInfo f
|
||||||
|
|
||||||
|
isCI :: IO Bool
|
||||||
|
isCI = do
|
||||||
|
env <- getEnvironment
|
||||||
|
return $ case lookup "TRAVIS" env <|> lookup "CI" env of
|
||||||
|
Just "true" -> True
|
||||||
|
_ -> False
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import Common.Test (RunDbMonad)
|
|||||||
share [mkPersist sqlSettings, mkMigrate "migrateJSON"] [persistUpperCase|
|
share [mkPersist sqlSettings, mkMigrate "migrateJSON"] [persistUpperCase|
|
||||||
Json
|
Json
|
||||||
value (JSONB Value)
|
value (JSONB Value)
|
||||||
|
deriving Show
|
||||||
|]
|
|]
|
||||||
|
|
||||||
cleanJSON
|
cleanJSON
|
||||||
|
|||||||
@ -1,47 +1,47 @@
|
|||||||
{-# OPTIONS_GHC -fno-warn-unused-binds #-}
|
{-# OPTIONS_GHC -fno-warn-unused-binds #-}
|
||||||
{-# LANGUAGE FlexibleContexts
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
, LambdaCase
|
{-# LANGUAGE LambdaCase #-}
|
||||||
, NamedFieldPuns
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
, OverloadedStrings
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
, RankNTypes
|
{-# LANGUAGE PartialTypeSignatures #-}
|
||||||
, ScopedTypeVariables
|
{-# LANGUAGE RankNTypes #-}
|
||||||
, TypeApplications
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
, TypeFamilies
|
{-# LANGUAGE TypeApplications #-}
|
||||||
, PartialTypeSignatures
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
#-}
|
|
||||||
module Main (main) where
|
module Main (main) where
|
||||||
|
|
||||||
import Data.Coerce
|
|
||||||
import Data.Foldable
|
|
||||||
import qualified Data.Map.Strict as Map
|
|
||||||
import Data.Map (Map)
|
|
||||||
import Data.Time
|
|
||||||
import Control.Arrow ((&&&))
|
import Control.Arrow ((&&&))
|
||||||
import Control.Monad (void, when)
|
import Control.Monad (void, when)
|
||||||
import Control.Monad.Catch (MonadCatch, catch)
|
import Control.Monad.Catch
|
||||||
import Control.Monad.IO.Class (MonadIO(liftIO))
|
import Control.Monad.IO.Class (MonadIO(liftIO))
|
||||||
import Control.Monad.Logger (runStderrLoggingT, runNoLoggingT)
|
import Control.Monad.Logger (runNoLoggingT, runStderrLoggingT)
|
||||||
import Control.Monad.Trans.Reader (ReaderT, ask)
|
import Control.Monad.Trans.Reader (ReaderT, ask)
|
||||||
import qualified Control.Monad.Trans.Resource as R
|
import qualified Control.Monad.Trans.Resource as R
|
||||||
import Data.Aeson hiding (Value)
|
import Data.Aeson hiding (Value)
|
||||||
import qualified Data.Aeson as A (Value)
|
import qualified Data.Aeson as A (Value)
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
|
import qualified Data.ByteString.Lazy as BSL
|
||||||
import qualified Data.Char as Char
|
import qualified Data.Char as Char
|
||||||
|
import Data.Coerce
|
||||||
|
import Data.Foldable
|
||||||
import qualified Data.List as L
|
import qualified Data.List as L
|
||||||
|
import Data.Map (Map)
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
import Data.Ord (comparing)
|
import Data.Ord (comparing)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Encoding as TE
|
import qualified Data.Text.Encoding as TE
|
||||||
import Data.Time.Clock (getCurrentTime, diffUTCTime, UTCTime)
|
import Data.Time
|
||||||
|
import Data.Time.Clock (UTCTime, diffUTCTime, getCurrentTime)
|
||||||
import Database.Esqueleto hiding (random_)
|
import Database.Esqueleto hiding (random_)
|
||||||
import Database.Esqueleto.Experimental hiding (random_, from, on)
|
import Database.Esqueleto.Experimental hiding (from, on, random_)
|
||||||
import qualified Database.Esqueleto.Experimental as Experimental
|
import qualified Database.Esqueleto.Experimental as Experimental
|
||||||
import qualified Database.Esqueleto.Internal.Sql as ES
|
import qualified Database.Esqueleto.Internal.Sql as ES
|
||||||
import Database.Esqueleto.PostgreSQL (random_)
|
import Database.Esqueleto.PostgreSQL (random_)
|
||||||
import qualified Database.Esqueleto.PostgreSQL as EP
|
import qualified Database.Esqueleto.PostgreSQL as EP
|
||||||
import Database.Esqueleto.PostgreSQL.JSON hiding ((?.), (-.), (||.))
|
import Database.Esqueleto.PostgreSQL.JSON hiding ((-.), (?.), (||.))
|
||||||
import qualified Database.Esqueleto.PostgreSQL.JSON as JSON
|
import qualified Database.Esqueleto.PostgreSQL.JSON as JSON
|
||||||
import Database.Persist.Postgresql (withPostgresqlConn)
|
import Database.Persist.Postgresql (withPostgresqlConn)
|
||||||
import Database.PostgreSQL.Simple (SqlError(..), ExecStatus(..))
|
import Database.PostgreSQL.Simple (ExecStatus(..), SqlError(..))
|
||||||
import System.Environment
|
import System.Environment
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
import Test.Hspec.QuickCheck
|
import Test.Hspec.QuickCheck
|
||||||
@ -570,11 +570,6 @@ testPostgresModule = do
|
|||||||
-- | Get the time diff and check it's less than a second
|
-- | Get the time diff and check it's less than a second
|
||||||
liftIO $ diffUTCTime nowUtc now `shouldSatisfy` (< oneSecond)
|
liftIO $ diffUTCTime nowUtc now `shouldSatisfy` (< oneSecond)
|
||||||
|
|
||||||
|
|
||||||
--------------- JSON --------------- JSON --------------- JSON ---------------
|
|
||||||
--------------- JSON --------------- JSON --------------- JSON ---------------
|
|
||||||
--------------- JSON --------------- JSON --------------- JSON ---------------
|
|
||||||
|
|
||||||
testJSONInsertions :: Spec
|
testJSONInsertions :: Spec
|
||||||
testJSONInsertions =
|
testJSONInsertions =
|
||||||
describe "JSON Insertions" $ do
|
describe "JSON Insertions" $ do
|
||||||
@ -619,14 +614,14 @@ testArrowJSONB =
|
|||||||
createSaneSQL @JSONValue
|
createSaneSQL @JSONValue
|
||||||
(jsonbVal (object ["a" .= True]) ->. "a")
|
(jsonbVal (object ["a" .= True]) ->. "a")
|
||||||
"SELECT (? -> ?)\nFROM \"Json\"\n"
|
"SELECT (? -> ?)\nFROM \"Json\"\n"
|
||||||
[ PersistDbSpecific "{\"a\":true}"
|
[ PersistLiteralEscaped "{\"a\":true}"
|
||||||
, PersistText "a" ]
|
, PersistText "a" ]
|
||||||
it "creates sane SQL (chained)" $ do
|
it "creates sane SQL (chained)" $ do
|
||||||
let obj = object ["a" .= [1 :: Int,2,3]]
|
let obj = object ["a" .= [1 :: Int,2,3]]
|
||||||
createSaneSQL @JSONValue
|
createSaneSQL @JSONValue
|
||||||
(jsonbVal obj ->. "a" ->. 1)
|
(jsonbVal obj ->. "a" ->. 1)
|
||||||
"SELECT ((? -> ?) -> ?)\nFROM \"Json\"\n"
|
"SELECT ((? -> ?) -> ?)\nFROM \"Json\"\n"
|
||||||
[ PersistDbSpecific "{\"a\":[1,2,3]}"
|
[ PersistLiteralEscaped "{\"a\":[1,2,3]}"
|
||||||
, PersistText "a"
|
, PersistText "a"
|
||||||
, PersistInt64 1 ]
|
, PersistInt64 1 ]
|
||||||
it "works as expected" $ run $ do
|
it "works as expected" $ run $ do
|
||||||
@ -644,14 +639,14 @@ testArrowText =
|
|||||||
createSaneSQL
|
createSaneSQL
|
||||||
(jsonbVal (object ["a" .= True]) ->>. "a")
|
(jsonbVal (object ["a" .= True]) ->>. "a")
|
||||||
"SELECT (? ->> ?)\nFROM \"Json\"\n"
|
"SELECT (? ->> ?)\nFROM \"Json\"\n"
|
||||||
[ PersistDbSpecific "{\"a\":true}"
|
[ PersistLiteralEscaped "{\"a\":true}"
|
||||||
, PersistText "a" ]
|
, PersistText "a" ]
|
||||||
it "creates sane SQL (chained)" $ do
|
it "creates sane SQL (chained)" $ do
|
||||||
let obj = object ["a" .= [1 :: Int,2,3]]
|
let obj = object ["a" .= [1 :: Int,2,3]]
|
||||||
createSaneSQL
|
createSaneSQL
|
||||||
(jsonbVal obj ->. "a" ->>. 1)
|
(jsonbVal obj ->. "a" ->>. 1)
|
||||||
"SELECT ((? -> ?) ->> ?)\nFROM \"Json\"\n"
|
"SELECT ((? -> ?) ->> ?)\nFROM \"Json\"\n"
|
||||||
[ PersistDbSpecific "{\"a\":[1,2,3]}"
|
[ PersistLiteralEscaped "{\"a\":[1,2,3]}"
|
||||||
, PersistText "a"
|
, PersistText "a"
|
||||||
, PersistInt64 1 ]
|
, PersistInt64 1 ]
|
||||||
it "works as expected" $ run $ do
|
it "works as expected" $ run $ do
|
||||||
@ -670,14 +665,14 @@ testHashArrowJSONB =
|
|||||||
createSaneSQL @JSONValue
|
createSaneSQL @JSONValue
|
||||||
(jsonbVal (object ["a" .= True]) #>. list)
|
(jsonbVal (object ["a" .= True]) #>. list)
|
||||||
"SELECT (? #> ?)\nFROM \"Json\"\n"
|
"SELECT (? #> ?)\nFROM \"Json\"\n"
|
||||||
[ PersistDbSpecific "{\"a\":true}"
|
[ PersistLiteralEscaped "{\"a\":true}"
|
||||||
, persistTextArray list ]
|
, persistTextArray list ]
|
||||||
it "creates sane SQL (chained)" $ do
|
it "creates sane SQL (chained)" $ do
|
||||||
let obj = object ["a" .= [object ["b" .= True]]]
|
let obj = object ["a" .= [object ["b" .= True]]]
|
||||||
createSaneSQL @JSONValue
|
createSaneSQL @JSONValue
|
||||||
(jsonbVal obj #>. ["a","1"] #>. ["b"])
|
(jsonbVal obj #>. ["a","1"] #>. ["b"])
|
||||||
"SELECT ((? #> ?) #> ?)\nFROM \"Json\"\n"
|
"SELECT ((? #> ?) #> ?)\nFROM \"Json\"\n"
|
||||||
[ PersistDbSpecific "{\"a\":[{\"b\":true}]}"
|
[ PersistLiteralEscaped "{\"a\":[{\"b\":true}]}"
|
||||||
, persistTextArray ["a","1"]
|
, persistTextArray ["a","1"]
|
||||||
, persistTextArray ["b"] ]
|
, persistTextArray ["b"] ]
|
||||||
it "works as expected" $ run $ do
|
it "works as expected" $ run $ do
|
||||||
@ -696,14 +691,14 @@ testHashArrowText =
|
|||||||
createSaneSQL
|
createSaneSQL
|
||||||
(jsonbVal (object ["a" .= True]) #>>. list)
|
(jsonbVal (object ["a" .= True]) #>>. list)
|
||||||
"SELECT (? #>> ?)\nFROM \"Json\"\n"
|
"SELECT (? #>> ?)\nFROM \"Json\"\n"
|
||||||
[ PersistDbSpecific "{\"a\":true}"
|
[ PersistLiteralEscaped "{\"a\":true}"
|
||||||
, persistTextArray list ]
|
, persistTextArray list ]
|
||||||
it "creates sane SQL (chained)" $ do
|
it "creates sane SQL (chained)" $ do
|
||||||
let obj = object ["a" .= [object ["b" .= True]]]
|
let obj = object ["a" .= [object ["b" .= True]]]
|
||||||
createSaneSQL
|
createSaneSQL
|
||||||
(jsonbVal obj #>. ["a","1"] #>>. ["b"])
|
(jsonbVal obj #>. ["a","1"] #>>. ["b"])
|
||||||
"SELECT ((? #> ?) #>> ?)\nFROM \"Json\"\n"
|
"SELECT ((? #> ?) #>> ?)\nFROM \"Json\"\n"
|
||||||
[ PersistDbSpecific "{\"a\":[{\"b\":true}]}"
|
[ PersistLiteralEscaped "{\"a\":[{\"b\":true}]}"
|
||||||
, persistTextArray ["a","1"]
|
, persistTextArray ["a","1"]
|
||||||
, persistTextArray ["b"] ]
|
, persistTextArray ["b"] ]
|
||||||
it "works as expected" $ run $ do
|
it "works as expected" $ run $ do
|
||||||
@ -725,130 +720,155 @@ testFilterOperators =
|
|||||||
|
|
||||||
testInclusion :: Spec
|
testInclusion :: Spec
|
||||||
testInclusion = do
|
testInclusion = do
|
||||||
describe "@>" $ do
|
describe "@>" $ do
|
||||||
it "creates sane SQL" $
|
it "creates sane SQL" $ do
|
||||||
createSaneSQL
|
let obj = object ["a" .= False, "b" .= True]
|
||||||
(jsonbVal (object ["a" .= False, "b" .= True]) @>. jsonbVal (object ["a" .= False]))
|
encoded = BSL.toStrict $ encode obj
|
||||||
"SELECT (? @> ?)\nFROM \"Json\"\n"
|
createSaneSQL
|
||||||
[ PersistDbSpecific "{\"a\":false,\"b\":true}"
|
(jsonbVal obj @>. jsonbVal (object ["a" .= False]))
|
||||||
, PersistDbSpecific "{\"a\":false}" ]
|
"SELECT (? @> ?)\nFROM \"Json\"\n"
|
||||||
it "creates sane SQL (chained)" $ do
|
[ PersistLiteralEscaped encoded
|
||||||
let obj = object ["a" .= [object ["b" .= True]]]
|
, PersistLiteralEscaped "{\"a\":false}"
|
||||||
createSaneSQL
|
]
|
||||||
(jsonbVal obj ->. "a" @>. jsonbVal (object ["b" .= True]))
|
it "creates sane SQL (chained)" $ do
|
||||||
"SELECT ((? -> ?) @> ?)\nFROM \"Json\"\n"
|
let obj = object ["a" .= [object ["b" .= True]]]
|
||||||
[ PersistDbSpecific "{\"a\":[{\"b\":true}]}"
|
encoded = BSL.toStrict $ encode obj
|
||||||
, PersistText "a"
|
createSaneSQL
|
||||||
, PersistDbSpecific "{\"b\":true}" ]
|
(jsonbVal obj ->. "a" @>. jsonbVal (object ["b" .= True]))
|
||||||
it "works as expected" $ run $ do
|
"SELECT ((? -> ?) @> ?)\nFROM \"Json\"\n"
|
||||||
x <- selectJSONwhere $ \v -> v @>. jsonbVal (Number 1)
|
[ PersistLiteralEscaped encoded
|
||||||
y <- selectJSONwhere $ \v -> v @>. jsonbVal (toJSON [object ["a" .= Number 3.14]])
|
, PersistText "a"
|
||||||
z <- selectJSONwhere $ \v -> v ->. 1 @>. jsonbVal (object ["a" .= Number 3.14])
|
, PersistLiteralEscaped "{\"b\":true}"
|
||||||
liftIO $ length x `shouldBe` 2
|
]
|
||||||
liftIO $ length y `shouldBe` 1
|
it "works as expected" $ run $ do
|
||||||
liftIO $ length z `shouldBe` 1
|
x <- selectJSONwhere $ \v -> v @>. jsonbVal (Number 1)
|
||||||
describe "<@" $ do
|
y <- selectJSONwhere $ \v -> v @>. jsonbVal (toJSON [object ["a" .= Number 3.14]])
|
||||||
it "creates sane SQL" $
|
z <- selectJSONwhere $ \v -> v ->. 1 @>. jsonbVal (object ["a" .= Number 3.14])
|
||||||
createSaneSQL
|
liftIO $ length x `shouldBe` 2
|
||||||
(jsonbVal (object ["a" .= False]) <@. jsonbVal (object ["a" .= False, "b" .= True]))
|
liftIO $ length y `shouldBe` 1
|
||||||
"SELECT (? <@ ?)\nFROM \"Json\"\n"
|
liftIO $ length z `shouldBe` 1
|
||||||
[ PersistDbSpecific "{\"a\":false}"
|
describe "<@" $ do
|
||||||
, PersistDbSpecific "{\"a\":false,\"b\":true}" ]
|
it "creates sane SQL" $ do
|
||||||
it "creates sane SQL (chained)" $ do
|
let obj = object ["a" .= False, "b" .= True]
|
||||||
let obj = object ["a" .= [object ["b" .= True]]]
|
encoded = BSL.toStrict $ encode obj
|
||||||
createSaneSQL
|
createSaneSQL
|
||||||
(jsonbVal obj ->. "a" <@. jsonbVal (object ["b" .= True, "c" .= Null]))
|
(jsonbVal (object ["a" .= False]) <@. jsonbVal obj )
|
||||||
"SELECT ((? -> ?) <@ ?)\nFROM \"Json\"\n"
|
"SELECT (? <@ ?)\nFROM \"Json\"\n"
|
||||||
[ PersistDbSpecific "{\"a\":[{\"b\":true}]}"
|
[ PersistLiteralEscaped "{\"a\":false}"
|
||||||
, PersistText "a"
|
, PersistLiteralEscaped encoded
|
||||||
, PersistDbSpecific "{\"b\":true,\"c\":null}" ]
|
]
|
||||||
it "works as expected" $ run $ do
|
it "creates sane SQL (chained)" $ do
|
||||||
x <- selectJSONwhere $ \v -> v <@. jsonbVal (toJSON [Number 1])
|
let obj = object ["a" .= [object ["b" .= True]]]
|
||||||
y <- selectJSONwhere $ \v -> v <@. jsonbVal (object ["a" .= (1 :: Int), "b" .= False, "c" .= Null])
|
obj' = object ["b" .= True, "c" .= Null]
|
||||||
z <- selectJSONwhere $ \v -> v #>. ["a","b"] <@. jsonbVal (object ["b" .= False, "c" .= String "message"])
|
encoded = BSL.toStrict $ encode obj'
|
||||||
liftIO $ length x `shouldBe` 2
|
createSaneSQL
|
||||||
liftIO $ length y `shouldBe` 1
|
(jsonbVal obj ->. "a" <@. jsonbVal obj')
|
||||||
liftIO $ length z `shouldBe` 1
|
"SELECT ((? -> ?) <@ ?)\nFROM \"Json\"\n"
|
||||||
|
[ PersistLiteralEscaped "{\"a\":[{\"b\":true}]}"
|
||||||
|
, PersistText "a"
|
||||||
|
, PersistLiteralEscaped encoded
|
||||||
|
]
|
||||||
|
it "works as expected" $ run $ do
|
||||||
|
x <- selectJSONwhere $ \v -> v <@. jsonbVal (toJSON [Number 1])
|
||||||
|
y <- selectJSONwhere $ \v -> v <@. jsonbVal (object ["a" .= (1 :: Int), "b" .= False, "c" .= Null])
|
||||||
|
z <- selectJSONwhere $ \v -> v #>. ["a","b"] <@. jsonbVal (object ["b" .= False, "c" .= String "message"])
|
||||||
|
liftIO $ length x `shouldBe` 2
|
||||||
|
liftIO $ length y `shouldBe` 1
|
||||||
|
liftIO $ length z `shouldBe` 1
|
||||||
|
|
||||||
testQMark :: Spec
|
testQMark :: Spec
|
||||||
testQMark =
|
testQMark = do
|
||||||
describe "Question Mark" $ do
|
describe "Question Mark" $ do
|
||||||
it "creates sane SQL" $
|
it "creates sane SQL" $ do
|
||||||
createSaneSQL
|
let obj = object ["a" .= False, "b" .= True]
|
||||||
(jsonbVal (object ["a" .= False, "b" .= True]) JSON.?. "a")
|
encoded = BSL.toStrict $ encode obj
|
||||||
"SELECT (? ?? ?)\nFROM \"Json\"\n"
|
createSaneSQL
|
||||||
[ PersistDbSpecific "{\"a\":false,\"b\":true}"
|
(jsonbVal obj JSON.?. "a")
|
||||||
, PersistText "a" ]
|
"SELECT (? ?? ?)\nFROM \"Json\"\n"
|
||||||
it "creates sane SQL (chained)" $ do
|
[ PersistLiteralEscaped encoded
|
||||||
let obj = object ["a" .= [object ["b" .= True]]]
|
, PersistText "a"
|
||||||
createSaneSQL
|
]
|
||||||
(jsonbVal obj #>. ["a","0"] JSON.?. "b")
|
it "creates sane SQL (chained)" $ do
|
||||||
"SELECT ((? #> ?) ?? ?)\nFROM \"Json\"\n"
|
let obj = object ["a" .= [object ["b" .= True]]]
|
||||||
[ PersistDbSpecific "{\"a\":[{\"b\":true}]}"
|
encoded = BSL.toStrict $ encode obj
|
||||||
, persistTextArray ["a","0"]
|
createSaneSQL
|
||||||
, PersistText "b" ]
|
(jsonbVal obj #>. ["a","0"] JSON.?. "b")
|
||||||
it "works as expected" $ run $ do
|
"SELECT ((? #> ?) ?? ?)\nFROM \"Json\"\n"
|
||||||
x <- selectJSONwhere (JSON.?. "a")
|
[ PersistLiteralEscaped encoded
|
||||||
y <- selectJSONwhere (JSON.?. "test")
|
, persistTextArray ["a","0"]
|
||||||
z <- selectJSONwhere $ \v -> v ->. "a" JSON.?. "b"
|
, PersistText "b"
|
||||||
liftIO $ length x `shouldBe` 2
|
]
|
||||||
liftIO $ length y `shouldBe` 2
|
it "works as expected" $ run $ do
|
||||||
liftIO $ length z `shouldBe` 1
|
x <- selectJSONwhere (JSON.?. "a")
|
||||||
|
y <- selectJSONwhere (JSON.?. "test")
|
||||||
|
z <- selectJSONwhere $ \v -> v ->. "a" JSON.?. "b"
|
||||||
|
liftIO $ length x `shouldBe` 2
|
||||||
|
liftIO $ length y `shouldBe` 2
|
||||||
|
liftIO $ length z `shouldBe` 1
|
||||||
|
|
||||||
testQMarkAny :: Spec
|
testQMarkAny :: Spec
|
||||||
testQMarkAny =
|
testQMarkAny = do
|
||||||
describe "Question Mark (Any)" $ do
|
describe "Question Mark (Any)" $ do
|
||||||
it "creates sane SQL" $
|
it "creates sane SQL" $ do
|
||||||
createSaneSQL
|
let obj = (object ["a" .= False, "b" .= True])
|
||||||
(jsonbVal (object ["a" .= False, "b" .= True]) ?|. ["a","c"])
|
encoded = BSL.toStrict $ encode obj
|
||||||
"SELECT (? ??| ?)\nFROM \"Json\"\n"
|
createSaneSQL
|
||||||
[ PersistDbSpecific "{\"a\":false,\"b\":true}"
|
(jsonbVal obj ?|. ["a","c"])
|
||||||
, persistTextArray ["a","c"] ]
|
"SELECT (? ??| ?)\nFROM \"Json\"\n"
|
||||||
it "creates sane SQL (chained)" $ do
|
[ PersistLiteralEscaped encoded
|
||||||
let obj = object ["a" .= [object ["b" .= True]]]
|
, persistTextArray ["a","c"]
|
||||||
createSaneSQL
|
]
|
||||||
(jsonbVal obj #>. ["a","0"] ?|. ["b","c"])
|
it "creates sane SQL (chained)" $ do
|
||||||
"SELECT ((? #> ?) ??| ?)\nFROM \"Json\"\n"
|
let obj = object ["a" .= [object ["b" .= True]]]
|
||||||
[ PersistDbSpecific "{\"a\":[{\"b\":true}]}"
|
encoded = BSL.toStrict $ encode obj
|
||||||
, persistTextArray ["a","0"]
|
createSaneSQL
|
||||||
, persistTextArray ["b","c"] ]
|
(jsonbVal obj #>. ["a","0"] ?|. ["b","c"])
|
||||||
it "works as expected" $ run $ do
|
"SELECT ((? #> ?) ??| ?)\nFROM \"Json\"\n"
|
||||||
x <- selectJSONwhere (?|. ["b","test"])
|
[ PersistLiteralEscaped encoded
|
||||||
y <- selectJSONwhere (?|. ["a"])
|
, persistTextArray ["a","0"]
|
||||||
z <- selectJSONwhere $ \v -> v ->. (-3) ?|. ["a"]
|
, persistTextArray ["b","c"]
|
||||||
w <- selectJSONwhere (?|. [])
|
]
|
||||||
liftIO $ length x `shouldBe` 3
|
it "works as expected" $ run $ do
|
||||||
liftIO $ length y `shouldBe` 2
|
x <- selectJSONwhere (?|. ["b","test"])
|
||||||
liftIO $ length z `shouldBe` 1
|
y <- selectJSONwhere (?|. ["a"])
|
||||||
liftIO $ length w `shouldBe` 0
|
z <- selectJSONwhere $ \v -> v ->. (-3) ?|. ["a"]
|
||||||
|
w <- selectJSONwhere (?|. [])
|
||||||
|
liftIO $ length x `shouldBe` 3
|
||||||
|
liftIO $ length y `shouldBe` 2
|
||||||
|
liftIO $ length z `shouldBe` 1
|
||||||
|
liftIO $ length w `shouldBe` 0
|
||||||
|
|
||||||
testQMarkAll :: Spec
|
testQMarkAll :: Spec
|
||||||
testQMarkAll =
|
testQMarkAll = do
|
||||||
describe "Question Mark (All)" $ do
|
describe "Question Mark (All)" $ do
|
||||||
it "creates sane SQL" $
|
it "creates sane SQL" $ do
|
||||||
createSaneSQL
|
let obj = object ["a" .= False, "b" .= True]
|
||||||
(jsonbVal (object ["a" .= False, "b" .= True]) ?&. ["a","c"])
|
encoded = BSL.toStrict $ encode obj
|
||||||
"SELECT (? ??& ?)\nFROM \"Json\"\n"
|
createSaneSQL
|
||||||
[ PersistDbSpecific "{\"a\":false,\"b\":true}"
|
(jsonbVal obj ?&. ["a","c"])
|
||||||
, persistTextArray ["a","c"] ]
|
"SELECT (? ??& ?)\nFROM \"Json\"\n"
|
||||||
it "creates sane SQL (chained)" $ do
|
[ PersistLiteralEscaped encoded
|
||||||
let obj = object ["a" .= [object ["b" .= True]]]
|
, persistTextArray ["a","c"]
|
||||||
createSaneSQL
|
]
|
||||||
(jsonbVal obj #>. ["a","0"] ?&. ["b","c"])
|
it "creates sane SQL (chained)" $ do
|
||||||
"SELECT ((? #> ?) ??& ?)\nFROM \"Json\"\n"
|
let obj = object ["a" .= [object ["b" .= True]]]
|
||||||
[ PersistDbSpecific "{\"a\":[{\"b\":true}]}"
|
encoded = BSL.toStrict $ encode obj
|
||||||
, persistTextArray ["a","0"]
|
createSaneSQL
|
||||||
, persistTextArray ["b","c"] ]
|
(jsonbVal obj #>. ["a","0"] ?&. ["b","c"])
|
||||||
it "works as expected" $ run $ do
|
"SELECT ((? #> ?) ??& ?)\nFROM \"Json\"\n"
|
||||||
x <- selectJSONwhere (?&. ["test"])
|
[ PersistLiteralEscaped encoded
|
||||||
y <- selectJSONwhere (?&. ["a","b"])
|
, persistTextArray ["a","0"]
|
||||||
z <- selectJSONwhere $ \v -> v ->. "a" ?&. ["b"]
|
, persistTextArray ["b","c"]
|
||||||
w <- selectJSONwhere (?&. [])
|
]
|
||||||
liftIO $ length x `shouldBe` 2
|
it "works as expected" $ run $ do
|
||||||
liftIO $ length y `shouldBe` 1
|
x <- selectJSONwhere (?&. ["test"])
|
||||||
liftIO $ length z `shouldBe` 1
|
y <- selectJSONwhere (?&. ["a","b"])
|
||||||
liftIO $ length w `shouldBe` 9
|
z <- selectJSONwhere $ \v -> v ->. "a" ?&. ["b"]
|
||||||
|
w <- selectJSONwhere (?&. [])
|
||||||
|
liftIO $ length x `shouldBe` 2
|
||||||
|
liftIO $ length y `shouldBe` 1
|
||||||
|
liftIO $ length z `shouldBe` 1
|
||||||
|
liftIO $ length w `shouldBe` 9
|
||||||
|
|
||||||
testConcatDeleteOperators :: Spec
|
testConcatDeleteOperators :: Spec
|
||||||
testConcatDeleteOperators = do
|
testConcatDeleteOperators = do
|
||||||
@ -859,120 +879,135 @@ testConcatDeleteOperators = do
|
|||||||
testHashMinusOperator
|
testHashMinusOperator
|
||||||
|
|
||||||
testConcatenationOperator :: Spec
|
testConcatenationOperator :: Spec
|
||||||
testConcatenationOperator =
|
testConcatenationOperator = do
|
||||||
describe "Concatenation" $ do
|
describe "Concatenation" $ do
|
||||||
it "creates sane SQL" $
|
it "creates sane SQL" $ do
|
||||||
createSaneSQL @JSONValue
|
let objAB = object ["a" .= False, "b" .= True]
|
||||||
(jsonbVal (object ["a" .= False, "b" .= True])
|
objC = object ["c" .= Null]
|
||||||
JSON.||. jsonbVal (object ["c" .= Null]))
|
createSaneSQL @JSONValue
|
||||||
"SELECT (? || ?)\nFROM \"Json\"\n"
|
(jsonbVal objAB
|
||||||
[ PersistDbSpecific "{\"a\":false,\"b\":true}"
|
JSON.||. jsonbVal objC)
|
||||||
, PersistDbSpecific "{\"c\":null}" ]
|
"SELECT (? || ?)\nFROM \"Json\"\n"
|
||||||
it "creates sane SQL (chained)" $ do
|
[ PersistLiteralEscaped $ BSL.toStrict $ encode objAB
|
||||||
let obj = object ["a" .= [object ["b" .= True]]]
|
, PersistLiteralEscaped $ BSL.toStrict $ encode objC
|
||||||
createSaneSQL @JSONValue
|
]
|
||||||
(jsonbVal obj ->. "a" JSON.||. jsonbVal (toJSON [Null]))
|
it "creates sane SQL (chained)" $ do
|
||||||
"SELECT ((? -> ?) || ?)\nFROM \"Json\"\n"
|
let obj = object ["a" .= [object ["b" .= True]]]
|
||||||
[ PersistDbSpecific "{\"a\":[{\"b\":true}]}"
|
encoded = BSL.toStrict $ encode obj
|
||||||
, PersistText "a"
|
createSaneSQL @JSONValue
|
||||||
, PersistDbSpecific "[null]" ]
|
(jsonbVal obj ->. "a" JSON.||. jsonbVal (toJSON [Null]))
|
||||||
it "works as expected" $ run $ do
|
"SELECT ((? -> ?) || ?)\nFROM \"Json\"\n"
|
||||||
x <- selectJSON $ \v -> do
|
[ PersistLiteralEscaped encoded
|
||||||
where_ $ v @>. jsonbVal (object [])
|
, PersistText "a"
|
||||||
where_ $ v JSON.||. jsonbVal (object ["x" .= True])
|
, PersistLiteralEscaped "[null]"
|
||||||
@>. jsonbVal (object ["x" .= True])
|
]
|
||||||
y <- selectJSONwhere $ \v ->
|
it "works as expected" $ run $ do
|
||||||
v JSON.||. jsonbVal (toJSON [String "a", String "b"])
|
x <- selectJSON $ \v -> do
|
||||||
->>. 4 ==. just (val "b")
|
where_ $ v @>. jsonbVal (object [])
|
||||||
z <- selectJSONwhere $ \v ->
|
where_ $ v JSON.||. jsonbVal (object ["x" .= True])
|
||||||
v JSON.||. jsonbVal (toJSON [Bool False])
|
@>. jsonbVal (object ["x" .= True])
|
||||||
->. 0 JSON.@>. jsonbVal (Number 1)
|
y <- selectJSONwhere $ \v ->
|
||||||
w <- selectJSON $ \v -> do
|
v JSON.||. jsonbVal (toJSON [String "a", String "b"])
|
||||||
where_ . not_ $ v @>. jsonbVal (object [])
|
->>. 4 ==. just (val "b")
|
||||||
where_ $ jsonbVal (String "test1") JSON.||. v ->>. 0 ==. just (val "test1")
|
z <- selectJSONwhere $ \v ->
|
||||||
liftIO $ length x `shouldBe` 2
|
v JSON.||. jsonbVal (toJSON [Bool False])
|
||||||
liftIO $ length y `shouldBe` 1
|
->. 0 JSON.@>. jsonbVal (Number 1)
|
||||||
liftIO $ length z `shouldBe` 2
|
w <- selectJSON $ \v -> do
|
||||||
liftIO $ length w `shouldBe` 7
|
where_ . not_ $ v @>. jsonbVal (object [])
|
||||||
sqlFailWith "22023" $ selectJSONwhere $ \v ->
|
where_ $ jsonbVal (String "test1") JSON.||. v ->>. 0 ==. just (val "test1")
|
||||||
v JSON.||. jsonbVal (toJSON $ String "test")
|
liftIO $ length x `shouldBe` 2
|
||||||
@>. jsonbVal (String "test")
|
liftIO $ length y `shouldBe` 1
|
||||||
|
liftIO $ length z `shouldBe` 2
|
||||||
|
liftIO $ length w `shouldBe` 7
|
||||||
|
|
||||||
testMinusOperator :: Spec
|
testMinusOperator :: Spec
|
||||||
testMinusOperator =
|
testMinusOperator =
|
||||||
describe "Minus Operator" $ do
|
describe "Minus Operator" $ do
|
||||||
it "creates sane SQL" $
|
it "creates sane SQL" $ do
|
||||||
createSaneSQL @JSONValue
|
let obj = object ["a" .= False, "b" .= True]
|
||||||
(jsonbVal (object ["a" .= False, "b" .= True]) JSON.-. "a")
|
encoded = BSL.toStrict $ encode obj
|
||||||
"SELECT (? - ?)\nFROM \"Json\"\n"
|
createSaneSQL @JSONValue
|
||||||
[ PersistDbSpecific "{\"a\":false,\"b\":true}"
|
(jsonbVal obj JSON.-. "a")
|
||||||
, PersistText "a" ]
|
"SELECT (? - ?)\nFROM \"Json\"\n"
|
||||||
it "creates sane SQL (chained)" $ do
|
[ PersistLiteralEscaped encoded
|
||||||
let obj = object ["a" .= [object ["b" .= True]]]
|
, PersistText "a"
|
||||||
createSaneSQL @JSONValue
|
]
|
||||||
(jsonbVal obj ->. "a" JSON.-. 0)
|
it "creates sane SQL (chained)" $ do
|
||||||
"SELECT ((? -> ?) - ?)\nFROM \"Json\"\n"
|
let obj = object ["a" .= [object ["b" .= True]]]
|
||||||
[ PersistDbSpecific "{\"a\":[{\"b\":true}]}"
|
encoded = BSL.toStrict $ encode obj
|
||||||
, PersistText "a"
|
createSaneSQL @JSONValue
|
||||||
, PersistInt64 0 ]
|
(jsonbVal obj ->. "a" JSON.-. 0)
|
||||||
it "works as expected" $ run $ do
|
"SELECT ((? -> ?) - ?)\nFROM \"Json\"\n"
|
||||||
x <- selectJSON $ \v -> do
|
[ PersistLiteralEscaped encoded
|
||||||
where_ $ v @>. jsonbVal (toJSON ([] :: [Int]))
|
, PersistText "a"
|
||||||
where_ $ v JSON.-. 0 @>. jsonbVal (toJSON [Bool True])
|
, PersistInt64 0
|
||||||
y <- selectJSON $ \v -> do
|
]
|
||||||
where_ $ v @>. jsonbVal (toJSON ([] :: [Int]))
|
it "works as expected" $ run $ do
|
||||||
where_ $ v JSON.-. (-1) @>. jsonbVal (toJSON [Null])
|
x <- selectJSON $ \v -> do
|
||||||
z <- selectJSON_ $ \v -> v JSON.-. "b" ?&. ["a", "b"]
|
where_ $ v @>. jsonbVal (toJSON ([] :: [Int]))
|
||||||
w <- selectJSON_ $ \v -> do
|
where_ $ v JSON.-. 0 @>. jsonbVal (toJSON [Bool True])
|
||||||
v JSON.-. "test" @>. jsonbVal (toJSON [String "test"])
|
y <- selectJSON $ \v -> do
|
||||||
liftIO $ length x `shouldBe` 2
|
where_ $ v @>. jsonbVal (toJSON ([] :: [Int]))
|
||||||
liftIO $ length y `shouldBe` 1
|
where_ $ v JSON.-. (-1) @>. jsonbVal (toJSON [Null])
|
||||||
liftIO $ length z `shouldBe` 0
|
z <- selectJSON_ $ \v -> v JSON.-. "b" ?&. ["a", "b"]
|
||||||
liftIO $ length w `shouldBe` 0
|
w <- selectJSON_ $ \v -> do
|
||||||
sqlFailWith "22023" $ selectJSONwhere $ \v ->
|
v JSON.-. "test" @>. jsonbVal (toJSON [String "test"])
|
||||||
v JSON.-. 0 @>. jsonbVal (toJSON ([] :: [Int]))
|
liftIO $ length x `shouldBe` 2
|
||||||
where selectJSON_ f = selectJSON $ \v -> do
|
liftIO $ length y `shouldBe` 1
|
||||||
where_ $ v @>. jsonbVal (object [])
|
liftIO $ length z `shouldBe` 0
|
||||||
||. v @>. jsonbVal (toJSON ([] :: [Int]))
|
liftIO $ length w `shouldBe` 0
|
||||||
where_ $ f v
|
sqlFailWith "22023" $ selectJSONwhere $ \v ->
|
||||||
|
v JSON.-. 0 @>. jsonbVal (toJSON ([] :: [Int]))
|
||||||
|
where
|
||||||
|
selectJSON_ f = selectJSON $ \v -> do
|
||||||
|
where_
|
||||||
|
$ v @>. jsonbVal (object [])
|
||||||
|
||. v @>. jsonbVal (toJSON ([] :: [Int]))
|
||||||
|
where_ $ f v
|
||||||
|
|
||||||
testMinusOperatorV10 :: Spec
|
testMinusOperatorV10 :: Spec
|
||||||
testMinusOperatorV10 =
|
testMinusOperatorV10 = do
|
||||||
describe "Minus Operator (PSQL >= v10)" $ do
|
describe "Minus Operator (PSQL >= v10)" $ do
|
||||||
it "creates sane SQL" $
|
it "creates sane SQL" $ do
|
||||||
createSaneSQL @JSONValue
|
let obj = object ["a" .= False, "b" .= True]
|
||||||
(jsonbVal (object ["a" .= False, "b" .= True]) --. ["a","b"])
|
encoded = BSL.toStrict $ encode obj
|
||||||
"SELECT (? - ?)\nFROM \"Json\"\n"
|
createSaneSQL @JSONValue
|
||||||
[ PersistDbSpecific "{\"a\":false,\"b\":true}"
|
(jsonbVal obj --. ["a","b"])
|
||||||
, persistTextArray ["a","b"] ]
|
"SELECT (? - ?)\nFROM \"Json\"\n"
|
||||||
it "creates sane SQL (chained)" $ do
|
[ PersistLiteralEscaped encoded
|
||||||
let obj = object ["a" .= [object ["b" .= True]]]
|
, persistTextArray ["a","b"]
|
||||||
createSaneSQL @JSONValue
|
]
|
||||||
(jsonbVal obj #>. ["a","0"] --. ["b"])
|
it "creates sane SQL (chained)" $ do
|
||||||
"SELECT ((? #> ?) - ?)\nFROM \"Json\"\n"
|
let obj = object ["a" .= [object ["b" .= True]]]
|
||||||
[ PersistDbSpecific "{\"a\":[{\"b\":true}]}"
|
encoded = BSL.toStrict $ encode obj
|
||||||
, persistTextArray ["a","0"]
|
createSaneSQL @JSONValue
|
||||||
, persistTextArray ["b"] ]
|
(jsonbVal obj #>. ["a","0"] --. ["b"])
|
||||||
it "works as expected" $ run $ do
|
"SELECT ((? #> ?) - ?)\nFROM \"Json\"\n"
|
||||||
x <- selectJSON $ \v -> do
|
[ PersistLiteralEscaped encoded
|
||||||
where_ $ v @>. jsonbVal (toJSON ([] :: [Int]))
|
, persistTextArray ["a","0"]
|
||||||
where_ $ v --. ["test","a"] @>. jsonbVal (toJSON [String "test"])
|
, persistTextArray ["b"]
|
||||||
y <- selectJSON $ \v -> do
|
]
|
||||||
where_ $ v @>. jsonbVal (object [])
|
it "works as expected" $ run $ do
|
||||||
where_ $ v --. ["a","b"] <@. jsonbVal (object [])
|
x <- selectJSON $ \v -> do
|
||||||
z <- selectJSON_ $ \v -> v --. ["b"] <@. jsonbVal (object ["a" .= (1 :: Int)])
|
where_ $ v @>. jsonbVal (toJSON ([] :: [Int]))
|
||||||
w <- selectJSON_ $ \v -> do
|
where_ $ v --. ["test","a"] @>. jsonbVal (toJSON [String "test"])
|
||||||
v --. ["test"] @>. jsonbVal (toJSON [String "test"])
|
y <- selectJSON $ \v -> do
|
||||||
liftIO $ length x `shouldBe` 0
|
where_ $ v @>. jsonbVal (object [])
|
||||||
liftIO $ length y `shouldBe` 2
|
where_ $ v --. ["a","b"] <@. jsonbVal (object [])
|
||||||
liftIO $ length z `shouldBe` 1
|
z <- selectJSON_ $ \v -> v --. ["b"] <@. jsonbVal (object ["a" .= (1 :: Int)])
|
||||||
liftIO $ length w `shouldBe` 0
|
w <- selectJSON_ $ \v -> do
|
||||||
sqlFailWith "22023" $ selectJSONwhere $ \v ->
|
v --. ["test"] @>. jsonbVal (toJSON [String "test"])
|
||||||
v --. ["a"] @>. jsonbVal (toJSON ([] :: [Int]))
|
liftIO $ length x `shouldBe` 0
|
||||||
where selectJSON_ f = selectJSON $ \v -> do
|
liftIO $ length y `shouldBe` 2
|
||||||
where_ $ v @>. jsonbVal (object [])
|
liftIO $ length z `shouldBe` 1
|
||||||
|
liftIO $ length w `shouldBe` 0
|
||||||
|
sqlFailWith "22023" $ selectJSONwhere $ \v ->
|
||||||
|
v --. ["a"] @>. jsonbVal (toJSON ([] :: [Int]))
|
||||||
|
where
|
||||||
|
selectJSON_ f = selectJSON $ \v -> do
|
||||||
|
where_ $ v @>. jsonbVal (object [])
|
||||||
||. v @>. jsonbVal (toJSON ([] :: [Int]))
|
||. v @>. jsonbVal (toJSON ([] :: [Int]))
|
||||||
where_ $ f v
|
where_ $ f v
|
||||||
|
|
||||||
testHashMinusOperator :: Spec
|
testHashMinusOperator :: Spec
|
||||||
testHashMinusOperator =
|
testHashMinusOperator =
|
||||||
@ -981,14 +1016,14 @@ testHashMinusOperator =
|
|||||||
createSaneSQL @JSONValue
|
createSaneSQL @JSONValue
|
||||||
(jsonbVal (object ["a" .= False, "b" .= True]) #-. ["a"])
|
(jsonbVal (object ["a" .= False, "b" .= True]) #-. ["a"])
|
||||||
"SELECT (? #- ?)\nFROM \"Json\"\n"
|
"SELECT (? #- ?)\nFROM \"Json\"\n"
|
||||||
[ PersistDbSpecific "{\"a\":false,\"b\":true}"
|
[ PersistLiteralEscaped (BSL.toStrict $ encode $ object ["a" .= False, "b" .= True])
|
||||||
, persistTextArray ["a"] ]
|
, persistTextArray ["a"] ]
|
||||||
it "creates sane SQL (chained)" $ do
|
it "creates sane SQL (chained)" $ do
|
||||||
let obj = object ["a" .= [object ["b" .= True]]]
|
let obj = object ["a" .= [object ["b" .= True]]]
|
||||||
createSaneSQL @JSONValue
|
createSaneSQL @JSONValue
|
||||||
(jsonbVal obj ->. "a" #-. ["0","b"])
|
(jsonbVal obj ->. "a" #-. ["0","b"])
|
||||||
"SELECT ((? -> ?) #- ?)\nFROM \"Json\"\n"
|
"SELECT ((? -> ?) #- ?)\nFROM \"Json\"\n"
|
||||||
[ PersistDbSpecific "{\"a\":[{\"b\":true}]}"
|
[ PersistLiteralEscaped (BSL.toStrict $ encode obj)
|
||||||
, PersistText "a"
|
, PersistText "a"
|
||||||
, persistTextArray ["0","b"] ]
|
, persistTextArray ["0","b"] ]
|
||||||
it "works as expected" $ run $ do
|
it "works as expected" $ run $ do
|
||||||
@ -1309,20 +1344,30 @@ fromValue act = from $ \x -> do
|
|||||||
persistTextArray :: [T.Text] -> PersistValue
|
persistTextArray :: [T.Text] -> PersistValue
|
||||||
persistTextArray = PersistArray . fmap PersistText
|
persistTextArray = PersistArray . fmap PersistText
|
||||||
|
|
||||||
sqlFailWith :: (MonadCatch m, MonadIO m) => ByteString -> SqlPersistT (R.ResourceT m) a -> SqlPersistT (R.ResourceT m) ()
|
sqlFailWith :: (HasCallStack, MonadCatch m, MonadIO m, Show a) => ByteString -> SqlPersistT (R.ResourceT m) a -> SqlPersistT (R.ResourceT m) ()
|
||||||
sqlFailWith errState f = do
|
sqlFailWith errState f = do
|
||||||
p <- (f >> return True) `catch` success
|
eres <- try f
|
||||||
when p failed
|
case eres of
|
||||||
where success SqlError{sqlState}
|
Left err ->
|
||||||
| sqlState == errState = return False
|
success err
|
||||||
| otherwise = do
|
Right a ->
|
||||||
liftIO $ expectationFailure $ T.unpack $ T.concat
|
liftIO $ expectationFailure $ mconcat
|
||||||
[ "should fail with: ", errStateT
|
[ "should fail with error code: "
|
||||||
, ", but received: ", TE.decodeUtf8 sqlState
|
, T.unpack errStateT
|
||||||
]
|
, ", but got: "
|
||||||
return False
|
, show a
|
||||||
failed = liftIO $ expectationFailure $ "should fail with: " `mappend` T.unpack errStateT
|
]
|
||||||
errStateT = TE.decodeUtf8 errState
|
where
|
||||||
|
success SqlError{sqlState}
|
||||||
|
| sqlState == errState =
|
||||||
|
pure ()
|
||||||
|
| otherwise = do
|
||||||
|
liftIO $ expectationFailure $ T.unpack $ T.concat
|
||||||
|
[ "should fail with: ", errStateT
|
||||||
|
, ", but received: ", TE.decodeUtf8 sqlState
|
||||||
|
]
|
||||||
|
errStateT =
|
||||||
|
TE.decodeUtf8 errState
|
||||||
|
|
||||||
selectJSONwhere
|
selectJSONwhere
|
||||||
:: MonadIO m
|
:: MonadIO m
|
||||||
@ -1406,8 +1451,26 @@ migrateIt = do
|
|||||||
cleanUniques
|
cleanUniques
|
||||||
|
|
||||||
withConn :: RunDbMonad m => (SqlBackend -> R.ResourceT m a) -> m a
|
withConn :: RunDbMonad m => (SqlBackend -> R.ResourceT m a) -> m a
|
||||||
withConn =
|
withConn f = do
|
||||||
R.runResourceT . withPostgresqlConn "host=localhost port=5432 user=esqutest password=esqutest dbname=esqutest"
|
ea <- try go
|
||||||
|
case ea of
|
||||||
|
Left (SomeException se) -> do
|
||||||
|
ea' <- try go
|
||||||
|
case ea' of
|
||||||
|
Left (SomeException se1) ->
|
||||||
|
if show se == show se1
|
||||||
|
then throwM se
|
||||||
|
else throwM se1
|
||||||
|
Right a ->
|
||||||
|
pure a
|
||||||
|
Right a ->
|
||||||
|
pure a
|
||||||
|
where
|
||||||
|
go =
|
||||||
|
R.runResourceT $
|
||||||
|
withPostgresqlConn
|
||||||
|
"host=localhost port=5432 user=esqutest password=esqutest dbname=esqutest"
|
||||||
|
f
|
||||||
|
|
||||||
-- | Show the SQL generated by a query
|
-- | Show the SQL generated by a query
|
||||||
showQuery :: (Monad m, ES.SqlSelect a r, BackendCompatible SqlBackend backend)
|
showQuery :: (Monad m, ES.SqlSelect a r, BackendCompatible SqlBackend backend)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user