Remove EOrderBy, EDistinctOn; Change PreprocessedFrom a to just be an independent datatype
This commit is contained in:
parent
f77134e788
commit
2da0526b90
@ -84,35 +84,35 @@ fromStart
|
|||||||
( PersistEntity a
|
( PersistEntity a
|
||||||
, BackendCompatible SqlBackend (PersistEntityBackend a)
|
, BackendCompatible SqlBackend (PersistEntityBackend a)
|
||||||
)
|
)
|
||||||
=> SqlQuery (SqlExpr (PreprocessedFrom (SqlExpr (Entity a))))
|
=> SqlQuery (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 (entityDB ed)
|
||||||
let ret = unsafeSqlEntity ident
|
let ret = unsafeSqlEntity ident
|
||||||
f' = FromStart ident ed
|
f' = FromStart ident ed
|
||||||
return (EPreprocessedFrom ret f')
|
return (PreprocessedFrom ret f')
|
||||||
|
|
||||||
-- | (Internal) Same as 'fromStart', but entity may be missing.
|
-- | (Internal) Same as 'fromStart', but entity may be missing.
|
||||||
fromStartMaybe
|
fromStartMaybe
|
||||||
:: ( PersistEntity a
|
:: ( PersistEntity a
|
||||||
, BackendCompatible SqlBackend (PersistEntityBackend a)
|
, BackendCompatible SqlBackend (PersistEntityBackend a)
|
||||||
)
|
)
|
||||||
=> SqlQuery (SqlExpr (PreprocessedFrom (SqlExpr (Maybe (Entity a)))))
|
=> SqlQuery (PreprocessedFrom (SqlExpr (Maybe (Entity a))))
|
||||||
fromStartMaybe = maybelize <$> fromStart
|
fromStartMaybe = maybelize <$> fromStart
|
||||||
where
|
where
|
||||||
maybelize
|
maybelize
|
||||||
:: SqlExpr (PreprocessedFrom (SqlExpr (Entity a)))
|
:: PreprocessedFrom (SqlExpr (Entity a))
|
||||||
-> SqlExpr (PreprocessedFrom (SqlExpr (Maybe (Entity a))))
|
-> PreprocessedFrom (SqlExpr (Maybe (Entity a)))
|
||||||
maybelize (EPreprocessedFrom (ERaw m f) f') = EPreprocessedFrom (ERaw m f) f'
|
maybelize (PreprocessedFrom (ERaw m f) f') = PreprocessedFrom (ERaw m f) f'
|
||||||
|
|
||||||
-- | (Internal) Do a @JOIN@.
|
-- | (Internal) Do a @JOIN@.
|
||||||
fromJoin
|
fromJoin
|
||||||
:: IsJoinKind join
|
:: IsJoinKind join
|
||||||
=> SqlExpr (PreprocessedFrom a)
|
=> PreprocessedFrom a
|
||||||
-> SqlExpr (PreprocessedFrom b)
|
-> PreprocessedFrom b
|
||||||
-> SqlQuery (SqlExpr (PreprocessedFrom (join a b)))
|
-> SqlQuery (PreprocessedFrom (join a b))
|
||||||
fromJoin (EPreprocessedFrom lhsRet lhsFrom)
|
fromJoin (PreprocessedFrom lhsRet lhsFrom)
|
||||||
(EPreprocessedFrom rhsRet rhsFrom) = Q $ do
|
(PreprocessedFrom rhsRet rhsFrom) = Q $ do
|
||||||
let ret = smartJoin lhsRet rhsRet
|
let ret = smartJoin lhsRet rhsRet
|
||||||
from' =
|
from' =
|
||||||
FromJoin
|
FromJoin
|
||||||
@ -120,13 +120,13 @@ fromJoin (EPreprocessedFrom lhsRet lhsFrom)
|
|||||||
(reifyJoinKind ret) -- JOIN
|
(reifyJoinKind ret) -- JOIN
|
||||||
rhsFrom -- RHS
|
rhsFrom -- RHS
|
||||||
Nothing -- ON
|
Nothing -- ON
|
||||||
return (EPreprocessedFrom ret from')
|
return (PreprocessedFrom ret from')
|
||||||
|
|
||||||
-- | (Internal) Finish a @JOIN@.
|
-- | (Internal) Finish a @JOIN@.
|
||||||
fromFinish
|
fromFinish
|
||||||
:: SqlExpr (PreprocessedFrom a)
|
:: PreprocessedFrom a
|
||||||
-> SqlQuery a
|
-> SqlQuery a
|
||||||
fromFinish (EPreprocessedFrom ret f') = Q $ do
|
fromFinish (PreprocessedFrom ret f') = Q $ do
|
||||||
W.tell mempty { sdFromClause = [f'] }
|
W.tell mempty { sdFromClause = [f'] }
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@ -250,11 +250,22 @@ orderBy exprs = Q $ W.tell mempty { sdOrderByClause = exprs }
|
|||||||
|
|
||||||
-- | Ascending order of this field or SqlExpression.
|
-- | Ascending order of this field or SqlExpression.
|
||||||
asc :: PersistField a => SqlExpr (Value a) -> SqlExpr OrderBy
|
asc :: PersistField a => SqlExpr (Value a) -> SqlExpr OrderBy
|
||||||
asc = EOrderBy ASC
|
asc = orderByExpr " ASC"
|
||||||
|
|
||||||
-- | Descending order of this field or SqlExpression.
|
-- | Descending order of this field or SqlExpression.
|
||||||
desc :: PersistField a => SqlExpr (Value a) -> SqlExpr OrderBy
|
desc :: PersistField a => SqlExpr (Value a) -> SqlExpr OrderBy
|
||||||
desc = EOrderBy DESC
|
desc = orderByExpr " DESC"
|
||||||
|
|
||||||
|
orderByExpr :: TLB.Builder -> SqlExpr (Value a) -> SqlExpr OrderBy
|
||||||
|
orderByExpr orderByType (ERaw m f)
|
||||||
|
| Just fields <- sqlExprMetaCompositeFields m =
|
||||||
|
ERaw noMeta $ \_ info ->
|
||||||
|
let fs = fields info
|
||||||
|
vals = repeat []
|
||||||
|
in uncommas' $ zip (map (<> orderByType) fs) vals
|
||||||
|
| otherwise =
|
||||||
|
ERaw noMeta $ \_ info ->
|
||||||
|
first (<> orderByType) $ f Never info
|
||||||
|
|
||||||
-- | @LIMIT@. Limit the number of returned rows.
|
-- | @LIMIT@. Limit the number of returned rows.
|
||||||
limit :: Int64 -> SqlQuery ()
|
limit :: Int64 -> SqlQuery ()
|
||||||
@ -326,7 +337,7 @@ distinctOn exprs act = Q (W.tell mempty { sdDistinctClause = DistinctOn exprs })
|
|||||||
--
|
--
|
||||||
-- @since 2.2.4
|
-- @since 2.2.4
|
||||||
don :: SqlExpr (Value a) -> SqlExpr DistinctOn
|
don :: SqlExpr (Value a) -> SqlExpr DistinctOn
|
||||||
don = EDistinctOn
|
don (ERaw m f) = ERaw m f
|
||||||
|
|
||||||
-- | A convenience function that calls both 'distinctOn' and
|
-- | A convenience function that calls both 'distinctOn' and
|
||||||
-- 'orderBy'. In other words,
|
-- 'orderBy'. In other words,
|
||||||
@ -352,7 +363,7 @@ distinctOnOrderBy exprs act =
|
|||||||
act
|
act
|
||||||
where
|
where
|
||||||
toDistinctOn :: SqlExpr OrderBy -> SqlExpr DistinctOn
|
toDistinctOn :: SqlExpr OrderBy -> SqlExpr DistinctOn
|
||||||
toDistinctOn (EOrderBy _ f) = EDistinctOn f
|
toDistinctOn (ERaw m f) = ERaw m f
|
||||||
toDistinctOn EOrderRandom =
|
toDistinctOn EOrderRandom =
|
||||||
error "We can't select distinct by a random order!"
|
error "We can't select distinct by a random order!"
|
||||||
|
|
||||||
@ -1362,9 +1373,6 @@ data OnClauseWithoutMatchingJoinException =
|
|||||||
|
|
||||||
instance Exception OnClauseWithoutMatchingJoinException
|
instance Exception OnClauseWithoutMatchingJoinException
|
||||||
|
|
||||||
-- | (Internal) Phantom type used to process 'from' (see 'fromStart').
|
|
||||||
data PreprocessedFrom a
|
|
||||||
|
|
||||||
-- | Phantom type used by 'orderBy', 'asc' and 'desc'.
|
-- | Phantom type used by 'orderBy', 'asc' and 'desc'.
|
||||||
data OrderBy
|
data OrderBy
|
||||||
|
|
||||||
@ -1606,7 +1614,7 @@ instance
|
|||||||
-- | (Internal) Class that implements the @JOIN@ 'from' magic
|
-- | (Internal) Class that implements the @JOIN@ 'from' magic
|
||||||
-- (see 'fromStart').
|
-- (see 'fromStart').
|
||||||
class FromPreprocess a where
|
class FromPreprocess a where
|
||||||
fromPreprocess :: SqlQuery (SqlExpr (PreprocessedFrom a))
|
fromPreprocess :: SqlQuery (PreprocessedFrom a)
|
||||||
|
|
||||||
instance
|
instance
|
||||||
(PersistEntity val, BackendCompatible SqlBackend (PersistEntityBackend val))
|
(PersistEntity val, BackendCompatible SqlBackend (PersistEntityBackend val))
|
||||||
@ -1996,7 +2004,47 @@ useIdent :: IdentInfo -> Ident -> TLB.Builder
|
|||||||
useIdent info (I ident) = fromDBName info $ DBName ident
|
useIdent info (I ident) = fromDBName info $ DBName ident
|
||||||
|
|
||||||
data SqlExprMeta = SqlExprMeta
|
data SqlExprMeta = SqlExprMeta
|
||||||
{ sqlExprMetaCompositeFields :: Maybe (IdentInfo -> [TLB.Builder])
|
{ -- A composite key.
|
||||||
|
--
|
||||||
|
-- Persistent uses the same 'PersistList' constructor for both
|
||||||
|
-- fields which are (homogeneous) lists of values and the
|
||||||
|
-- (probably heterogeneous) values of a composite primary key.
|
||||||
|
--
|
||||||
|
-- We need to treat composite keys as fields. For example, we
|
||||||
|
-- have to support using ==., otherwise you wouldn't be able to
|
||||||
|
-- join. OTOH, lists of values should be treated exactly the
|
||||||
|
-- same as any other scalar value.
|
||||||
|
--
|
||||||
|
-- In particular, this is valid for persistent via rawSql for
|
||||||
|
-- an F field that is a list:
|
||||||
|
--
|
||||||
|
-- A.F in ? -- [PersistList [foo, bar]]
|
||||||
|
--
|
||||||
|
-- However, this is not for a composite key entity:
|
||||||
|
--
|
||||||
|
-- A.ID = ? -- [PersistList [foo, bar]]
|
||||||
|
--
|
||||||
|
-- The ID field doesn't exist on the DB for a composite key
|
||||||
|
-- table, it exists only on the Haskell side. Those variations
|
||||||
|
-- also don't work:
|
||||||
|
--
|
||||||
|
-- (A.KeyA, A.KeyB) = ? -- [PersistList [foo, bar]]
|
||||||
|
-- [A.KeyA, A.KeyB] = ? -- [PersistList [foo, bar]]
|
||||||
|
--
|
||||||
|
-- We have to generate:
|
||||||
|
--
|
||||||
|
-- A.KeyA = ? AND A.KeyB = ? -- [foo, bar]
|
||||||
|
--
|
||||||
|
-- Note that the PersistList had to be deconstructed into its
|
||||||
|
-- components.
|
||||||
|
--
|
||||||
|
-- In order to disambiguate behaviors, this constructor is used
|
||||||
|
-- /only/ to represent a composite field access. It does not
|
||||||
|
-- represent a 'PersistList', not even if the 'PersistList' is
|
||||||
|
-- used in the context of a composite key. That's because it's
|
||||||
|
-- impossible, e.g., for 'val' to disambiguate between these
|
||||||
|
-- uses.
|
||||||
|
sqlExprMetaCompositeFields :: Maybe (IdentInfo -> [TLB.Builder])
|
||||||
, sqlExprMetaAlias :: Maybe Ident
|
, sqlExprMetaAlias :: Maybe Ident
|
||||||
, sqlExprMetaIsReference :: Bool
|
, sqlExprMetaIsReference :: Bool
|
||||||
}
|
}
|
||||||
@ -2023,65 +2071,17 @@ data SqlExpr a where
|
|||||||
-- interpolated by the SQL backend.
|
-- interpolated by the SQL backend.
|
||||||
ERaw :: SqlExprMeta -> (NeedParens -> IdentInfo -> (TLB.Builder, [PersistValue])) -> SqlExpr a
|
ERaw :: SqlExprMeta -> (NeedParens -> IdentInfo -> (TLB.Builder, [PersistValue])) -> SqlExpr a
|
||||||
|
|
||||||
-- A composite key.
|
|
||||||
--
|
|
||||||
-- Persistent uses the same 'PersistList' constructor for both
|
|
||||||
-- fields which are (homogeneous) lists of values and the
|
|
||||||
-- (probably heterogeneous) values of a composite primary key.
|
|
||||||
--
|
|
||||||
-- We need to treat composite keys as fields. For example, we
|
|
||||||
-- have to support using ==., otherwise you wouldn't be able to
|
|
||||||
-- join. OTOH, lists of values should be treated exactly the
|
|
||||||
-- same as any other scalar value.
|
|
||||||
--
|
|
||||||
-- In particular, this is valid for persistent via rawSql for
|
|
||||||
-- an F field that is a list:
|
|
||||||
--
|
|
||||||
-- A.F in ? -- [PersistList [foo, bar]]
|
|
||||||
--
|
|
||||||
-- However, this is not for a composite key entity:
|
|
||||||
--
|
|
||||||
-- A.ID = ? -- [PersistList [foo, bar]]
|
|
||||||
--
|
|
||||||
-- The ID field doesn't exist on the DB for a composite key
|
|
||||||
-- table, it exists only on the Haskell side. Those variations
|
|
||||||
-- also don't work:
|
|
||||||
--
|
|
||||||
-- (A.KeyA, A.KeyB) = ? -- [PersistList [foo, bar]]
|
|
||||||
-- [A.KeyA, A.KeyB] = ? -- [PersistList [foo, bar]]
|
|
||||||
--
|
|
||||||
-- We have to generate:
|
|
||||||
--
|
|
||||||
-- A.KeyA = ? AND A.KeyB = ? -- [foo, bar]
|
|
||||||
--
|
|
||||||
-- Note that the PersistList had to be deconstructed into its
|
|
||||||
-- components.
|
|
||||||
--
|
|
||||||
-- In order to disambiguate behaviors, this constructor is used
|
|
||||||
-- /only/ to represent a composite field access. It does not
|
|
||||||
-- represent a 'PersistList', not even if the 'PersistList' is
|
|
||||||
-- used in the context of a composite key. That's because it's
|
|
||||||
-- impossible, e.g., for 'val' to disambiguate between these
|
|
||||||
-- uses.
|
|
||||||
|
|
||||||
-- A 'SqlExpr' accepted only by 'orderBy'.
|
|
||||||
EOrderBy :: OrderByType -> SqlExpr (Value a) -> SqlExpr OrderBy
|
|
||||||
|
|
||||||
EOrderRandom :: SqlExpr OrderBy
|
EOrderRandom :: SqlExpr OrderBy
|
||||||
|
|
||||||
-- A 'SqlExpr' accepted only by 'distinctOn'.
|
|
||||||
EDistinctOn :: SqlExpr (Value a) -> SqlExpr DistinctOn
|
|
||||||
|
|
||||||
-- A 'SqlExpr' accepted only by 'set'.
|
-- A 'SqlExpr' accepted only by 'set'.
|
||||||
ESet :: (SqlExpr (Entity val) -> SqlExpr (Value ())) -> SqlExpr (Update val)
|
ESet :: (SqlExpr (Entity val) -> SqlExpr (Value ())) -> SqlExpr (Update val)
|
||||||
|
|
||||||
-- An internal 'SqlExpr' used by the 'from' hack.
|
|
||||||
EPreprocessedFrom :: a -> FromClause -> SqlExpr (PreprocessedFrom a)
|
|
||||||
|
|
||||||
-- Used by 'insertSelect'.
|
-- Used by 'insertSelect'.
|
||||||
EInsert :: Proxy a -> (IdentInfo -> (TLB.Builder, [PersistValue])) -> SqlExpr (Insertion a)
|
EInsert :: Proxy a -> (IdentInfo -> (TLB.Builder, [PersistValue])) -> SqlExpr (Insertion a)
|
||||||
EInsertFinal :: PersistEntity a => SqlExpr (Insertion a) -> SqlExpr InsertFinal
|
EInsertFinal :: PersistEntity a => SqlExpr (Insertion a) -> SqlExpr InsertFinal
|
||||||
|
|
||||||
|
data PreprocessedFrom a = PreprocessedFrom a FromClause
|
||||||
|
|
||||||
-- | Phantom type used to mark a @INSERT INTO@ query.
|
-- | Phantom type used to mark a @INSERT INTO@ query.
|
||||||
data InsertFinal
|
data InsertFinal
|
||||||
|
|
||||||
@ -2812,7 +2812,7 @@ makeSelect info mode_ distinctClause ret = process mode_
|
|||||||
first (("SELECT DISTINCT ON (" <>) . (<> ") "))
|
first (("SELECT DISTINCT ON (" <>) . (<> ") "))
|
||||||
$ uncommas' (processExpr <$> exprs)
|
$ uncommas' (processExpr <$> exprs)
|
||||||
where
|
where
|
||||||
processExpr (EDistinctOn f) = materializeExpr info f
|
processExpr (ERaw m f) = materializeExpr info (ERaw m f :: SqlExpr (Value a))
|
||||||
withCols v = v <> sqlSelectCols info ret
|
withCols v = v <> sqlSelectCols info ret
|
||||||
plain v = (v, [])
|
plain v = (v, [])
|
||||||
|
|
||||||
@ -2908,16 +2908,7 @@ makeOrderByNoNewline _ [] = mempty
|
|||||||
makeOrderByNoNewline info os = first ("ORDER BY " <>) . uncommas' $ concatMap mk os
|
makeOrderByNoNewline info os = first ("ORDER BY " <>) . uncommas' $ concatMap mk os
|
||||||
where
|
where
|
||||||
mk :: OrderByClause -> [(TLB.Builder, [PersistValue])]
|
mk :: OrderByClause -> [(TLB.Builder, [PersistValue])]
|
||||||
mk (EOrderBy t v)
|
mk (ERaw _ f) = [f Never info]
|
||||||
| ERaw m _ <- v, Just f <- sqlExprMetaCompositeFields m =
|
|
||||||
let fs = f info
|
|
||||||
vals = repeat []
|
|
||||||
in zip (map (<> orderByType t) fs) vals
|
|
||||||
| otherwise =
|
|
||||||
let x =
|
|
||||||
case v of
|
|
||||||
ERaw _ f -> f Never
|
|
||||||
in [ first (<> orderByType t) $ x info ]
|
|
||||||
mk EOrderRandom = [first (<> "RANDOM()") mempty]
|
mk EOrderRandom = [first (<> "RANDOM()") mempty]
|
||||||
|
|
||||||
orderByType ASC = " ASC"
|
orderByType ASC = " ASC"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user