{-# LANGUAGE BangPatterns, TypeFamilies, DataKinds, PolyKinds, TypeApplications, ScopedTypeVariables, ConstraintKinds, TypeOperators, GADTs, UndecidableInstances, StandaloneDeriving, FunctionalDependencies, FlexibleContexts, InstanceSigs, AllowAmbiguousTypes, DeriveAnyClass #-}
module IHP.QueryBuilder.Union
( queryUnion
, queryUnionList
, queryOr
) where
import IHP.Prelude
import IHP.ModelSupport
import IHP.QueryBuilder.Types
import IHP.QueryBuilder.Compiler (query)
queryUnion :: QueryBuilder model -> QueryBuilder model -> QueryBuilder model
queryUnion :: forall (model :: Symbol).
QueryBuilder model -> QueryBuilder model -> QueryBuilder model
queryUnion (QueryBuilder SQLQuery
first) (QueryBuilder SQLQuery
second) =
let isSimple :: SQLQuery -> Bool
isSimple SQLQuery
q = [OrderByClause] -> Bool
forall mono. MonoFoldable mono => mono -> Bool
null (SQLQuery -> [OrderByClause]
orderByClause SQLQuery
q) Bool -> Bool -> Bool
&& Maybe Int -> Bool
forall a. Maybe a -> Bool
isNothing (SQLQuery -> Maybe Int
limitClause SQLQuery
q) Bool -> Bool -> Bool
&& Maybe Int -> Bool
forall a. Maybe a -> Bool
isNothing (SQLQuery -> Maybe Int
offsetClause SQLQuery
q)
unionWhere :: Maybe Condition
unionWhere = case (SQLQuery -> Maybe Condition
whereCondition SQLQuery
first, SQLQuery -> Maybe Condition
whereCondition SQLQuery
second) of
(Maybe Condition
Nothing, Maybe Condition
wc) -> Maybe Condition
wc
(Maybe Condition
wc, Maybe Condition
Nothing) -> Maybe Condition
wc
(Just Condition
a, Just Condition
b) -> Condition -> Maybe Condition
forall a. a -> Maybe a
Just (Condition -> Condition -> Condition
OrCondition Condition
a Condition
b)
in if SQLQuery -> Bool
isSimple SQLQuery
first Bool -> Bool -> Bool
&& SQLQuery -> Bool
isSimple SQLQuery
second
then SQLQuery -> QueryBuilder model
forall (table :: Symbol). SQLQuery -> QueryBuilder table
QueryBuilder SQLQuery
first { whereCondition = unionWhere }
else Text -> QueryBuilder model
forall a. Text -> a
error Text
"queryUnion: Union of complex queries (with ORDER BY, LIMIT, or OFFSET) not supported"
{-# INLINE queryUnion #-}
queryUnionList :: forall table. (Table (GetModelByTableName table), KnownSymbol table, GetTableName (GetModelByTableName table) ~ table) => [QueryBuilder table] -> QueryBuilder table
queryUnionList :: forall (table :: Symbol).
(Table (GetModelByTableName table), KnownSymbol table,
GetTableName (GetModelByTableName table) ~ table) =>
[QueryBuilder table] -> QueryBuilder table
queryUnionList [] = Condition -> QueryBuilder table -> QueryBuilder table
forall (table :: Symbol).
Condition -> QueryBuilder table -> QueryBuilder table
addCondition (Text
-> FilterOperator
-> ConditionValue
-> Maybe Text
-> Maybe Text
-> Condition
ColumnCondition Text
"id" FilterOperator
NotEqOp (Text -> ConditionValue
Literal Text
"id") Maybe Text
forall a. Maybe a
Nothing Maybe Text
forall a. Maybe a
Nothing) (forall model (table :: Symbol).
(table ~ GetTableName model, Table model, DefaultScope table) =>
QueryBuilder table
query @(GetModelByTableName table) @table)
queryUnionList [QueryBuilder table
single] = QueryBuilder table
single
queryUnionList (QueryBuilder table
first:[QueryBuilder table]
rest) =
let QueryBuilder SQLQuery
firstSq = QueryBuilder table
first
QueryBuilder SQLQuery
restSq = forall (table :: Symbol).
(Table (GetModelByTableName table), KnownSymbol table,
GetTableName (GetModelByTableName table) ~ table) =>
[QueryBuilder table] -> QueryBuilder table
queryUnionList @table [QueryBuilder table]
rest
isSimple :: SQLQuery -> Bool
isSimple SQLQuery
q = [OrderByClause] -> Bool
forall mono. MonoFoldable mono => mono -> Bool
null (SQLQuery -> [OrderByClause]
orderByClause SQLQuery
q) Bool -> Bool -> Bool
&& Maybe Int -> Bool
forall a. Maybe a -> Bool
isNothing (SQLQuery -> Maybe Int
limitClause SQLQuery
q) Bool -> Bool -> Bool
&& Maybe Int -> Bool
forall a. Maybe a -> Bool
isNothing (SQLQuery -> Maybe Int
offsetClause SQLQuery
q)
unionWhere :: Maybe Condition
unionWhere = case (SQLQuery -> Maybe Condition
whereCondition SQLQuery
firstSq, SQLQuery -> Maybe Condition
whereCondition SQLQuery
restSq) of
(Maybe Condition
Nothing, Maybe Condition
wc) -> Maybe Condition
wc
(Maybe Condition
wc, Maybe Condition
Nothing) -> Maybe Condition
wc
(Just Condition
a, Just Condition
b) -> Condition -> Maybe Condition
forall a. a -> Maybe a
Just (Condition -> Condition -> Condition
OrCondition Condition
a Condition
b)
in if SQLQuery -> Bool
isSimple SQLQuery
firstSq Bool -> Bool -> Bool
&& SQLQuery -> Bool
isSimple SQLQuery
restSq
then SQLQuery -> QueryBuilder table
forall (table :: Symbol). SQLQuery -> QueryBuilder table
QueryBuilder SQLQuery
firstSq { whereCondition = unionWhere }
else Text -> QueryBuilder table
forall a. Text -> a
error Text
"queryUnionList: Union of complex queries (with ORDER BY, LIMIT, or OFFSET) not supported"
queryOr :: (QueryBuilder model -> QueryBuilder model) -> (QueryBuilder model -> QueryBuilder model) -> QueryBuilder model -> QueryBuilder model
queryOr :: forall (model :: Symbol).
(QueryBuilder model -> QueryBuilder model)
-> (QueryBuilder model -> QueryBuilder model)
-> QueryBuilder model
-> QueryBuilder model
queryOr QueryBuilder model -> QueryBuilder model
firstQuery QueryBuilder model -> QueryBuilder model
secondQuery QueryBuilder model
queryBuilder =
let QueryBuilder SQLQuery
firstSq = QueryBuilder model -> QueryBuilder model
firstQuery QueryBuilder model
queryBuilder
QueryBuilder SQLQuery
secondSq = QueryBuilder model -> QueryBuilder model
secondQuery QueryBuilder model
queryBuilder
unionWhere :: Maybe Condition
unionWhere = case (SQLQuery -> Maybe Condition
whereCondition SQLQuery
firstSq, SQLQuery -> Maybe Condition
whereCondition SQLQuery
secondSq) of
(Maybe Condition
Nothing, Maybe Condition
wc) -> Maybe Condition
wc
(Maybe Condition
wc, Maybe Condition
Nothing) -> Maybe Condition
wc
(Just Condition
a, Just Condition
b) -> Condition -> Maybe Condition
forall a. a -> Maybe a
Just (Condition -> Condition -> Condition
OrCondition Condition
a Condition
b)
QueryBuilder SQLQuery
baseSq = QueryBuilder model
queryBuilder
in SQLQuery -> QueryBuilder model
forall (table :: Symbol). SQLQuery -> QueryBuilder table
QueryBuilder SQLQuery
baseSq { whereCondition = unionWhere }
{-# INLINE queryOr #-}