Bump version and add more comments
This commit is contained in:
parent
ae9ef126d9
commit
4f9793f6cb
@ -1,14 +1,17 @@
|
|||||||
3.4.1.0
|
3.5.0.0
|
||||||
=======-
|
=======-
|
||||||
- @belevy
|
- @belevy
|
||||||
- [#228](https://github.com/bitemyapp/esqueleto/pull/228)
|
- [#228](https://github.com/bitemyapp/esqueleto/pull/228)
|
||||||
- Destroy all GADTs; Removes the From GADT and SqlExpr GADT
|
- Destroy all GADTs; Removes the From GADT and SqlExpr GADT
|
||||||
- From GADT is replaced with a From typeclass
|
- From GADT is replaced with a From data type and FromRaw
|
||||||
- SqlExpr is now all defined in terms of ERaw
|
- SqlExpr is now all defined in terms of ERaw
|
||||||
- Modified ERaw to contain a SqlExprMeta with any extra information
|
- Modified ERaw to contain a SqlExprMeta with any extra information
|
||||||
that may be needed
|
that may be needed
|
||||||
- Experimental top level is now strictly for documentation and all the
|
- Experimental top level is now strictly for documentation and all the
|
||||||
implementation details are in Experimental.* modules
|
implementation details are in Experimental.* modules
|
||||||
|
|
||||||
|
3.4.1.0
|
||||||
|
=======
|
||||||
- @Vlix
|
- @Vlix
|
||||||
- [#232](https://github.com/bitemyapp/esqueleto/pull/232)
|
- [#232](https://github.com/bitemyapp/esqueleto/pull/232)
|
||||||
- Export the `ValidOnClauseValue` type family
|
- Export the `ValidOnClauseValue` type family
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
cabal-version: 1.12
|
cabal-version: 1.12
|
||||||
|
|
||||||
name: esqueleto
|
name: esqueleto
|
||||||
version: 3.4.1.0
|
version: 3.5.0.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.
|
||||||
.
|
.
|
||||||
|
|||||||
@ -18,13 +18,24 @@ module Database.Esqueleto.Experimental
|
|||||||
|
|
||||||
-- * Documentation
|
-- * Documentation
|
||||||
|
|
||||||
Table(..)
|
-- ** Basic Queries
|
||||||
|
from
|
||||||
, table
|
, table
|
||||||
, from
|
, Table(..)
|
||||||
, SubQuery(..)
|
, SubQuery(..)
|
||||||
, selectQuery
|
, selectQuery
|
||||||
|
|
||||||
|
-- ** Joins
|
||||||
, (:&)(..)
|
, (:&)(..)
|
||||||
, on
|
, on
|
||||||
|
, innerJoin
|
||||||
|
, innerJoinLateral
|
||||||
|
, leftJoin
|
||||||
|
, leftJoinLateral
|
||||||
|
, rightJoin
|
||||||
|
, fullOuterJoin
|
||||||
|
, crossJoin
|
||||||
|
, crossJoinLateral
|
||||||
|
|
||||||
-- ** Set Operations
|
-- ** Set Operations
|
||||||
-- $sql-set-operations
|
-- $sql-set-operations
|
||||||
@ -42,16 +53,7 @@ module Database.Esqueleto.Experimental
|
|||||||
, with
|
, with
|
||||||
, withRecursive
|
, withRecursive
|
||||||
|
|
||||||
, innerJoin
|
-- ** Internals
|
||||||
, innerJoinLateral
|
|
||||||
, leftJoin
|
|
||||||
, leftJoinLateral
|
|
||||||
, rightJoin
|
|
||||||
, fullOuterJoin
|
|
||||||
, crossJoin
|
|
||||||
, crossJoinLateral
|
|
||||||
|
|
||||||
-- * Internals
|
|
||||||
, From(..)
|
, From(..)
|
||||||
, ToMaybe(..)
|
, ToMaybe(..)
|
||||||
, ToAlias(..)
|
, ToAlias(..)
|
||||||
@ -60,8 +62,8 @@ module Database.Esqueleto.Experimental
|
|||||||
, ToAliasReferenceT
|
, ToAliasReferenceT
|
||||||
, ToSqlSetOperation(..)
|
, ToSqlSetOperation(..)
|
||||||
, ValidOnClauseValue
|
, ValidOnClauseValue
|
||||||
-- * The Normal Stuff
|
|
||||||
|
|
||||||
|
-- * The Normal Stuff
|
||||||
, where_
|
, where_
|
||||||
, groupBy
|
, groupBy
|
||||||
, orderBy
|
, orderBy
|
||||||
@ -174,6 +176,7 @@ module Database.Esqueleto.Experimental
|
|||||||
, DistinctOn
|
, DistinctOn
|
||||||
, LockingKind(..)
|
, LockingKind(..)
|
||||||
, SqlString
|
, SqlString
|
||||||
|
|
||||||
-- ** Joins
|
-- ** Joins
|
||||||
, InnerJoin(..)
|
, InnerJoin(..)
|
||||||
, CrossJoin(..)
|
, CrossJoin(..)
|
||||||
@ -182,7 +185,8 @@ module Database.Esqueleto.Experimental
|
|||||||
, FullOuterJoin(..)
|
, FullOuterJoin(..)
|
||||||
, JoinKind(..)
|
, JoinKind(..)
|
||||||
, OnClauseWithoutMatchingJoinException(..)
|
, OnClauseWithoutMatchingJoinException(..)
|
||||||
-- * SQL backend
|
|
||||||
|
-- ** SQL backend
|
||||||
, SqlQuery
|
, SqlQuery
|
||||||
, SqlExpr
|
, SqlExpr
|
||||||
, SqlEntity
|
, SqlEntity
|
||||||
@ -196,22 +200,20 @@ module Database.Esqueleto.Experimental
|
|||||||
, insertSelectCount
|
, insertSelectCount
|
||||||
, (<#)
|
, (<#)
|
||||||
, (<&>)
|
, (<&>)
|
||||||
|
|
||||||
-- ** Rendering Queries
|
-- ** Rendering Queries
|
||||||
, renderQueryToText
|
, renderQueryToText
|
||||||
, renderQuerySelect
|
, renderQuerySelect
|
||||||
, renderQueryUpdate
|
, renderQueryUpdate
|
||||||
, renderQueryDelete
|
, renderQueryDelete
|
||||||
, renderQueryInsertInto
|
, renderQueryInsertInto
|
||||||
-- * Internal.Language
|
|
||||||
-- * RDBMS-specific modules
|
|
||||||
-- $rdbmsSpecificModules
|
|
||||||
|
|
||||||
-- * Helpers
|
-- ** Helpers
|
||||||
, valkey
|
, valkey
|
||||||
, valJ
|
, valJ
|
||||||
, associateJoin
|
, associateJoin
|
||||||
|
|
||||||
-- * Re-exports
|
-- ** Re-exports
|
||||||
-- $reexports
|
-- $reexports
|
||||||
, deleteKey
|
, deleteKey
|
||||||
, module Database.Esqueleto.Internal.PersistentImport
|
, module Database.Esqueleto.Internal.PersistentImport
|
||||||
@ -316,7 +318,7 @@ import Database.Esqueleto.Experimental.ToMaybe
|
|||||||
--
|
--
|
||||||
-- @
|
-- @
|
||||||
-- select $ do
|
-- select $ do
|
||||||
-- people <- from $ Table \@Person
|
-- people <- from $ table \@Person
|
||||||
-- where_ (people ^. PersonName ==. val \"John\")
|
-- where_ (people ^. PersonName ==. val \"John\")
|
||||||
-- pure people
|
-- pure people
|
||||||
-- @
|
-- @
|
||||||
@ -344,8 +346,8 @@ import Database.Esqueleto.Experimental.ToMaybe
|
|||||||
-- @
|
-- @
|
||||||
-- select $ do
|
-- select $ do
|
||||||
-- (people :& blogPosts) <-
|
-- (people :& blogPosts) <-
|
||||||
-- from $ Table \@Person
|
-- from $ table \@Person
|
||||||
-- \`LeftOuterJoin\` Table \@BlogPost
|
-- \`leftJoin\` table \@BlogPost
|
||||||
-- \`on\` (\\(people :& blogPosts) ->
|
-- \`on\` (\\(people :& blogPosts) ->
|
||||||
-- people ^. PersonId ==. blogPosts ?. BlogPostAuthorId)
|
-- people ^. PersonId ==. blogPosts ?. BlogPostAuthorId)
|
||||||
-- where_ (people ^. PersonAge >. val 18)
|
-- where_ (people ^. PersonAge >. val 18)
|
||||||
@ -376,7 +378,7 @@ import Database.Esqueleto.Experimental.ToMaybe
|
|||||||
--
|
--
|
||||||
-- In this version, with each successive 'on' clause, only the tables
|
-- In this version, with each successive 'on' clause, only the tables
|
||||||
-- we have already joined into are in scope, so we must pattern match
|
-- we have already joined into are in scope, so we must pattern match
|
||||||
-- accordingly. In this case, in the second 'InnerJoin', we do not use
|
-- accordingly. In this case, in the second 'innerJoin', we do not use
|
||||||
-- the first `Person` reference, so we use @_@ as a placeholder to
|
-- the first `Person` reference, so we use @_@ as a placeholder to
|
||||||
-- ignore it. This prevents a possible runtime error where a table
|
-- ignore it. This prevents a possible runtime error where a table
|
||||||
-- is referenced before it appears in the sequence of 'JOIN's.
|
-- is referenced before it appears in the sequence of 'JOIN's.
|
||||||
@ -384,11 +386,11 @@ import Database.Esqueleto.Experimental.ToMaybe
|
|||||||
-- @
|
-- @
|
||||||
-- select $ do
|
-- select $ do
|
||||||
-- (people1 :& followers :& people2) <-
|
-- (people1 :& followers :& people2) <-
|
||||||
-- from $ Table \@Person
|
-- from $ table \@Person
|
||||||
-- \`InnerJoin` Table \@Follow
|
-- \`innerJoin` table \@Follow
|
||||||
-- \`on\` (\\(people1 :& followers) ->
|
-- \`on\` (\\(people1 :& followers) ->
|
||||||
-- people1 ^. PersonId ==. followers ^. FollowFollowed)
|
-- people1 ^. PersonId ==. followers ^. FollowFollowed)
|
||||||
-- \`InnerJoin` Table \@Person
|
-- \`innerJoin` table \@Person
|
||||||
-- \`on\` (\\(_ :& followers :& people2) ->
|
-- \`on\` (\\(_ :& followers :& people2) ->
|
||||||
-- followers ^. FollowFollower ==. people2 ^. PersonId)
|
-- followers ^. FollowFollower ==. people2 ^. PersonId)
|
||||||
-- where_ (people1 ^. PersonName ==. val \"John\")
|
-- where_ (people1 ^. PersonName ==. val \"John\")
|
||||||
@ -420,8 +422,8 @@ import Database.Esqueleto.Experimental.ToMaybe
|
|||||||
-- peopleWithPosts <-
|
-- peopleWithPosts <-
|
||||||
-- from $ do
|
-- from $ do
|
||||||
-- (people :& blogPosts) <-
|
-- (people :& blogPosts) <-
|
||||||
-- from $ Table \@Person
|
-- from $ table \@Person
|
||||||
-- \`InnerJoin\` Table \@BlogPost
|
-- \`innerJoin\` table \@BlogPost
|
||||||
-- \`on\` (\\(p :& bP) ->
|
-- \`on\` (\\(p :& bP) ->
|
||||||
-- p ^. PersonId ==. bP ^. BlogPostAuthorId)
|
-- p ^. PersonId ==. bP ^. BlogPostAuthorId)
|
||||||
-- groupBy (people ^. PersonId)
|
-- groupBy (people ^. PersonId)
|
||||||
@ -451,8 +453,8 @@ import Database.Esqueleto.Experimental.ToMaybe
|
|||||||
-- (authors, blogPosts) <- from $
|
-- (authors, blogPosts) <- from $
|
||||||
-- (do
|
-- (do
|
||||||
-- (author :& blogPost) <-
|
-- (author :& blogPost) <-
|
||||||
-- from $ Table \@Person
|
-- from $ table \@Person
|
||||||
-- \`InnerJoin\` Table \@BlogPost
|
-- \`innerJoin\` table \@BlogPost
|
||||||
-- \`on\` (\\(a :& bP) ->
|
-- \`on\` (\\(a :& bP) ->
|
||||||
-- a ^. PersonId ==. bP ^. BlogPostAuthorId)
|
-- a ^. PersonId ==. bP ^. BlogPostAuthorId)
|
||||||
-- where_ (author ^. PersonId ==. val currentPersonId)
|
-- where_ (author ^. PersonId ==. val currentPersonId)
|
||||||
@ -461,11 +463,11 @@ import Database.Esqueleto.Experimental.ToMaybe
|
|||||||
-- \`union_\`
|
-- \`union_\`
|
||||||
-- (do
|
-- (do
|
||||||
-- (follow :& blogPost :& author) <-
|
-- (follow :& blogPost :& author) <-
|
||||||
-- from $ Table \@Follow
|
-- from $ table \@Follow
|
||||||
-- \`InnerJoin\` Table \@BlogPost
|
-- \`innerJoin\` table \@BlogPost
|
||||||
-- \`on\` (\\(f :& bP) ->
|
-- \`on\` (\\(f :& bP) ->
|
||||||
-- f ^. FollowFollowed ==. bP ^. BlogPostAuthorId)
|
-- f ^. FollowFollowed ==. bP ^. BlogPostAuthorId)
|
||||||
-- \`InnerJoin\` Table \@Person
|
-- \`innerJoin\` table \@Person
|
||||||
-- \`on\` (\\(_ :& bP :& a) ->
|
-- \`on\` (\\(_ :& bP :& a) ->
|
||||||
-- bP ^. BlogPostAuthorId ==. a ^. PersonId)
|
-- bP ^. BlogPostAuthorId ==. a ^. PersonId)
|
||||||
-- where_ (follow ^. FollowFollower ==. val currentPersonId)
|
-- where_ (follow ^. FollowFollower ==. val currentPersonId)
|
||||||
@ -484,14 +486,14 @@ import Database.Esqueleto.Experimental.ToMaybe
|
|||||||
-- @
|
-- @
|
||||||
-- select $ do
|
-- select $ do
|
||||||
-- (salesPerson :& maxSaleAmount :& maxSaleCustomerName) <-
|
-- (salesPerson :& maxSaleAmount :& maxSaleCustomerName) <-
|
||||||
-- from $ Table \@SalesPerson
|
-- from $ table \@SalesPerson
|
||||||
-- \`CrossJoin\` (\\salesPerson -> do
|
-- \`crossJoinLateral\` (\\salesPerson -> do
|
||||||
-- sales <- from $ Table \@Sale
|
-- sales <- from $ table \@Sale
|
||||||
-- where_ $ sales ^. SaleSalesPersonId ==. salesPerson ^. SalesPersonId
|
-- where_ $ sales ^. SaleSalesPersonId ==. salesPerson ^. SalesPersonId
|
||||||
-- pure $ max_ (sales ^. SaleAmount)
|
-- pure $ max_ (sales ^. SaleAmount)
|
||||||
-- )
|
-- )
|
||||||
-- \`CrossJoin\` (\\(salesPerson :& maxSaleAmount) -> do
|
-- \`crossJoinLateral\` (\\(salesPerson :& maxSaleAmount) -> do
|
||||||
-- sales <- from $ Table \@Sale
|
-- sales <- from $ table \@Sale
|
||||||
-- where_ $ sales ^. SaleSalesPersonId ==. salesPerson ^. SalesPersonId
|
-- where_ $ sales ^. SaleSalesPersonId ==. salesPerson ^. SalesPersonId
|
||||||
-- &&. sales ^. SaleAmount ==. maxSaleAmount
|
-- &&. sales ^. SaleAmount ==. maxSaleAmount
|
||||||
-- pure $ sales ^. SaleCustomerName)
|
-- pure $ sales ^. SaleCustomerName)
|
||||||
@ -539,12 +541,12 @@ import Database.Esqueleto.Experimental.ToMaybe
|
|||||||
-- @
|
-- @
|
||||||
-- select $ from $
|
-- select $ from $
|
||||||
-- (do
|
-- (do
|
||||||
-- a <- from Table @A
|
-- a <- from $ table @A
|
||||||
-- pure $ a ^. ASomeCol
|
-- pure $ a ^. ASomeCol
|
||||||
-- )
|
-- )
|
||||||
-- \`union_\`
|
-- \`union_\`
|
||||||
-- (do
|
-- (do
|
||||||
-- b <- from Table @B
|
-- b <- from $ table @B
|
||||||
-- pure $ b ^. BSomeCol
|
-- pure $ b ^. BSomeCol
|
||||||
-- )
|
-- )
|
||||||
-- @
|
-- @
|
||||||
|
|||||||
@ -30,11 +30,11 @@ import Database.Esqueleto.Internal.PersistentImport
|
|||||||
|
|
||||||
-- | 'FROM' clause, used to bring entities into scope.
|
-- | 'FROM' clause, used to bring entities into scope.
|
||||||
--
|
--
|
||||||
-- Internally, this function uses the `From` datatype and the
|
-- Internally, this function uses the `From` datatype.
|
||||||
-- `From` typeclass. Unlike the old `Database.Esqueleto.from`,
|
-- Unlike the old `Database.Esqueleto.from`, this does not
|
||||||
-- this does not take a function as a parameter, but rather
|
-- take a function as a parameter, but rather a value that
|
||||||
-- a value that represents a 'JOIN' tree constructed out of
|
-- represents a 'JOIN' tree constructed out of instances of `From`.
|
||||||
-- instances of `From`. This implementation eliminates certain
|
-- This implementation eliminates certain
|
||||||
-- types of runtime errors by preventing the construction of
|
-- types of runtime errors by preventing the construction of
|
||||||
-- invalid SQL (e.g. illegal nested-@from@).
|
-- invalid SQL (e.g. illegal nested-@from@).
|
||||||
from :: ToFrom a a' => a -> SqlQuery a'
|
from :: ToFrom a a' => a -> SqlQuery a'
|
||||||
@ -44,23 +44,44 @@ from f = do
|
|||||||
pure a
|
pure a
|
||||||
|
|
||||||
type RawFn = NeedParens -> IdentInfo -> (TLB.Builder, [PersistValue])
|
type RawFn = NeedParens -> IdentInfo -> (TLB.Builder, [PersistValue])
|
||||||
|
|
||||||
|
-- | Data type defining the "From" language. This should not
|
||||||
|
-- constructed directly in application code.
|
||||||
|
--
|
||||||
|
-- A @From@ is a SqlQuery which returns a reference to the result of calling from
|
||||||
|
-- and a function that produces a portion of a FROM clause. This gets passed to
|
||||||
|
-- the FromRaw FromClause constructor directly when converting
|
||||||
|
-- from a @From@ to a @SqlQuery@ using @from@
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
newtype From a = From
|
newtype From a = From
|
||||||
{ unFrom :: SqlQuery (a, RawFn)}
|
{ unFrom :: SqlQuery (a, RawFn)}
|
||||||
|
|
||||||
|
|
||||||
|
-- | A helper class primarily designed to allow using @SqlQuery@ directly in
|
||||||
|
-- a From expression. This is also useful for embedding a @SqlSetOperation@,
|
||||||
|
-- as well as supporting backwards compatibility for the
|
||||||
|
-- data constructor join tree used prior to /3.5.0.0/
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
class ToFrom a r | a -> r where
|
class ToFrom a r | a -> r where
|
||||||
toFrom :: a -> From r
|
toFrom :: a -> From r
|
||||||
instance ToFrom (From a) a where
|
instance ToFrom (From a) a where
|
||||||
toFrom = id
|
toFrom = id
|
||||||
|
|
||||||
-- | Data type for bringing a Table into scope in a JOIN tree
|
{-# DEPRECATED Table "/Since: 3.5.0.0/ - use 'table' instead" #-}
|
||||||
--
|
|
||||||
-- @
|
|
||||||
-- select $ from $ Table \@People
|
|
||||||
-- @
|
|
||||||
data Table a = Table
|
data Table a = Table
|
||||||
|
|
||||||
instance PersistEntity ent => ToFrom (Table ent) (SqlExpr (Entity ent)) where
|
instance PersistEntity ent => ToFrom (Table ent) (SqlExpr (Entity ent)) where
|
||||||
toFrom _ = table
|
toFrom _ = table
|
||||||
|
|
||||||
|
-- | Bring a PersistEntity into scope from a table
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- select $ from $ table \@People
|
||||||
|
-- @
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
table :: forall ent. PersistEntity ent => From (SqlExpr (Entity ent))
|
table :: forall ent. PersistEntity ent => From (SqlExpr (Entity ent))
|
||||||
table = From $ do
|
table = From $ do
|
||||||
let ed = entityDef (Proxy @ent)
|
let ed = entityDef (Proxy @ent)
|
||||||
@ -85,6 +106,21 @@ instance (SqlSelect a r, ToAlias a, ToAliasReference a) => ToFrom (SubQuery (Sql
|
|||||||
instance (SqlSelect a r, ToAlias a, ToAliasReference a) => ToFrom (SqlQuery a) a where
|
instance (SqlSelect a r, ToAlias a, ToAliasReference a) => ToFrom (SqlQuery a) a where
|
||||||
toFrom = selectQuery
|
toFrom = selectQuery
|
||||||
|
|
||||||
|
-- | Select from a subquery, often used in conjuction with joins but can be
|
||||||
|
-- used without any joins. Because @SqlQuery@ has a @ToFrom@ instance you probably
|
||||||
|
-- dont need to use this function directly.
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- select $
|
||||||
|
-- p <- from $
|
||||||
|
-- selectQuery do
|
||||||
|
-- p <- from $ table \@Person
|
||||||
|
-- limit 5
|
||||||
|
-- orderBy [ asc p ^. PersonAge ]
|
||||||
|
-- ...
|
||||||
|
-- @
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
selectQuery :: (SqlSelect a r, ToAlias a, ToAliasReference a) => SqlQuery a -> From a
|
selectQuery :: (SqlSelect a r, ToAlias a, ToAliasReference a) => SqlQuery a -> From a
|
||||||
selectQuery subquery = From $ do
|
selectQuery subquery = From $ do
|
||||||
-- We want to update the IdentState without writing the query to side data
|
-- We want to update the IdentState without writing the query to side data
|
||||||
|
|||||||
@ -56,21 +56,21 @@ with query = do
|
|||||||
-- @
|
-- @
|
||||||
-- select $ do
|
-- select $ do
|
||||||
-- cte <- withRecursive
|
-- cte <- withRecursive
|
||||||
-- (do $
|
-- (do
|
||||||
-- person <- from $ Table \@Person
|
-- person <- from $ table \@Person
|
||||||
-- where_ $ person ^. PersonId ==. val personId
|
-- where_ $ person ^. PersonId ==. val personId
|
||||||
-- pure person
|
-- pure person
|
||||||
-- )
|
-- )
|
||||||
-- unionAll_
|
-- unionAll_
|
||||||
-- (\\self -> do $
|
-- (\\self -> do
|
||||||
-- (p :& f :& p2 :& pSelf) <- from self
|
-- (p :& f :& p2 :& pSelf) <- from self
|
||||||
-- \`InnerJoin\` $ Table \@Follow
|
-- \`innerJoin\` $ table \@Follow
|
||||||
-- \`on\` (\\(p :& f) ->
|
-- \`on\` (\\(p :& f) ->
|
||||||
-- p ^. PersonId ==. f ^. FollowFollower)
|
-- p ^. PersonId ==. f ^. FollowFollower)
|
||||||
-- \`InnerJoin\` $ Table \@Person
|
-- \`innerJoin\` $ table \@Person
|
||||||
-- \`on\` (\\(p :& f :& p2) ->
|
-- \`on\` (\\(p :& f :& p2) ->
|
||||||
-- f ^. FollowFollowed ==. p2 ^. PersonId)
|
-- f ^. FollowFollowed ==. p2 ^. PersonId)
|
||||||
-- \`LeftOuterJoin\` self
|
-- \`leftJoin\` self
|
||||||
-- \`on\` (\\(_ :& _ :& p2 :& pSelf) ->
|
-- \`on\` (\\(_ :& _ :& p2 :& pSelf) ->
|
||||||
-- just (p2 ^. PersonId) ==. pSelf ?. PersonId)
|
-- just (p2 ^. PersonId) ==. pSelf ?. PersonId)
|
||||||
-- where_ $ isNothing (pSelf ?. PersonId)
|
-- where_ $ isNothing (pSelf ?. PersonId)
|
||||||
|
|||||||
@ -65,8 +65,8 @@ type family ValidOnClauseValue a :: Constraint where
|
|||||||
--
|
--
|
||||||
-- @
|
-- @
|
||||||
-- select $
|
-- select $
|
||||||
-- from $ Table \@Person
|
-- from $ table \@Person
|
||||||
-- \`InnerJoin\` Table \@BlogPost
|
-- \`innerJoin\` table \@BlogPost
|
||||||
-- \`on\` (\\(p :& bP) ->
|
-- \`on\` (\\(p :& bP) ->
|
||||||
-- p ^. PersonId ==. bP ^. BlogPostAuthorId)
|
-- p ^. PersonId ==. bP ^. BlogPostAuthorId)
|
||||||
-- @
|
-- @
|
||||||
@ -103,6 +103,19 @@ type family HasOnClause actual expected :: Constraint where
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
-- | INNER JOIN
|
||||||
|
--
|
||||||
|
-- Used as an infix operator \`innerJoin\`
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- select $
|
||||||
|
-- from $ table \@Person
|
||||||
|
-- \`innerJoin\` table \@BlogPost
|
||||||
|
-- \`on\` (\\(p :& bp) ->
|
||||||
|
-- p ^. PersonId ==. bp ^. BlogPostAuthorId)
|
||||||
|
-- @
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
innerJoin :: ( ToFrom a a'
|
innerJoin :: ( ToFrom a a'
|
||||||
, ToFrom b b'
|
, ToFrom b b'
|
||||||
, HasOnClause rhs (a' :& b')
|
, HasOnClause rhs (a' :& b')
|
||||||
@ -115,6 +128,16 @@ innerJoin lhs (rhs, on') = From $ do
|
|||||||
pure $ (ret, fromJoin " INNER JOIN " leftFrom rightFrom (Just $ on' ret))
|
pure $ (ret, fromJoin " INNER JOIN " leftFrom rightFrom (Just $ on' ret))
|
||||||
|
|
||||||
|
|
||||||
|
-- | INNER JOIN LATERAL
|
||||||
|
--
|
||||||
|
-- A Lateral subquery join allows the joined query to reference entities from the
|
||||||
|
-- left hand side of the join. Discards rows that don't match the on clause
|
||||||
|
--
|
||||||
|
-- Used as an infix operator \`innerJoinLateral\`
|
||||||
|
--
|
||||||
|
-- See example 6
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
innerJoinLateral :: ( ToFrom a a'
|
innerJoinLateral :: ( ToFrom a a'
|
||||||
, HasOnClause rhs (a' :& b)
|
, HasOnClause rhs (a' :& b)
|
||||||
, SqlSelect b r
|
, SqlSelect b r
|
||||||
@ -129,6 +152,17 @@ innerJoinLateral lhs (rhsFn, on') = From $ do
|
|||||||
let ret = leftVal :& rightVal
|
let ret = leftVal :& rightVal
|
||||||
pure $ (ret, fromJoin " INNER JOIN LATERAL " leftFrom rightFrom (Just $ on' ret))
|
pure $ (ret, fromJoin " INNER JOIN LATERAL " leftFrom rightFrom (Just $ on' ret))
|
||||||
|
|
||||||
|
-- | CROSS JOIN
|
||||||
|
--
|
||||||
|
-- Used as an infix \`crossJoin\`
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- select $ do
|
||||||
|
-- from $ table \@Person
|
||||||
|
-- \`crossJoin\` table \@BlogPost
|
||||||
|
-- @
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
crossJoin :: ( ToFrom a a'
|
crossJoin :: ( ToFrom a a'
|
||||||
, ToFrom b b'
|
, ToFrom b b'
|
||||||
) => a -> b -> From (a' :& b')
|
) => a -> b -> From (a' :& b')
|
||||||
@ -138,6 +172,16 @@ crossJoin lhs rhs = From $ do
|
|||||||
let ret = leftVal :& rightVal
|
let ret = leftVal :& rightVal
|
||||||
pure $ (ret, fromJoin " CROSS JOIN " leftFrom rightFrom Nothing)
|
pure $ (ret, fromJoin " CROSS JOIN " leftFrom rightFrom Nothing)
|
||||||
|
|
||||||
|
-- | CROSS JOIN LATERAL
|
||||||
|
--
|
||||||
|
-- A Lateral subquery join allows the joined query to reference entities from the
|
||||||
|
-- left hand side of the join.
|
||||||
|
--
|
||||||
|
-- Used as an infix operator \`crossJoinLateral\`
|
||||||
|
--
|
||||||
|
-- See example 6
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
crossJoinLateral :: ( ToFrom a a'
|
crossJoinLateral :: ( ToFrom a a'
|
||||||
, SqlSelect b r
|
, SqlSelect b r
|
||||||
, ToAlias b
|
, ToAlias b
|
||||||
@ -150,6 +194,23 @@ crossJoinLateral lhs rhsFn = From $ do
|
|||||||
let ret = leftVal :& rightVal
|
let ret = leftVal :& rightVal
|
||||||
pure $ (ret, fromJoin " CROSS JOIN LATERAL " leftFrom rightFrom Nothing)
|
pure $ (ret, fromJoin " CROSS JOIN LATERAL " leftFrom rightFrom Nothing)
|
||||||
|
|
||||||
|
-- | LEFT OUTER JOIN
|
||||||
|
--
|
||||||
|
-- Join where the right side may not exist.
|
||||||
|
-- If the on clause fails then the right side will be NULL'ed
|
||||||
|
-- Because of this the right side needs to be handled as a Maybe
|
||||||
|
--
|
||||||
|
-- Used as an infix operator \`leftJoin\`
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- select $
|
||||||
|
-- from $ table \@Person
|
||||||
|
-- \`leftJoin\` table \@BlogPost
|
||||||
|
-- \`on\` (\\(p :& bp) ->
|
||||||
|
-- p ^. PersonId ==. bp ?. BlogPostAuthorId)
|
||||||
|
-- @
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
leftJoin :: ( ToFrom a a'
|
leftJoin :: ( ToFrom a a'
|
||||||
, ToFrom b b'
|
, ToFrom b b'
|
||||||
, ToMaybe b'
|
, ToMaybe b'
|
||||||
@ -162,6 +223,18 @@ leftJoin lhs (rhs, on') = From $ do
|
|||||||
let ret = leftVal :& toMaybe rightVal
|
let ret = leftVal :& toMaybe rightVal
|
||||||
pure $ (ret, fromJoin " LEFT OUTER JOIN " leftFrom rightFrom (Just $ on' ret))
|
pure $ (ret, fromJoin " LEFT OUTER JOIN " leftFrom rightFrom (Just $ on' ret))
|
||||||
|
|
||||||
|
-- | LEFT OUTER JOIN LATERAL
|
||||||
|
--
|
||||||
|
-- Lateral join where the right side may not exist.
|
||||||
|
-- In the case that the query returns nothing or the on clause fails the right
|
||||||
|
-- side of the join will be NULL'ed
|
||||||
|
-- Because of this the right side needs to be handled as a Maybe
|
||||||
|
--
|
||||||
|
-- Used as an infix operator \`leftJoinLateral\`
|
||||||
|
--
|
||||||
|
-- See example 6 for how to use LATERAL
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
leftJoinLateral :: ( ToFrom a a'
|
leftJoinLateral :: ( ToFrom a a'
|
||||||
, SqlSelect b r
|
, SqlSelect b r
|
||||||
, HasOnClause rhs (a' :& ToMaybeT b)
|
, HasOnClause rhs (a' :& ToMaybeT b)
|
||||||
@ -177,6 +250,23 @@ leftJoinLateral lhs (rhsFn, on') = From $ do
|
|||||||
let ret = leftVal :& toMaybe rightVal
|
let ret = leftVal :& toMaybe rightVal
|
||||||
pure $ (ret, fromJoin " LEFT OUTER JOIN LATERAL " leftFrom rightFrom (Just $ on' ret))
|
pure $ (ret, fromJoin " LEFT OUTER JOIN LATERAL " leftFrom rightFrom (Just $ on' ret))
|
||||||
|
|
||||||
|
-- | RIGHT OUTER JOIN
|
||||||
|
--
|
||||||
|
-- Join where the left side may not exist.
|
||||||
|
-- If the on clause fails then the left side will be NULL'ed
|
||||||
|
-- Because of this the left side needs to be handled as a Maybe
|
||||||
|
--
|
||||||
|
-- Used as an infix operator \`rightJoin\`
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- select $
|
||||||
|
-- from $ table \@Person
|
||||||
|
-- \`rightJoin\` table \@BlogPost
|
||||||
|
-- \`on\` (\\(p :& bp) ->
|
||||||
|
-- p ?. PersonId ==. bp ^. BlogPostAuthorId)
|
||||||
|
-- @
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
rightJoin :: ( ToFrom a a'
|
rightJoin :: ( ToFrom a a'
|
||||||
, ToFrom b b'
|
, ToFrom b b'
|
||||||
, ToMaybe a'
|
, ToMaybe a'
|
||||||
@ -189,6 +279,22 @@ rightJoin lhs (rhs, on') = From $ do
|
|||||||
let ret = toMaybe leftVal :& rightVal
|
let ret = toMaybe leftVal :& rightVal
|
||||||
pure $ (ret, fromJoin " RIGHT OUTER JOIN " leftFrom rightFrom (Just $ on' ret))
|
pure $ (ret, fromJoin " RIGHT OUTER JOIN " leftFrom rightFrom (Just $ on' ret))
|
||||||
|
|
||||||
|
-- | FULL OUTER JOIN
|
||||||
|
--
|
||||||
|
-- Join where both sides of the join may not exist.
|
||||||
|
-- Because of this the result needs to be handled as a Maybe
|
||||||
|
--
|
||||||
|
-- Used as an infix operator \`fullOuterJoin\`
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- select $
|
||||||
|
-- from $ table \@Person
|
||||||
|
-- \`fullOuterJoin\` table \@BlogPost
|
||||||
|
-- \`on\` (\\(p :& bp) ->
|
||||||
|
-- p ?. PersonId ==. bp ?. BlogPostAuthorId)
|
||||||
|
-- @
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
fullOuterJoin :: ( ToFrom a a'
|
fullOuterJoin :: ( ToFrom a a'
|
||||||
, ToFrom b b'
|
, ToFrom b b'
|
||||||
, ToMaybe a'
|
, ToMaybe a'
|
||||||
|
|||||||
@ -24,6 +24,12 @@ import Database.Esqueleto.Internal.Internal hiding (From(..), from, on)
|
|||||||
import Database.Esqueleto.Internal.PersistentImport
|
import Database.Esqueleto.Internal.PersistentImport
|
||||||
(DBName(..), Entity, PersistEntity, PersistValue)
|
(DBName(..), Entity, PersistEntity, PersistValue)
|
||||||
|
|
||||||
|
-- | Data type used to implement the SqlSetOperation language
|
||||||
|
-- this type is implemented in the same way as a @From@
|
||||||
|
--
|
||||||
|
-- Semantically a @SqlSetOperation@ is always a @From@ but not vice versa
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
newtype SqlSetOperation a = SqlSetOperation
|
newtype SqlSetOperation a = SqlSetOperation
|
||||||
{ unSqlSetOperation :: NeedParens -> SqlQuery (a, IdentInfo -> (TLB.Builder, [PersistValue]))}
|
{ unSqlSetOperation :: NeedParens -> SqlQuery (a, IdentInfo -> (TLB.Builder, [PersistValue]))}
|
||||||
|
|
||||||
@ -34,6 +40,9 @@ instance ToAliasReference a => ToFrom (SqlSetOperation a) a where
|
|||||||
ref <- toAliasReference ident a
|
ref <- toAliasReference ident a
|
||||||
pure (ref, \_ info -> (first parens $ fromClause info) <> (" AS " <> useIdent info ident, mempty))
|
pure (ref, \_ info -> (first parens $ fromClause info) <> (" AS " <> useIdent info ident, mempty))
|
||||||
|
|
||||||
|
-- | Type class to support direct use of @SqlQuery@ in a set operation tree
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
class ToSqlSetOperation a r | a -> r where
|
class ToSqlSetOperation a r | a -> r where
|
||||||
toSqlSetOperation :: a -> SqlSetOperation r
|
toSqlSetOperation :: a -> SqlSetOperation r
|
||||||
instance ToSqlSetOperation (SqlSetOperation a) a where
|
instance ToSqlSetOperation (SqlSetOperation a) a where
|
||||||
@ -57,7 +66,10 @@ instance (SqlSelect a r, ToAlias a, ToAliasReference a) => ToSqlSetOperation (Sq
|
|||||||
Never
|
Never
|
||||||
pure (aliasedValue, \info -> first (parensM p') $ toRawSql SELECT info aliasedQuery)
|
pure (aliasedValue, \info -> first (parensM p') $ toRawSql SELECT info aliasedQuery)
|
||||||
|
|
||||||
mkSetOperation :: (ToSqlSetOperation a a', ToSqlSetOperation b a') => TLB.Builder -> a -> b -> SqlSetOperation a'
|
-- | Helper function for defining set operations
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
|
mkSetOperation :: (ToSqlSetOperation a a', ToSqlSetOperation b a')
|
||||||
|
=> TLB.Builder -> a -> b -> SqlSetOperation a'
|
||||||
mkSetOperation operation lhs rhs = SqlSetOperation $ \p -> do
|
mkSetOperation operation lhs rhs = SqlSetOperation $ \p -> do
|
||||||
(leftValue, leftClause) <- unSqlSetOperation (toSqlSetOperation lhs) p
|
(leftValue, leftClause) <- unSqlSetOperation (toSqlSetOperation lhs) p
|
||||||
(_, rightClause) <- unSqlSetOperation (toSqlSetOperation rhs) p
|
(_, rightClause) <- unSqlSetOperation (toSqlSetOperation rhs) p
|
||||||
@ -68,7 +80,10 @@ data Union a b = a `Union` b
|
|||||||
instance ToSqlSetOperation a a' => ToSqlSetOperation (Union a a) a' where
|
instance ToSqlSetOperation a a' => ToSqlSetOperation (Union a a) a' where
|
||||||
toSqlSetOperation (Union a b) = union_ a b
|
toSqlSetOperation (Union a b) = union_ a b
|
||||||
|
|
||||||
|
-- | Overloaded @union_@ function to support use in both 'SqlSetOperation'
|
||||||
|
-- and 'withRecursive'
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
class Union_ a where
|
class Union_ a where
|
||||||
-- | @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
|
union_ :: a
|
||||||
@ -77,6 +92,10 @@ instance (ToSqlSetOperation a c, ToSqlSetOperation b c, res ~ SqlSetOperation c)
|
|||||||
=> Union_ (a -> b -> res) where
|
=> Union_ (a -> b -> res) where
|
||||||
union_ = mkSetOperation " UNION "
|
union_ = mkSetOperation " UNION "
|
||||||
|
|
||||||
|
-- | Overloaded @unionAll_@ function to support use in both 'SqlSetOperation'
|
||||||
|
-- and 'withRecursive'
|
||||||
|
--
|
||||||
|
-- /Since: 3.5.0.0/
|
||||||
class UnionAll_ a where
|
class UnionAll_ a where
|
||||||
-- | @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
|
unionAll_ :: a
|
||||||
|
|||||||
@ -2035,6 +2035,8 @@ data SqlExprMeta = SqlExprMeta
|
|||||||
, sqlExprMetaIsReference :: Bool -- Is this SqlExpr a reference to the selected value/entity (supports subqueries)
|
, sqlExprMetaIsReference :: Bool -- Is this SqlExpr a reference to the selected value/entity (supports subqueries)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- | Empty 'SqlExprMeta' if you are constructing an 'ERaw' probably use this
|
||||||
|
-- for your meta
|
||||||
noMeta :: SqlExprMeta
|
noMeta :: SqlExprMeta
|
||||||
noMeta = SqlExprMeta
|
noMeta = SqlExprMeta
|
||||||
{ sqlExprMetaCompositeFields = Nothing
|
{ sqlExprMetaCompositeFields = Nothing
|
||||||
@ -2042,18 +2044,19 @@ noMeta = SqlExprMeta
|
|||||||
, sqlExprMetaIsReference = False
|
, sqlExprMetaIsReference = False
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- | Does this meta contain values for composite fields.
|
||||||
|
-- This field is field out for composite key values
|
||||||
hasCompositeKeyMeta :: SqlExprMeta -> Bool
|
hasCompositeKeyMeta :: SqlExprMeta -> Bool
|
||||||
hasCompositeKeyMeta = Maybe.isJust . sqlExprMetaCompositeFields
|
hasCompositeKeyMeta = Maybe.isJust . sqlExprMetaCompositeFields
|
||||||
|
|
||||||
-- | An expression on the SQL backend.
|
-- | An expression on the SQL backend.
|
||||||
--
|
--
|
||||||
-- There are many comments describing the constructors of this
|
-- Raw expression: Contains a 'SqlExprMeta' and a function for
|
||||||
-- data type. However, Haddock doesn't like GADTs, so you'll have to read them by hitting \"Source\".
|
-- building the expr. It recieves a parameter telling it whether
|
||||||
-- Raw expression: states whether parenthesis are needed
|
-- it is in a parenthesized context, and takes information about the SQL
|
||||||
-- around this expression, and takes information about the SQL
|
-- connection (mainly for escaping names) and returns both an
|
||||||
-- connection (mainly for escaping names) and returns both an
|
-- string ('TLB.Builder') and a list of values to be
|
||||||
-- string ('TLB.Builder') and a list of values to be
|
-- interpolated by the SQL backend.
|
||||||
-- interpolated by the SQL backend.
|
|
||||||
data SqlExpr a = ERaw SqlExprMeta (NeedParens -> IdentInfo -> (TLB.Builder, [PersistValue]))
|
data SqlExpr a = ERaw SqlExprMeta (NeedParens -> IdentInfo -> (TLB.Builder, [PersistValue]))
|
||||||
|
|
||||||
-- | Data type to support from hack
|
-- | Data type to support from hack
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user