Add support for EXISTS and NOT EXISTS.

This commit is contained in:
Felipe Lessa 2012-11-28 18:23:07 -02:00
parent 927bc831f8
commit 4769d30b18
4 changed files with 57 additions and 0 deletions

View File

@ -24,6 +24,7 @@ module Database.Esqueleto
, (==.), (>=.), (>.), (<=.), (<.), (!=.), (&&.), (||.)
, (+.), (-.), (/.), (*.)
, like, (%), concat_, (++.)
, exists, notExists
, set, (=.), (+=.), (-=.), (*=.), (/=.) )
, from
, Value(..)

View File

@ -240,6 +240,21 @@ class (Functor query, Applicative query, Monad query) =>
-- Supported by SQLite and PostgreSQL.
(++.) :: (PersistField s, IsString s) => expr (Value s) -> expr (Value s) -> expr (Value s)
-- | @EXISTS@ operator. For example:
--
-- @
-- select $
-- from $ \person -> do
-- where_ $ exists $
-- from $ \post -> do
-- where_ (post ^. BlogPostAuthorId ==. person ^. PersonId)
-- return person
-- @
exists :: query () -> expr (Value Bool)
-- | @NOT EXISTS@ operator.
notExists :: query () -> expr (Value Bool)
-- | @SET@ clause used on @UPDATE@s. Note that while it's not
-- a type error to use this function on a @SELECT@, it will
-- most certainly result in a runtime error.

View File

@ -324,6 +324,9 @@ instance Esqueleto SqlQuery SqlExpr SqlPersist where
concat_ = unsafeSqlFunction "CONCAT"
(++.) = unsafeSqlBinOp " || "
exists = unsafeSqlFunction "EXISTS " . existsHelper
notExists = unsafeSqlFunction "NOT EXISTS " . existsHelper
set ent upds = Q $ W.tell mempty { sdSetClause = map apply upds }
where
apply (ESet f) = SetClause (f ent)
@ -356,6 +359,12 @@ sub mode query = ERaw Parens $ \conn -> first parens (toRawSql mode conn query)
fromDBName :: Connection -> DBName -> TLB.Builder
fromDBName conn = TLB.fromText . escapeName conn
existsHelper :: SqlQuery () -> SqlExpr (Value a)
existsHelper =
ERaw Parens .
flip (toRawSql SELECT) .
(>> return (val True :: SqlExpr (Value Bool)))
----------------------------------------------------------------------

View File

@ -463,6 +463,38 @@ main = do
, Entity p3k p3 { personAge = Just 7 }
, Entity p2k p2 { personAge = Just 0 } ]
describe "lists of values" $ do
it "EXISTS works for subList_select" $
run $ do
p1k <- insert p1
p2k <- insert p2
p3k <- insert p3
_ <- insert (BlogPost "" p1k)
_ <- insert (BlogPost "" p3k)
ret <- select $
from $ \p -> do
where_ $ exists $
from $ \bp -> do
where_ (bp ^. BlogPostAuthorId ==. p ^. PersonId)
return p
liftIO $ ret `shouldBe` [ Entity p1k p1
, Entity p3k p3 ]
it "EXISTS works for subList_select" $
run $ do
p1k <- insert p1
p2k <- insert p2
p3k <- insert p3
_ <- insert (BlogPost "" p1k)
_ <- insert (BlogPost "" p3k)
ret <- select $
from $ \p -> do
where_ $ notExists $
from $ \bp -> do
where_ (bp ^. BlogPostAuthorId ==. p ^. PersonId)
return p
liftIO $ ret `shouldBe` [ Entity p2k p2 ]
----------------------------------------------------------------------