mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 09:22:43 +03:00
server/postgres: support computed fields in order by
https://github.com/hasura/graphql-engine-mono/pull/1793 GitOrigin-RevId: e0396c0d4d96fc8f9bdbd7567193933db5b295a6
This commit is contained in:
parent
e4155e4c5b
commit
5cfac6ea87
@ -3,6 +3,7 @@
|
|||||||
## Next release
|
## Next release
|
||||||
(Add entries below in the order of server, console, cli, docs, others)
|
(Add entries below in the order of server, console, cli, docs, others)
|
||||||
|
|
||||||
|
- server: support computed fields in query 'order_by' (close #7103)
|
||||||
- server: log warning if there are errors while executing clean up actions after "drop source" (previously it would throw an error)
|
- server: log warning if there are errors while executing clean up actions after "drop source" (previously it would throw an error)
|
||||||
- server: Fixed a bug where MSSQL and BigQuery would ignore environment variables set from the console
|
- server: Fixed a bug where MSSQL and BigQuery would ignore environment variables set from the console
|
||||||
- server: Fixing bug in ReplaceMetadata parser - Moving from Alternative to committed-choice.
|
- server: Fixing bug in ReplaceMetadata parser - Moving from Alternative to committed-choice.
|
||||||
|
@ -403,7 +403,7 @@ fromSelectArgsG selectArgsG = do
|
|||||||
Nothing -> pure Proxy
|
Nothing -> pure Proxy
|
||||||
Just {} -> refute (pure DistinctIsn'tSupported)
|
Just {} -> refute (pure DistinctIsn'tSupported)
|
||||||
(argsOrderBy, joins) <-
|
(argsOrderBy, joins) <-
|
||||||
runWriterT (traverse fromAnnOrderByItemG (maybe [] toList orders))
|
runWriterT (traverse fromAnnotatedOrderByItemG (maybe [] toList orders))
|
||||||
-- Any object-relation joins that we generated, we record their
|
-- Any object-relation joins that we generated, we record their
|
||||||
-- generated names into a mapping.
|
-- generated names into a mapping.
|
||||||
let argsExistingJoins =
|
let argsExistingJoins =
|
||||||
@ -424,10 +424,10 @@ fromSelectArgsG selectArgsG = do
|
|||||||
|
|
||||||
-- | Produce a valid ORDER BY construct, telling about any joins
|
-- | Produce a valid ORDER BY construct, telling about any joins
|
||||||
-- needed on the side.
|
-- needed on the side.
|
||||||
fromAnnOrderByItemG ::
|
fromAnnotatedOrderByItemG ::
|
||||||
Ir.AnnOrderByItemG 'BigQuery Expression -> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) OrderBy
|
Ir.AnnotatedOrderByItemG 'BigQuery Expression -> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) OrderBy
|
||||||
fromAnnOrderByItemG Ir.OrderByItemG {obiType, obiColumn, obiNulls} = do
|
fromAnnotatedOrderByItemG Ir.OrderByItemG {obiType, obiColumn, obiNulls} = do
|
||||||
orderByFieldName <- unfurlAnnOrderByElement obiColumn
|
orderByFieldName <- unfurlAnnotatedOrderByElement obiColumn
|
||||||
let morderByOrder =
|
let morderByOrder =
|
||||||
obiType
|
obiType
|
||||||
let orderByNullsOrder =
|
let orderByNullsOrder =
|
||||||
@ -439,9 +439,9 @@ fromAnnOrderByItemG Ir.OrderByItemG {obiType, obiColumn, obiNulls} = do
|
|||||||
-- | Unfurl the nested set of object relations (tell'd in the writer)
|
-- | Unfurl the nested set of object relations (tell'd in the writer)
|
||||||
-- that are terminated by field name (Ir.AOCColumn and
|
-- that are terminated by field name (Ir.AOCColumn and
|
||||||
-- Ir.AOCArrayAggregation).
|
-- Ir.AOCArrayAggregation).
|
||||||
unfurlAnnOrderByElement ::
|
unfurlAnnotatedOrderByElement ::
|
||||||
Ir.AnnOrderByElement 'BigQuery Expression -> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) FieldName
|
Ir.AnnotatedOrderByElement 'BigQuery Expression -> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) FieldName
|
||||||
unfurlAnnOrderByElement =
|
unfurlAnnotatedOrderByElement =
|
||||||
\case
|
\case
|
||||||
Ir.AOCColumn pgColumnInfo -> lift (fromPGColumnInfo pgColumnInfo)
|
Ir.AOCColumn pgColumnInfo -> lift (fromPGColumnInfo pgColumnInfo)
|
||||||
Ir.AOCObjectRelation Rql.RelInfo {riMapping = mapping, riRTable = tableName} annBoolExp annOrderByElementG -> do
|
Ir.AOCObjectRelation Rql.RelInfo {riMapping = mapping, riRTable = tableName} annBoolExp annOrderByElementG -> do
|
||||||
@ -477,7 +477,7 @@ unfurlAnnOrderByElement =
|
|||||||
}
|
}
|
||||||
, unfurledObjectTableAlias = Just (tableName, joinAliasEntity)
|
, unfurledObjectTableAlias = Just (tableName, joinAliasEntity)
|
||||||
})
|
})
|
||||||
local (const joinAliasEntity) (unfurlAnnOrderByElement annOrderByElementG)
|
local (const joinAliasEntity) (unfurlAnnotatedOrderByElement annOrderByElementG)
|
||||||
Ir.AOCArrayAggregation Rql.RelInfo {riMapping = mapping, riRTable = tableName} annBoolExp annAggregateOrderBy -> do
|
Ir.AOCArrayAggregation Rql.RelInfo {riMapping = mapping, riRTable = tableName} annBoolExp annAggregateOrderBy -> do
|
||||||
selectFrom <- lift (lift (fromQualifiedTable tableName))
|
selectFrom <- lift (lift (fromQualifiedTable tableName))
|
||||||
let alias = aggFieldName
|
let alias = aggFieldName
|
||||||
|
@ -358,7 +358,7 @@ fromSelectArgsG selectArgsG = do
|
|||||||
-- you can just drop the Proxy wrapper.
|
-- you can just drop the Proxy wrapper.
|
||||||
let argsDistinct = Proxy
|
let argsDistinct = Proxy
|
||||||
(argsOrderBy, joins) <-
|
(argsOrderBy, joins) <-
|
||||||
runWriterT (traverse fromAnnOrderByItemG (maybe [] toList orders))
|
runWriterT (traverse fromAnnotatedOrderByItemG (maybe [] toList orders))
|
||||||
-- Any object-relation joins that we generated, we record their
|
-- Any object-relation joins that we generated, we record their
|
||||||
-- generated names into a mapping.
|
-- generated names into a mapping.
|
||||||
let argsExistingJoins =
|
let argsExistingJoins =
|
||||||
@ -378,11 +378,11 @@ fromSelectArgsG selectArgsG = do
|
|||||||
|
|
||||||
-- | Produce a valid ORDER BY construct, telling about any joins
|
-- | Produce a valid ORDER BY construct, telling about any joins
|
||||||
-- needed on the side.
|
-- needed on the side.
|
||||||
fromAnnOrderByItemG
|
fromAnnotatedOrderByItemG
|
||||||
:: IR.AnnOrderByItemG 'MSSQL Expression
|
:: IR.AnnotatedOrderByItemG 'MSSQL Expression
|
||||||
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) OrderBy
|
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) OrderBy
|
||||||
fromAnnOrderByItemG IR.OrderByItemG {obiType, obiColumn = obiColumn, obiNulls} = do
|
fromAnnotatedOrderByItemG IR.OrderByItemG {obiType, obiColumn = obiColumn, obiNulls} = do
|
||||||
(orderByFieldName, orderByType) <- unfurlAnnOrderByElement obiColumn
|
(orderByFieldName, orderByType) <- unfurlAnnotatedOrderByElement obiColumn
|
||||||
let orderByNullsOrder = fromMaybe NullsAnyOrder obiNulls
|
let orderByNullsOrder = fromMaybe NullsAnyOrder obiNulls
|
||||||
orderByOrder = fromMaybe AscOrder obiType
|
orderByOrder = fromMaybe AscOrder obiType
|
||||||
pure OrderBy {..}
|
pure OrderBy {..}
|
||||||
@ -390,10 +390,10 @@ fromAnnOrderByItemG IR.OrderByItemG {obiType, obiColumn = obiColumn, obiNulls} =
|
|||||||
-- | Unfurl the nested set of object relations (tell'd in the writer)
|
-- | Unfurl the nested set of object relations (tell'd in the writer)
|
||||||
-- that are terminated by field name (IR.AOCColumn and
|
-- that are terminated by field name (IR.AOCColumn and
|
||||||
-- IR.AOCArrayAggregation).
|
-- IR.AOCArrayAggregation).
|
||||||
unfurlAnnOrderByElement
|
unfurlAnnotatedOrderByElement
|
||||||
:: IR.AnnOrderByElement 'MSSQL Expression
|
:: IR.AnnotatedOrderByElement 'MSSQL Expression
|
||||||
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) (FieldName, Maybe TSQL.ScalarType)
|
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) (FieldName, Maybe TSQL.ScalarType)
|
||||||
unfurlAnnOrderByElement =
|
unfurlAnnotatedOrderByElement =
|
||||||
\case
|
\case
|
||||||
IR.AOCColumn pgColumnInfo -> do
|
IR.AOCColumn pgColumnInfo -> do
|
||||||
fieldName <- lift (fromPGColumnInfo pgColumnInfo)
|
fieldName <- lift (fromPGColumnInfo pgColumnInfo)
|
||||||
@ -444,7 +444,7 @@ unfurlAnnOrderByElement =
|
|||||||
})
|
})
|
||||||
local
|
local
|
||||||
(const (EntityAlias joinAliasEntity))
|
(const (EntityAlias joinAliasEntity))
|
||||||
(unfurlAnnOrderByElement annOrderByElementG)
|
(unfurlAnnotatedOrderByElement annOrderByElementG)
|
||||||
IR.AOCArrayAggregation IR.RelInfo {riMapping = mapping, riRTable = tableName} annBoolExp annAggregateOrderBy -> do
|
IR.AOCArrayAggregation IR.RelInfo {riMapping = mapping, riRTable = tableName} annBoolExp annAggregateOrderBy -> do
|
||||||
selectFrom <- lift (lift (fromQualifiedTable tableName))
|
selectFrom <- lift (lift (fromQualifiedTable tableName))
|
||||||
let alias = aggFieldName
|
let alias = aggFieldName
|
||||||
|
@ -220,11 +220,11 @@ mkBaseTableColumnAlias :: Identifier -> PGCol -> Identifier
|
|||||||
mkBaseTableColumnAlias pfx pgColumn =
|
mkBaseTableColumnAlias pfx pgColumn =
|
||||||
pfx <> Identifier ".pg." <> toIdentifier pgColumn
|
pfx <> Identifier ".pg." <> toIdentifier pgColumn
|
||||||
|
|
||||||
mkOrderByFieldName :: RelName -> FieldName
|
mkOrderByFieldName :: ToTxt a => a -> FieldName
|
||||||
mkOrderByFieldName relName =
|
mkOrderByFieldName name =
|
||||||
FieldName $ relNameToTxt relName <> "." <> "order_by"
|
FieldName $ toTxt name <> "." <> "order_by"
|
||||||
|
|
||||||
mkAggregateOrderByAlias :: AnnAggregateOrderBy ('Postgres pgKind) -> S.Alias
|
mkAggregateOrderByAlias :: AnnotatedAggregateOrderBy ('Postgres pgKind) -> S.Alias
|
||||||
mkAggregateOrderByAlias = (S.Alias . Identifier) . \case
|
mkAggregateOrderByAlias = (S.Alias . Identifier) . \case
|
||||||
AAOCount -> "count"
|
AAOCount -> "count"
|
||||||
AAOOp opText col -> opText <> "." <> getPGColTxt (pgiColumn col)
|
AAOOp opText col -> opText <> "." <> getPGColTxt (pgiColumn col)
|
||||||
@ -284,7 +284,7 @@ withForceAggregation tyAnn e =
|
|||||||
mkAggregateOrderByExtractorAndFields
|
mkAggregateOrderByExtractorAndFields
|
||||||
:: forall pgKind
|
:: forall pgKind
|
||||||
. Backend ('Postgres pgKind)
|
. Backend ('Postgres pgKind)
|
||||||
=> AnnAggregateOrderBy ('Postgres pgKind)
|
=> AnnotatedAggregateOrderBy ('Postgres pgKind)
|
||||||
-> (S.Extractor, AggregateFields ('Postgres pgKind))
|
-> (S.Extractor, AggregateFields ('Postgres pgKind))
|
||||||
mkAggregateOrderByExtractorAndFields annAggOrderBy =
|
mkAggregateOrderByExtractorAndFields annAggOrderBy =
|
||||||
case annAggOrderBy of
|
case annAggOrderBy of
|
||||||
@ -309,7 +309,7 @@ mkAggregateOrderByExtractorAndFields annAggOrderBy =
|
|||||||
alias = Just $ mkAggregateOrderByAlias annAggOrderBy
|
alias = Just $ mkAggregateOrderByAlias annAggOrderBy
|
||||||
|
|
||||||
mkAnnOrderByAlias
|
mkAnnOrderByAlias
|
||||||
:: Identifier -> FieldName -> SimilarArrayFields -> AnnOrderByElementG ('Postgres pgKind) v -> S.Alias
|
:: Identifier -> FieldName -> SimilarArrayFields -> AnnotatedOrderByElement ('Postgres pgKind) v -> S.Alias
|
||||||
mkAnnOrderByAlias pfx parAls similarFields = \case
|
mkAnnOrderByAlias pfx parAls similarFields = \case
|
||||||
AOCColumn pgColumnInfo ->
|
AOCColumn pgColumnInfo ->
|
||||||
let pgColumn = pgiColumn pgColumnInfo
|
let pgColumn = pgiColumn pgColumnInfo
|
||||||
@ -328,6 +328,14 @@ mkAnnOrderByAlias pfx parAls similarFields = \case
|
|||||||
mkOrderByFieldName rn
|
mkOrderByFieldName rn
|
||||||
obAls = arrPfx <> Identifier "." <> toIdentifier (mkAggregateOrderByAlias aggOrderBy)
|
obAls = arrPfx <> Identifier "." <> toIdentifier (mkAggregateOrderByAlias aggOrderBy)
|
||||||
in S.Alias obAls
|
in S.Alias obAls
|
||||||
|
AOCComputedField cfOrderBy ->
|
||||||
|
let fieldName = fromComputedField $ _cfobName cfOrderBy
|
||||||
|
in case _cfobOrderByElement cfOrderBy of
|
||||||
|
CFOBEScalar _ -> S.Alias $ mkComputedFieldTableAlias pfx fieldName
|
||||||
|
CFOBETableAggregation _ _ aggOrderBy ->
|
||||||
|
let cfPfx = mkComputedFieldTableAlias pfx fieldName
|
||||||
|
obAls = cfPfx <> Identifier "." <> toIdentifier (mkAggregateOrderByAlias aggOrderBy)
|
||||||
|
in S.Alias obAls
|
||||||
|
|
||||||
processDistinctOnColumns
|
processDistinctOnColumns
|
||||||
:: Identifier
|
:: Identifier
|
||||||
@ -349,7 +357,7 @@ mkSimilarArrayFields
|
|||||||
:: forall pgKind v
|
:: forall pgKind v
|
||||||
. (Backend ('Postgres pgKind), Eq v)
|
. (Backend ('Postgres pgKind), Eq v)
|
||||||
=> AnnFieldsG ('Postgres pgKind) (Const Void) v
|
=> AnnFieldsG ('Postgres pgKind) (Const Void) v
|
||||||
-> Maybe (NE.NonEmpty (AnnOrderByItemG ('Postgres pgKind) v))
|
-> Maybe (NE.NonEmpty (AnnotatedOrderByItemG ('Postgres pgKind) v))
|
||||||
-> SimilarArrayFields
|
-> SimilarArrayFields
|
||||||
mkSimilarArrayFields annFields maybeOrderBys =
|
mkSimilarArrayFields annFields maybeOrderBys =
|
||||||
HM.fromList $ flip map allTuples $
|
HM.fromList $ flip map allTuples $
|
||||||
@ -432,7 +440,7 @@ withWriteArrayRelation action =
|
|||||||
pure (out, (source, topExtractor, nodeExtractors))
|
pure (out, (source, topExtractor, nodeExtractors))
|
||||||
where
|
where
|
||||||
updateJoinTree joinTree (source, topExtractor, nodeExtractors) =
|
updateJoinTree joinTree (source, topExtractor, nodeExtractors) =
|
||||||
let arraySelectNode = ArraySelectNode [topExtractor] $
|
let arraySelectNode = MultiRowSelectNode [topExtractor] $
|
||||||
SelectNode nodeExtractors joinTree
|
SelectNode nodeExtractors joinTree
|
||||||
in mempty{_jtArrayRelations = HM.singleton source arraySelectNode}
|
in mempty{_jtArrayRelations = HM.singleton source arraySelectNode}
|
||||||
|
|
||||||
@ -450,24 +458,25 @@ withWriteArrayConnection action =
|
|||||||
pure (out, (source, topExtractor, nodeExtractors))
|
pure (out, (source, topExtractor, nodeExtractors))
|
||||||
where
|
where
|
||||||
updateJoinTree joinTree (source, topExtractor, nodeExtractors) =
|
updateJoinTree joinTree (source, topExtractor, nodeExtractors) =
|
||||||
let arraySelectNode = ArraySelectNode [topExtractor] $
|
let arraySelectNode = MultiRowSelectNode [topExtractor] $
|
||||||
SelectNode nodeExtractors joinTree
|
SelectNode nodeExtractors joinTree
|
||||||
in mempty{_jtArrayConnections = HM.singleton source arraySelectNode}
|
in mempty{_jtArrayConnections = HM.singleton source arraySelectNode}
|
||||||
|
|
||||||
withWriteComputedFieldTableSet
|
withWriteComputedFieldTableSet
|
||||||
:: (MonadWriter JoinTree m)
|
:: (MonadWriter JoinTree m)
|
||||||
=> m ( ComputedFieldTableSetSource
|
=> m ( ComputedFieldTableSetSource
|
||||||
|
, S.Extractor
|
||||||
, HM.HashMap S.Alias S.SQLExp
|
, HM.HashMap S.Alias S.SQLExp
|
||||||
, a
|
, a
|
||||||
)
|
)
|
||||||
-> m a
|
-> m a
|
||||||
withWriteComputedFieldTableSet action =
|
withWriteComputedFieldTableSet action =
|
||||||
withWriteJoinTree updateJoinTree $ do
|
withWriteJoinTree updateJoinTree $ do
|
||||||
(source, nodeExtractors, out) <- action
|
(source, topExtractor, nodeExtractors, out) <- action
|
||||||
pure (out, (source, nodeExtractors))
|
pure (out, (source, topExtractor, nodeExtractors))
|
||||||
where
|
where
|
||||||
updateJoinTree joinTree (source, nodeExtractors) =
|
updateJoinTree joinTree (source, topExtractor, nodeExtractors) =
|
||||||
let selectNode = SelectNode nodeExtractors joinTree
|
let selectNode = MultiRowSelectNode [topExtractor] $ SelectNode nodeExtractors joinTree
|
||||||
in mempty{_jtComputedFieldTableSets = HM.singleton source selectNode}
|
in mempty{_jtComputedFieldTableSets = HM.singleton source selectNode}
|
||||||
|
|
||||||
|
|
||||||
@ -557,7 +566,7 @@ processAnnAggregateSelect sourcePrefixes fieldAlias annAggSel = do
|
|||||||
mkPermissionLimitSubQuery
|
mkPermissionLimitSubQuery
|
||||||
:: Maybe Int
|
:: Maybe Int
|
||||||
-> TableAggregateFields ('Postgres pgKind)
|
-> TableAggregateFields ('Postgres pgKind)
|
||||||
-> Maybe (NE.NonEmpty (AnnOrderByItem ('Postgres pgKind)))
|
-> Maybe (NE.NonEmpty (AnnotatedOrderByItem ('Postgres pgKind)))
|
||||||
-> PermissionLimitSubQuery
|
-> PermissionLimitSubQuery
|
||||||
mkPermissionLimitSubQuery permLimit aggFields orderBys =
|
mkPermissionLimitSubQuery permLimit aggFields orderBys =
|
||||||
case permLimit of
|
case permLimit of
|
||||||
@ -685,7 +694,7 @@ processOrderByItems
|
|||||||
=> Identifier
|
=> Identifier
|
||||||
-> FieldName
|
-> FieldName
|
||||||
-> SimilarArrayFields
|
-> SimilarArrayFields
|
||||||
-> NE.NonEmpty (AnnOrderByItem ('Postgres pgKind))
|
-> NE.NonEmpty (AnnotatedOrderByItem ('Postgres pgKind))
|
||||||
-> m ( [(S.Alias, S.SQLExp)] -- Order by Extractors
|
-> m ( [(S.Alias, S.SQLExp)] -- Order by Extractors
|
||||||
, S.OrderByExp
|
, S.OrderByExp
|
||||||
, S.SQLExp -- The cursor expression
|
, S.SQLExp -- The cursor expression
|
||||||
@ -698,15 +707,15 @@ processOrderByItems sourcePrefix' fieldAlias' similarArrayFields orderByItems =
|
|||||||
pure (orderByExtractors, orderByExp, cursor)
|
pure (orderByExtractors, orderByExp, cursor)
|
||||||
where
|
where
|
||||||
processAnnOrderByItem
|
processAnnOrderByItem
|
||||||
:: AnnOrderByItem ('Postgres pgKind)
|
:: AnnotatedOrderByItem ('Postgres pgKind)
|
||||||
-> m (OrderByItemG ('Postgres pgKind) (AnnOrderByElement ('Postgres pgKind) (SQLExpression ('Postgres pgKind)), (S.Alias, SQLExpression ('Postgres pgKind))))
|
-> m (OrderByItemG ('Postgres pgKind) (AnnotatedOrderByElement ('Postgres pgKind) (SQLExpression ('Postgres pgKind)), (S.Alias, SQLExpression ('Postgres pgKind))))
|
||||||
processAnnOrderByItem orderByItem =
|
processAnnOrderByItem orderByItem =
|
||||||
forM orderByItem $ \ordByCol -> (ordByCol,) <$>
|
forM orderByItem $ \ordByCol -> (ordByCol,) <$>
|
||||||
processAnnOrderByElement sourcePrefix' fieldAlias' ordByCol
|
processAnnotatedOrderByElement sourcePrefix' fieldAlias' ordByCol
|
||||||
|
|
||||||
processAnnOrderByElement
|
processAnnotatedOrderByElement
|
||||||
:: Identifier -> FieldName -> AnnOrderByElement ('Postgres pgKind) S.SQLExp -> m (S.Alias, S.SQLExp)
|
:: Identifier -> FieldName -> AnnotatedOrderByElement ('Postgres pgKind) S.SQLExp -> m (S.Alias, S.SQLExp)
|
||||||
processAnnOrderByElement sourcePrefix fieldAlias annObCol = do
|
processAnnotatedOrderByElement sourcePrefix fieldAlias annObCol = do
|
||||||
let ordByAlias = mkAnnOrderByAlias sourcePrefix fieldAlias similarArrayFields annObCol
|
let ordByAlias = mkAnnOrderByAlias sourcePrefix fieldAlias similarArrayFields annObCol
|
||||||
(ordByAlias, ) <$> case annObCol of
|
(ordByAlias, ) <$> case annObCol of
|
||||||
AOCColumn pgColInfo -> pure $
|
AOCColumn pgColInfo -> pure $
|
||||||
@ -717,7 +726,7 @@ processOrderByItems sourcePrefix' fieldAlias' similarArrayFields orderByItems =
|
|||||||
relSourcePrefix = mkObjectRelationTableAlias sourcePrefix relName
|
relSourcePrefix = mkObjectRelationTableAlias sourcePrefix relName
|
||||||
fieldName = mkOrderByFieldName relName
|
fieldName = mkOrderByFieldName relName
|
||||||
(relOrderByAlias, relOrdByExp) <-
|
(relOrderByAlias, relOrdByExp) <-
|
||||||
processAnnOrderByElement relSourcePrefix fieldName rest
|
processAnnotatedOrderByElement relSourcePrefix fieldName rest
|
||||||
let selectSource = ObjectSelectSource relSourcePrefix
|
let selectSource = ObjectSelectSource relSourcePrefix
|
||||||
(S.FISimple relTable Nothing)
|
(S.FISimple relTable Nothing)
|
||||||
(toSQLBoolExp (S.QualTable relTable) relFilter)
|
(toSQLBoolExp (S.QualTable relTable) relFilter)
|
||||||
@ -745,15 +754,38 @@ processOrderByItems sourcePrefix' fieldAlias' similarArrayFields orderByItems =
|
|||||||
, S.mkQIdenExp relSourcePrefix (mkAggregateOrderByAlias aggOrderBy)
|
, S.mkQIdenExp relSourcePrefix (mkAggregateOrderByAlias aggOrderBy)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AOCComputedField ComputedFieldOrderBy{..} ->
|
||||||
|
case _cfobOrderByElement of
|
||||||
|
CFOBEScalar _ -> do
|
||||||
|
let functionArgs = fromTableRowArgs sourcePrefix _cfobFunctionArgsExp
|
||||||
|
functionExp = S.FunctionExp _cfobFunction functionArgs Nothing
|
||||||
|
pure $ S.SEFunction functionExp
|
||||||
|
CFOBETableAggregation _ tableFilter aggOrderBy -> withWriteComputedFieldTableSet $ do
|
||||||
|
let fieldName = mkOrderByFieldName _cfobName
|
||||||
|
computedFieldSourcePrefix = mkComputedFieldTableAlias sourcePrefix fieldName
|
||||||
|
(topExtractor, fields) = mkAggregateOrderByExtractorAndFields aggOrderBy
|
||||||
|
fromItem = selectFromToFromItem sourcePrefix $
|
||||||
|
FromFunction _cfobFunction _cfobFunctionArgsExp Nothing
|
||||||
|
functionQual = S.QualifiedIdentifier (functionToIdentifier _cfobFunction) Nothing
|
||||||
|
selectSource = SelectSource computedFieldSourcePrefix fromItem Nothing
|
||||||
|
(toSQLBoolExp functionQual tableFilter)
|
||||||
|
Nothing Nothing Nothing
|
||||||
|
source = ComputedFieldTableSetSource fieldName selectSource
|
||||||
|
pure ( source
|
||||||
|
, topExtractor
|
||||||
|
, HM.fromList $ aggregateFieldsToExtractorExps computedFieldSourcePrefix fields
|
||||||
|
, S.mkQIdenExp computedFieldSourcePrefix (mkAggregateOrderByAlias aggOrderBy)
|
||||||
|
)
|
||||||
|
|
||||||
toOrderByExp
|
toOrderByExp
|
||||||
:: OrderByItemG ('Postgres pgKind) (AnnOrderByElement ('Postgres pgKind) (SQLExpression ('Postgres pgKind)), (S.Alias, SQLExpression ('Postgres pgKind)))
|
:: OrderByItemG ('Postgres pgKind) (AnnotatedOrderByElement ('Postgres pgKind) (SQLExpression ('Postgres pgKind)), (S.Alias, SQLExpression ('Postgres pgKind)))
|
||||||
-> S.OrderByItem
|
-> S.OrderByItem
|
||||||
toOrderByExp orderByItemExp =
|
toOrderByExp orderByItemExp =
|
||||||
let OrderByItemG obTyM expAlias obNullsM = fst . snd <$> orderByItemExp
|
let OrderByItemG obTyM expAlias obNullsM = fst . snd <$> orderByItemExp
|
||||||
in S.OrderByItem (S.SEIdentifier $ toIdentifier expAlias) obTyM obNullsM
|
in S.OrderByItem (S.SEIdentifier $ toIdentifier expAlias) obTyM obNullsM
|
||||||
|
|
||||||
mkCursorExp
|
mkCursorExp
|
||||||
:: [OrderByItemG ('Postgres pgKind) (AnnOrderByElement ('Postgres pgKind) (SQLExpression ('Postgres pgKind)), (S.Alias, SQLExpression ('Postgres pgKind)))]
|
:: [OrderByItemG ('Postgres pgKind) (AnnotatedOrderByElement ('Postgres pgKind) (SQLExpression ('Postgres pgKind)), (S.Alias, SQLExpression ('Postgres pgKind)))]
|
||||||
-> S.SQLExp
|
-> S.SQLExp
|
||||||
mkCursorExp orderByItemExps =
|
mkCursorExp orderByItemExps =
|
||||||
S.applyJsonBuildObj $ flip concatMap orderByItemExps $
|
S.applyJsonBuildObj $ flip concatMap orderByItemExps $
|
||||||
@ -761,6 +793,13 @@ processOrderByItems sourcePrefix' fieldAlias' similarArrayFields orderByItems =
|
|||||||
let OrderByItemG _ (annObCol, (_, valExp)) _ = orderByItemExp
|
let OrderByItemG _ (annObCol, (_, valExp)) _ = orderByItemExp
|
||||||
in annObColToJSONField valExp annObCol
|
in annObColToJSONField valExp annObCol
|
||||||
where
|
where
|
||||||
|
mkAggOrderByValExp valExp = \case
|
||||||
|
AAOCount -> [S.SELit "count", valExp]
|
||||||
|
AAOOp opText colInfo ->
|
||||||
|
[ S.SELit opText
|
||||||
|
, S.applyJsonBuildObj [S.SELit $ getPGColTxt $ pgiColumn colInfo, valExp]
|
||||||
|
]
|
||||||
|
|
||||||
annObColToJSONField valExp = \case
|
annObColToJSONField valExp = \case
|
||||||
AOCColumn pgCol -> [S.SELit $ getPGColTxt $ pgiColumn pgCol, valExp]
|
AOCColumn pgCol -> [S.SELit $ getPGColTxt $ pgiColumn pgCol, valExp]
|
||||||
AOCObjectRelation relInfo _ obCol ->
|
AOCObjectRelation relInfo _ obCol ->
|
||||||
@ -769,14 +808,16 @@ processOrderByItems sourcePrefix' fieldAlias' similarArrayFields orderByItems =
|
|||||||
]
|
]
|
||||||
AOCArrayAggregation relInfo _ aggOrderBy ->
|
AOCArrayAggregation relInfo _ aggOrderBy ->
|
||||||
[ S.SELit $ relNameToTxt (riName relInfo) <> "_aggregate"
|
[ S.SELit $ relNameToTxt (riName relInfo) <> "_aggregate"
|
||||||
, S.applyJsonBuildObj $
|
, S.applyJsonBuildObj $ mkAggOrderByValExp valExp aggOrderBy
|
||||||
case aggOrderBy of
|
|
||||||
AAOCount -> [S.SELit "count", valExp]
|
|
||||||
AAOOp opText colInfo ->
|
|
||||||
[ S.SELit opText
|
|
||||||
, S.applyJsonBuildObj [S.SELit $ getPGColTxt $ pgiColumn colInfo, valExp]
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
|
AOCComputedField cfOrderBy ->
|
||||||
|
let fieldNameText = computedFieldNameToText $ _cfobName cfOrderBy
|
||||||
|
in case _cfobOrderByElement cfOrderBy of
|
||||||
|
CFOBEScalar _ -> [S.SELit fieldNameText, valExp]
|
||||||
|
CFOBETableAggregation _ _ aggOrderBy ->
|
||||||
|
[ S.SELit $ fieldNameText <> "_aggregate"
|
||||||
|
, S.applyJsonBuildObj $ mkAggOrderByValExp valExp aggOrderBy
|
||||||
|
]
|
||||||
|
|
||||||
aggregateFieldsToExtractorExps
|
aggregateFieldsToExtractorExps
|
||||||
:: Identifier -> AggregateFields ('Postgres pgKind) -> [(S.Alias, S.SQLExp)]
|
:: Identifier -> AggregateFields ('Postgres pgKind) -> [(S.Alias, S.SQLExp)]
|
||||||
@ -917,9 +958,11 @@ processAnnFields sourcePrefix fieldAlias similarArrFields annFields = do
|
|||||||
(selectSource, nodeExtractors) <-
|
(selectSource, nodeExtractors) <-
|
||||||
processAnnSimpleSelect (mkSourcePrefixes computedFieldSourcePrefix)
|
processAnnSimpleSelect (mkSourcePrefixes computedFieldSourcePrefix)
|
||||||
fieldName PLSQNotRequired sel
|
fieldName PLSQNotRequired sel
|
||||||
let computedFieldTableSetSource =
|
let computedFieldTableSetSource = ComputedFieldTableSetSource fieldName selectSource
|
||||||
ComputedFieldTableSetSource fieldName selectTy selectSource
|
extractor = asJsonAggExtr selectTy (S.toAlias fieldName) PLSQNotRequired $
|
||||||
|
_ssOrderBy selectSource
|
||||||
pure ( computedFieldTableSetSource
|
pure ( computedFieldTableSetSource
|
||||||
|
, extractor
|
||||||
, nodeExtractors
|
, nodeExtractors
|
||||||
, S.mkQIdenExp computedFieldSourcePrefix fieldName
|
, S.mkQIdenExp computedFieldSourcePrefix fieldName
|
||||||
)
|
)
|
||||||
@ -1027,7 +1070,6 @@ generateSQLSelect joinCondition selectSource selectNode =
|
|||||||
map arrayConnectionToFromItem (HM.toList arrayConnections) <>
|
map arrayConnectionToFromItem (HM.toList arrayConnections) <>
|
||||||
map computedFieldToFromItem (HM.toList computedFields)
|
map computedFieldToFromItem (HM.toList computedFields)
|
||||||
|
|
||||||
|
|
||||||
objectRelationToFromItem
|
objectRelationToFromItem
|
||||||
:: (ObjectRelationSource, SelectNode) -> S.FromItem
|
:: (ObjectRelationSource, SelectNode) -> S.FromItem
|
||||||
objectRelationToFromItem (objectRelationSource, node) =
|
objectRelationToFromItem (objectRelationSource, node) =
|
||||||
@ -1038,7 +1080,7 @@ generateSQLSelect joinCondition selectSource selectNode =
|
|||||||
in S.mkLateralFromItem select alias
|
in S.mkLateralFromItem select alias
|
||||||
|
|
||||||
arrayRelationToFromItem
|
arrayRelationToFromItem
|
||||||
:: (ArrayRelationSource, ArraySelectNode) -> S.FromItem
|
:: (ArrayRelationSource, MultiRowSelectNode) -> S.FromItem
|
||||||
arrayRelationToFromItem (arrayRelationSource, arraySelectNode) =
|
arrayRelationToFromItem (arrayRelationSource, arraySelectNode) =
|
||||||
let ArrayRelationSource _ colMapping source = arrayRelationSource
|
let ArrayRelationSource _ colMapping source = arrayRelationSource
|
||||||
alias = S.Alias $ _ssPrefix source
|
alias = S.Alias $ _ssPrefix source
|
||||||
@ -1047,29 +1089,27 @@ generateSQLSelect joinCondition selectSource selectNode =
|
|||||||
in S.mkLateralFromItem select alias
|
in S.mkLateralFromItem select alias
|
||||||
|
|
||||||
arrayConnectionToFromItem
|
arrayConnectionToFromItem
|
||||||
:: (ArrayConnectionSource, ArraySelectNode) -> S.FromItem
|
:: (ArrayConnectionSource, MultiRowSelectNode) -> S.FromItem
|
||||||
arrayConnectionToFromItem (arrayConnectionSource, arraySelectNode) =
|
arrayConnectionToFromItem (arrayConnectionSource, arraySelectNode) =
|
||||||
let selectWith = connectionToSelectWith baseSelectAlias arrayConnectionSource arraySelectNode
|
let selectWith = connectionToSelectWith baseSelectAlias arrayConnectionSource arraySelectNode
|
||||||
alias = S.Alias $ _ssPrefix $ _acsSource arrayConnectionSource
|
alias = S.Alias $ _ssPrefix $ _acsSource arrayConnectionSource
|
||||||
in S.FISelectWith (S.Lateral True) selectWith alias
|
in S.FISelectWith (S.Lateral True) selectWith alias
|
||||||
|
|
||||||
computedFieldToFromItem
|
computedFieldToFromItem
|
||||||
:: (ComputedFieldTableSetSource, SelectNode) -> S.FromItem
|
:: (ComputedFieldTableSetSource, MultiRowSelectNode) -> S.FromItem
|
||||||
computedFieldToFromItem (computedFieldTableSource, node) =
|
computedFieldToFromItem (computedFieldTableSource, node) =
|
||||||
let ComputedFieldTableSetSource fieldName selectTy source = computedFieldTableSource
|
let ComputedFieldTableSetSource _ source = computedFieldTableSource
|
||||||
internalSelect = generateSQLSelect (S.BELit True) source node
|
internalSelect = generateSQLSelect (S.BELit True) source $ _mrsnSelectNode node
|
||||||
extractor = asJsonAggExtr selectTy (S.toAlias fieldName) PLSQNotRequired $
|
|
||||||
_ssOrderBy source
|
|
||||||
alias = S.Alias $ _ssPrefix source
|
alias = S.Alias $ _ssPrefix source
|
||||||
select = S.mkSelect
|
select = S.mkSelect
|
||||||
{ S.selExtr = [extractor]
|
{ S.selExtr = _mrsnTopExtractors node
|
||||||
, S.selFrom = Just $ S.FromExp [S.mkSelFromItem internalSelect alias]
|
, S.selFrom = Just $ S.FromExp [S.mkSelFromItem internalSelect alias]
|
||||||
}
|
}
|
||||||
in S.mkLateralFromItem select alias
|
in S.mkLateralFromItem select alias
|
||||||
|
|
||||||
generateSQLSelectFromArrayNode
|
generateSQLSelectFromArrayNode
|
||||||
:: SelectSource
|
:: SelectSource
|
||||||
-> ArraySelectNode
|
-> MultiRowSelectNode
|
||||||
-> S.BoolExp
|
-> S.BoolExp
|
||||||
-> S.Select
|
-> S.Select
|
||||||
generateSQLSelectFromArrayNode selectSource arraySelectNode joinCondition =
|
generateSQLSelectFromArrayNode selectSource arraySelectNode joinCondition =
|
||||||
@ -1078,7 +1118,7 @@ generateSQLSelectFromArrayNode selectSource arraySelectNode joinCondition =
|
|||||||
, S.selFrom = Just $ S.FromExp [selectFrom]
|
, S.selFrom = Just $ S.FromExp [selectFrom]
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
ArraySelectNode topExtractors selectNode = arraySelectNode
|
MultiRowSelectNode topExtractors selectNode = arraySelectNode
|
||||||
selectFrom = S.mkSelFromItem
|
selectFrom = S.mkSelFromItem
|
||||||
(generateSQLSelect joinCondition selectSource selectNode) $
|
(generateSQLSelect joinCondition selectSource selectNode) $
|
||||||
S.Alias $ _ssPrefix selectSource
|
S.Alias $ _ssPrefix selectSource
|
||||||
@ -1095,7 +1135,7 @@ mkAggregateSelect annAggSel =
|
|||||||
runWriter $ flip runReaderT strfyNum $
|
runWriter $ flip runReaderT strfyNum $
|
||||||
processAnnAggregateSelect sourcePrefixes rootFieldName annAggSel
|
processAnnAggregateSelect sourcePrefixes rootFieldName annAggSel
|
||||||
selectNode = SelectNode nodeExtractors joinTree
|
selectNode = SelectNode nodeExtractors joinTree
|
||||||
arrayNode = ArraySelectNode [topExtractor] selectNode
|
arrayNode = MultiRowSelectNode [topExtractor] selectNode
|
||||||
in prefixNumToAliases $
|
in prefixNumToAliases $
|
||||||
generateSQLSelectFromArrayNode selectSource arrayNode $ S.BELit True
|
generateSQLSelectFromArrayNode selectSource arrayNode $ S.BELit True
|
||||||
where
|
where
|
||||||
@ -1120,7 +1160,7 @@ mkSQLSelect jsonAggSelect annSel =
|
|||||||
selectNode = SelectNode nodeExtractors joinTree
|
selectNode = SelectNode nodeExtractors joinTree
|
||||||
topExtractor = asJsonAggExtr jsonAggSelect rootFldAls permLimitSubQuery
|
topExtractor = asJsonAggExtr jsonAggSelect rootFldAls permLimitSubQuery
|
||||||
$ _ssOrderBy selectSource
|
$ _ssOrderBy selectSource
|
||||||
arrayNode = ArraySelectNode [topExtractor] selectNode
|
arrayNode = MultiRowSelectNode [topExtractor] selectNode
|
||||||
in prefixNumToAliases $
|
in prefixNumToAliases $
|
||||||
generateSQLSelectFromArrayNode selectSource arrayNode $ S.BELit True
|
generateSQLSelectFromArrayNode selectSource arrayNode $ S.BELit True
|
||||||
where
|
where
|
||||||
@ -1142,7 +1182,7 @@ mkConnectionSelect connectionSelect =
|
|||||||
runWriter $ flip runReaderT strfyNum $
|
runWriter $ flip runReaderT strfyNum $
|
||||||
processConnectionSelect sourcePrefixes rootFieldName
|
processConnectionSelect sourcePrefixes rootFieldName
|
||||||
(S.Alias rootIdentifier) mempty connectionSelect
|
(S.Alias rootIdentifier) mempty connectionSelect
|
||||||
selectNode = ArraySelectNode [topExtractor] $
|
selectNode = MultiRowSelectNode [topExtractor] $
|
||||||
SelectNode nodeExtractors joinTree
|
SelectNode nodeExtractors joinTree
|
||||||
in prefixNumToAliasesSelectWith $
|
in prefixNumToAliasesSelectWith $
|
||||||
connectionToSelectWith (S.Alias rootIdentifier) connectionSource selectNode
|
connectionToSelectWith (S.Alias rootIdentifier) connectionSource selectNode
|
||||||
@ -1350,7 +1390,7 @@ processConnectionSelect sourcePrefixes fieldAlias relAlias colMapping connection
|
|||||||
connectionToSelectWith
|
connectionToSelectWith
|
||||||
:: S.Alias
|
:: S.Alias
|
||||||
-> ArrayConnectionSource
|
-> ArrayConnectionSource
|
||||||
-> ArraySelectNode
|
-> MultiRowSelectNode
|
||||||
-> S.SelectWithG S.Select
|
-> S.SelectWithG S.Select
|
||||||
connectionToSelectWith baseSelectAlias arrayConnectionSource arraySelectNode =
|
connectionToSelectWith baseSelectAlias arrayConnectionSource arraySelectNode =
|
||||||
let extractionSelect = S.mkSelect
|
let extractionSelect = S.mkSelect
|
||||||
@ -1361,7 +1401,7 @@ connectionToSelectWith baseSelectAlias arrayConnectionSource arraySelectNode =
|
|||||||
where
|
where
|
||||||
ArrayConnectionSource _ columnMapping maybeSplit maybeSlice selectSource =
|
ArrayConnectionSource _ columnMapping maybeSplit maybeSlice selectSource =
|
||||||
arrayConnectionSource
|
arrayConnectionSource
|
||||||
ArraySelectNode topExtractors selectNode = arraySelectNode
|
MultiRowSelectNode topExtractors selectNode = arraySelectNode
|
||||||
baseSelectIdentifier = Identifier "__base_select"
|
baseSelectIdentifier = Identifier "__base_select"
|
||||||
splitSelectIdentifier = Identifier "__split_select"
|
splitSelectIdentifier = Identifier "__split_select"
|
||||||
sliceSelectIdentifier = Identifier "__slice_select"
|
sliceSelectIdentifier = Identifier "__slice_select"
|
||||||
|
@ -79,20 +79,19 @@ data ArrayRelationSource
|
|||||||
instance Hashable ArrayRelationSource
|
instance Hashable ArrayRelationSource
|
||||||
deriving instance Eq ArrayRelationSource
|
deriving instance Eq ArrayRelationSource
|
||||||
|
|
||||||
data ArraySelectNode
|
data MultiRowSelectNode
|
||||||
= ArraySelectNode
|
= MultiRowSelectNode
|
||||||
{ _asnTopExtractors :: ![PG.Extractor]
|
{ _mrsnTopExtractors :: ![PG.Extractor]
|
||||||
, _asnSelectNode :: !SelectNode
|
, _mrsnSelectNode :: !SelectNode
|
||||||
}
|
}
|
||||||
|
|
||||||
instance Semigroup ArraySelectNode where
|
instance Semigroup MultiRowSelectNode where
|
||||||
ArraySelectNode lTopExtrs lSelNode <> ArraySelectNode rTopExtrs rSelNode =
|
MultiRowSelectNode lTopExtrs lSelNode <> MultiRowSelectNode rTopExtrs rSelNode =
|
||||||
ArraySelectNode (lTopExtrs <> rTopExtrs) (lSelNode <> rSelNode)
|
MultiRowSelectNode (lTopExtrs <> rTopExtrs) (lSelNode <> rSelNode)
|
||||||
|
|
||||||
data ComputedFieldTableSetSource
|
data ComputedFieldTableSetSource
|
||||||
= ComputedFieldTableSetSource
|
= ComputedFieldTableSetSource
|
||||||
{ _cftssFieldName :: !FieldName
|
{ _cftssFieldName :: !FieldName
|
||||||
, _cftssSelectType :: !JsonAggSelect
|
|
||||||
, _cftssSelectSource :: !SelectSource
|
, _cftssSelectSource :: !SelectSource
|
||||||
} deriving (Generic)
|
} deriving (Generic)
|
||||||
instance Hashable ComputedFieldTableSetSource
|
instance Hashable ComputedFieldTableSetSource
|
||||||
@ -114,9 +113,9 @@ instance Hashable ArrayConnectionSource
|
|||||||
data JoinTree
|
data JoinTree
|
||||||
= JoinTree
|
= JoinTree
|
||||||
{ _jtObjectRelations :: !(HM.HashMap ObjectRelationSource SelectNode)
|
{ _jtObjectRelations :: !(HM.HashMap ObjectRelationSource SelectNode)
|
||||||
, _jtArrayRelations :: !(HM.HashMap ArrayRelationSource ArraySelectNode)
|
, _jtArrayRelations :: !(HM.HashMap ArrayRelationSource MultiRowSelectNode)
|
||||||
, _jtArrayConnections :: !(HM.HashMap ArrayConnectionSource ArraySelectNode)
|
, _jtArrayConnections :: !(HM.HashMap ArrayConnectionSource MultiRowSelectNode)
|
||||||
, _jtComputedFieldTableSets :: !(HM.HashMap ComputedFieldTableSetSource SelectNode)
|
, _jtComputedFieldTableSets :: !(HM.HashMap ComputedFieldTableSetSource MultiRowSelectNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
instance Semigroup JoinTree where
|
instance Semigroup JoinTree where
|
||||||
|
@ -322,19 +322,10 @@ transformAnnFields path fields = do
|
|||||||
mkScalarComputedFieldSelect :: ScalarComputedField b -> (AnnFieldG b (Const Void) (UnpreparedValue b))
|
mkScalarComputedFieldSelect :: ScalarComputedField b -> (AnnFieldG b (Const Void) (UnpreparedValue b))
|
||||||
mkScalarComputedFieldSelect ScalarComputedField{..} =
|
mkScalarComputedFieldSelect ScalarComputedField{..} =
|
||||||
let functionArgs = flip FunctionArgsExp mempty
|
let functionArgs = flip FunctionArgsExp mempty
|
||||||
$ functionArgsWithTableRowAndSession _scfTableArgument _scfSessionArgument
|
$ functionArgsWithTableRowAndSession UVSession _scfTableArgument _scfSessionArgument
|
||||||
fieldSelect = flip CFSScalar Nothing
|
fieldSelect = flip CFSScalar Nothing
|
||||||
$ ComputedFieldScalarSelect _scfFunction functionArgs _scfType Nothing
|
$ ComputedFieldScalarSelect _scfFunction functionArgs _scfType Nothing
|
||||||
in AFComputedField _scfXField _scfName fieldSelect
|
in AFComputedField _scfXField _scfName fieldSelect
|
||||||
where
|
|
||||||
functionArgsWithTableRowAndSession
|
|
||||||
:: FunctionTableArgument
|
|
||||||
-> Maybe FunctionSessionArgument
|
|
||||||
-> [ArgumentExp b (UnpreparedValue b)]
|
|
||||||
functionArgsWithTableRowAndSession _ Nothing = [AETableRow Nothing] -- No session argument
|
|
||||||
functionArgsWithTableRowAndSession (FTAFirst) _ = [AETableRow Nothing, AESession UVSession]
|
|
||||||
functionArgsWithTableRowAndSession (FTANamed _ 0) _ = [AETableRow Nothing, AESession UVSession] -- Index is 0 implies table argument is first
|
|
||||||
functionArgsWithTableRowAndSession _ _ = [AESession UVSession, AETableRow Nothing]
|
|
||||||
|
|
||||||
|
|
||||||
mapToNonEmpty :: RemoteJoinMap -> Maybe RemoteJoins
|
mapToNonEmpty :: RemoteJoinMap -> Maybe RemoteJoins
|
||||||
|
@ -36,7 +36,7 @@ orderByExp
|
|||||||
=> SourceName
|
=> SourceName
|
||||||
-> TableInfo b
|
-> TableInfo b
|
||||||
-> SelPermInfo b
|
-> SelPermInfo b
|
||||||
-> m (Parser 'Input n [IR.AnnOrderByItemG b (UnpreparedValue b)])
|
-> m (Parser 'Input n [IR.AnnotatedOrderByItemG b (UnpreparedValue b)])
|
||||||
orderByExp sourceName tableInfo selectPermissions = memoizeOn 'orderByExp (sourceName, tableInfoName tableInfo) $ do
|
orderByExp sourceName tableInfo selectPermissions = memoizeOn 'orderByExp (sourceName, tableInfoName tableInfo) $ do
|
||||||
tableGQLName <- getTableGQLName tableInfo
|
tableGQLName <- getTableGQLName tableInfo
|
||||||
let name = tableGQLName <> $$(G.litName "_order_by")
|
let name = tableGQLName <> $$(G.litName "_order_by")
|
||||||
@ -48,18 +48,19 @@ orderByExp sourceName tableInfo selectPermissions = memoizeOn 'orderByExp (sourc
|
|||||||
where
|
where
|
||||||
mkField
|
mkField
|
||||||
:: FieldInfo b
|
:: FieldInfo b
|
||||||
-> m (Maybe (InputFieldsParser n (Maybe [IR.AnnOrderByItemG b (UnpreparedValue b)])))
|
-> m (Maybe (InputFieldsParser n (Maybe [IR.AnnotatedOrderByItemG b (UnpreparedValue b)])))
|
||||||
mkField fieldInfo = runMaybeT $
|
mkField fieldInfo = runMaybeT $
|
||||||
case fieldInfo of
|
case fieldInfo of
|
||||||
FIColumn columnInfo -> do
|
FIColumn columnInfo -> do
|
||||||
let fieldName = pgiName columnInfo
|
let fieldName = pgiName columnInfo
|
||||||
pure $ P.fieldOptional fieldName Nothing (orderByOperator @b)
|
pure $ P.fieldOptional fieldName Nothing (orderByOperator @b)
|
||||||
<&> fmap (pure . mkOrderByItemG @b (IR.AOCColumn columnInfo)) . join
|
<&> fmap (pure . mkOrderByItemG @b (IR.AOCColumn columnInfo)) . join
|
||||||
|
|
||||||
FIRelationship relationshipInfo -> do
|
FIRelationship relationshipInfo -> do
|
||||||
remoteTableInfo <- askTableInfo @b sourceName $ riRTable relationshipInfo
|
remoteTableInfo <- askTableInfo @b sourceName $ riRTable relationshipInfo
|
||||||
fieldName <- hoistMaybe $ G.mkName $ relNameToTxt $ riName relationshipInfo
|
fieldName <- hoistMaybe $ G.mkName $ relNameToTxt $ riName relationshipInfo
|
||||||
perms <- MaybeT $ tableSelectPermissions remoteTableInfo
|
perms <- MaybeT $ tableSelectPermissions remoteTableInfo
|
||||||
let newPerms = (fmap . fmap) partialSQLExpToUnpreparedValue $ spiFilter perms
|
let newPerms = fmap partialSQLExpToUnpreparedValue <$> spiFilter perms
|
||||||
case riType relationshipInfo of
|
case riType relationshipInfo of
|
||||||
ObjRel -> do
|
ObjRel -> do
|
||||||
otherTableParser <- lift $ orderByExp sourceName remoteTableInfo perms
|
otherTableParser <- lift $ orderByExp sourceName remoteTableInfo perms
|
||||||
@ -72,7 +73,33 @@ orderByExp sourceName tableInfo selectPermissions = memoizeOn 'orderByExp (sourc
|
|||||||
pure $ do
|
pure $ do
|
||||||
aggregationOrderBy <- join <$> P.fieldOptional aggregateFieldName Nothing (P.nullable aggregationParser)
|
aggregationOrderBy <- join <$> P.fieldOptional aggregateFieldName Nothing (P.nullable aggregationParser)
|
||||||
pure $ fmap (map $ fmap $ IR.AOCArrayAggregation relationshipInfo newPerms) aggregationOrderBy
|
pure $ fmap (map $ fmap $ IR.AOCArrayAggregation relationshipInfo newPerms) aggregationOrderBy
|
||||||
FIComputedField _ -> empty
|
|
||||||
|
FIComputedField ComputedFieldInfo{..} -> do
|
||||||
|
let ComputedFieldFunction{..} = _cfiFunction
|
||||||
|
mkComputedFieldOrderBy =
|
||||||
|
let functionArgs = flip IR.FunctionArgsExp mempty
|
||||||
|
$ IR.functionArgsWithTableRowAndSession P.UVSession _cffTableArgument _cffSessionArgument
|
||||||
|
in IR.ComputedFieldOrderBy _cfiXComputedFieldInfo _cfiName _cffName functionArgs
|
||||||
|
fieldName <- hoistMaybe $ G.mkName $ toTxt _cfiName
|
||||||
|
guard $ _cffInputArgs == mempty -- No input arguments other than table row and session argument
|
||||||
|
case _cfiReturnType of
|
||||||
|
CFRScalar scalarType -> do
|
||||||
|
let computedFieldOrderBy = mkComputedFieldOrderBy $ IR.CFOBEScalar scalarType
|
||||||
|
pure $ P.fieldOptional fieldName Nothing (orderByOperator @b)
|
||||||
|
<&> fmap (pure . mkOrderByItemG @b (IR.AOCComputedField computedFieldOrderBy)) . join
|
||||||
|
CFRSetofTable table -> do
|
||||||
|
let aggregateFieldName = fieldName <> $$(G.litName "_aggregate")
|
||||||
|
tableInfo' <- askTableInfo @b sourceName table
|
||||||
|
perms <- MaybeT $ tableSelectPermissions tableInfo'
|
||||||
|
let newPerms = fmap partialSQLExpToUnpreparedValue <$> spiFilter perms
|
||||||
|
aggregationParser <- lift $ orderByAggregation sourceName tableInfo' perms
|
||||||
|
pure $ do
|
||||||
|
aggregationOrderBy <- join <$> P.fieldOptional aggregateFieldName Nothing (P.nullable aggregationParser)
|
||||||
|
pure $ fmap (map $ fmap $ IR.AOCComputedField
|
||||||
|
. mkComputedFieldOrderBy
|
||||||
|
. IR.CFOBETableAggregation table newPerms
|
||||||
|
) aggregationOrderBy
|
||||||
|
|
||||||
FIRemoteRelationship _ -> empty
|
FIRemoteRelationship _ -> empty
|
||||||
|
|
||||||
|
|
||||||
@ -85,7 +112,7 @@ orderByAggregation
|
|||||||
=> SourceName
|
=> SourceName
|
||||||
-> TableInfo b
|
-> TableInfo b
|
||||||
-> SelPermInfo b
|
-> SelPermInfo b
|
||||||
-> m (Parser 'Input n [IR.OrderByItemG b (IR.AnnAggregateOrderBy b)])
|
-> m (Parser 'Input n [IR.OrderByItemG b (IR.AnnotatedAggregateOrderBy b)])
|
||||||
orderByAggregation sourceName tableInfo selectPermissions = memoizeOn 'orderByAggregation (sourceName, tableName) do
|
orderByAggregation sourceName tableInfo selectPermissions = memoizeOn 'orderByAggregation (sourceName, tableName) do
|
||||||
-- WIP NOTE
|
-- WIP NOTE
|
||||||
-- there is heavy duplication between this and Select.tableAggregationFields
|
-- there is heavy duplication between this and Select.tableAggregationFields
|
||||||
@ -125,7 +152,7 @@ orderByAggregation sourceName tableInfo selectPermissions = memoizeOn 'orderByAg
|
|||||||
:: G.Name
|
:: G.Name
|
||||||
-> G.Name
|
-> G.Name
|
||||||
-> InputFieldsParser n [(ColumnInfo b, (BasicOrderType b, NullsOrderType b))]
|
-> InputFieldsParser n [(ColumnInfo b, (BasicOrderType b, NullsOrderType b))]
|
||||||
-> InputFieldsParser n (Maybe [IR.OrderByItemG b (IR.AnnAggregateOrderBy b)])
|
-> InputFieldsParser n (Maybe [IR.OrderByItemG b (IR.AnnotatedAggregateOrderBy b)])
|
||||||
parseOperator operator tableGQLName columns =
|
parseOperator operator tableGQLName columns =
|
||||||
let opText = G.unName operator
|
let opText = G.unName operator
|
||||||
objectName = tableGQLName <> $$(G.litName "_") <> operator <> $$(G.litName "_order_by")
|
objectName = tableGQLName <> $$(G.litName "_") <> operator <> $$(G.litName "_order_by")
|
||||||
|
@ -625,7 +625,7 @@ tableOrderByArg
|
|||||||
=> SourceName
|
=> SourceName
|
||||||
-> TableInfo b
|
-> TableInfo b
|
||||||
-> SelPermInfo b
|
-> SelPermInfo b
|
||||||
-> m (InputFieldsParser n (Maybe (NonEmpty (IR.AnnOrderByItemG b (UnpreparedValue b)))))
|
-> m (InputFieldsParser n (Maybe (NonEmpty (IR.AnnotatedOrderByItemG b (UnpreparedValue b)))))
|
||||||
tableOrderByArg sourceName tableInfo selectPermissions = do
|
tableOrderByArg sourceName tableInfo selectPermissions = do
|
||||||
orderByParser <- orderByExp sourceName tableInfo selectPermissions
|
orderByParser <- orderByExp sourceName tableInfo selectPermissions
|
||||||
pure $ do
|
pure $ do
|
||||||
@ -738,7 +738,7 @@ tableConnectionArgs pkeyColumns sourceName tableInfo selectPermissions = do
|
|||||||
where
|
where
|
||||||
base64Text = base64Decode <$> P.string
|
base64Text = base64Decode <$> P.string
|
||||||
|
|
||||||
appendPrimaryKeyOrderBy :: NonEmpty (IR.AnnOrderByItemG b v) -> NonEmpty (IR.AnnOrderByItemG b v)
|
appendPrimaryKeyOrderBy :: NonEmpty (IR.AnnotatedOrderByItemG b v) -> NonEmpty (IR.AnnotatedOrderByItemG b v)
|
||||||
appendPrimaryKeyOrderBy orderBys@(h NE.:| t) =
|
appendPrimaryKeyOrderBy orderBys@(h NE.:| t) =
|
||||||
let orderByColumnNames =
|
let orderByColumnNames =
|
||||||
orderBys ^.. traverse . to IR.obiColumn . IR._AOCColumn . to pgiColumn
|
orderBys ^.. traverse . to IR.obiColumn . IR._AOCColumn . to pgiColumn
|
||||||
@ -748,7 +748,7 @@ tableConnectionArgs pkeyColumns sourceName tableInfo selectPermissions = do
|
|||||||
in h NE.:| (t <> pkeyOrderBys)
|
in h NE.:| (t <> pkeyOrderBys)
|
||||||
|
|
||||||
parseConnectionSplit
|
parseConnectionSplit
|
||||||
:: Maybe (NonEmpty (IR.AnnOrderByItemG b (UnpreparedValue b)))
|
:: Maybe (NonEmpty (IR.AnnotatedOrderByItemG b (UnpreparedValue b)))
|
||||||
-> IR.ConnectionSplitKind
|
-> IR.ConnectionSplitKind
|
||||||
-> BL.ByteString
|
-> BL.ByteString
|
||||||
-> n (NonEmpty (IR.ConnectionSplit b (UnpreparedValue b)))
|
-> n (NonEmpty (IR.ConnectionSplit b (UnpreparedValue b)))
|
||||||
@ -774,11 +774,15 @@ tableConnectionArgs pkeyColumns sourceName tableInfo selectPermissions = do
|
|||||||
pgValue <- liftQErr $ parseScalarValueColumnType columnType orderByItemValue
|
pgValue <- liftQErr $ parseScalarValueColumnType columnType orderByItemValue
|
||||||
let unresolvedValue = UVParameter Nothing $ ColumnValue columnType pgValue
|
let unresolvedValue = UVParameter Nothing $ ColumnValue columnType pgValue
|
||||||
pure $ IR.ConnectionSplit splitKind unresolvedValue $
|
pure $ IR.ConnectionSplit splitKind unresolvedValue $
|
||||||
IR.OrderByItemG orderType (() <$ annObCol) nullsOrder
|
IR.OrderByItemG orderType annObCol nullsOrder
|
||||||
where
|
where
|
||||||
throwInvalidCursor = parseError "the \"after\" or \"before\" cursor is invalid"
|
throwInvalidCursor = parseError "the \"after\" or \"before\" cursor is invalid"
|
||||||
liftQErr = either (parseError . qeError) pure . runExcept
|
liftQErr = either (parseError . qeError) pure . runExcept
|
||||||
|
|
||||||
|
mkAggregateOrderByPath = \case
|
||||||
|
IR.AAOCount -> [J.Key "count"]
|
||||||
|
IR.AAOOp t col -> [J.Key t, J.Key $ toTxt $ pgiColumn col]
|
||||||
|
|
||||||
getPathFromOrderBy = \case
|
getPathFromOrderBy = \case
|
||||||
IR.AOCColumn pgColInfo ->
|
IR.AOCColumn pgColInfo ->
|
||||||
let pathElement = J.Key $ toTxt $ pgiColumn pgColInfo
|
let pathElement = J.Key $ toTxt $ pgiColumn pgColInfo
|
||||||
@ -788,15 +792,24 @@ tableConnectionArgs pkeyColumns sourceName tableInfo selectPermissions = do
|
|||||||
in pathElement : getPathFromOrderBy obCol
|
in pathElement : getPathFromOrderBy obCol
|
||||||
IR.AOCArrayAggregation relInfo _ aggOb ->
|
IR.AOCArrayAggregation relInfo _ aggOb ->
|
||||||
let fieldName = J.Key $ relNameToTxt (riName relInfo) <> "_aggregate"
|
let fieldName = J.Key $ relNameToTxt (riName relInfo) <> "_aggregate"
|
||||||
in fieldName : case aggOb of
|
in fieldName : mkAggregateOrderByPath aggOb
|
||||||
IR.AAOCount -> [J.Key "count"]
|
IR.AOCComputedField cfob ->
|
||||||
IR.AAOOp t col -> [J.Key t, J.Key $ toTxt $ pgiColumn col]
|
let fieldNameText = computedFieldNameToText $ IR._cfobName cfob
|
||||||
|
in case IR._cfobOrderByElement cfob of
|
||||||
|
IR.CFOBEScalar _ -> [J.Key fieldNameText]
|
||||||
|
IR.CFOBETableAggregation _ _ aggOb ->
|
||||||
|
J.Key (fieldNameText <> "_aggregate") : mkAggregateOrderByPath aggOb
|
||||||
|
|
||||||
getOrderByColumnType = \case
|
getOrderByColumnType = \case
|
||||||
IR.AOCColumn pgColInfo -> pgiType pgColInfo
|
IR.AOCColumn pgColInfo -> pgiType pgColInfo
|
||||||
IR.AOCObjectRelation _ _ obCol -> getOrderByColumnType obCol
|
IR.AOCObjectRelation _ _ obCol -> getOrderByColumnType obCol
|
||||||
IR.AOCArrayAggregation _ _ aggOb ->
|
IR.AOCArrayAggregation _ _ aggOb -> aggregateOrderByColumnType aggOb
|
||||||
case aggOb of
|
IR.AOCComputedField cfob ->
|
||||||
|
case IR._cfobOrderByElement cfob of
|
||||||
|
IR.CFOBEScalar scalarType -> ColumnScalar scalarType
|
||||||
|
IR.CFOBETableAggregation _ _ aggOb -> aggregateOrderByColumnType aggOb
|
||||||
|
where
|
||||||
|
aggregateOrderByColumnType = \case
|
||||||
IR.AAOCount -> ColumnScalar (aggregateOrderByCountType @b)
|
IR.AAOCount -> ColumnScalar (aggregateOrderByCountType @b)
|
||||||
IR.AAOOp _ colInfo -> pgiType colInfo
|
IR.AAOOp _ colInfo -> pgiType colInfo
|
||||||
|
|
||||||
@ -1311,7 +1324,7 @@ functionArgs functionTrackedAs (toList -> inputArgs) = do
|
|||||||
|
|
||||||
tablePermissionsInfo :: Backend b => SelPermInfo b -> TablePerms b
|
tablePermissionsInfo :: Backend b => SelPermInfo b -> TablePerms b
|
||||||
tablePermissionsInfo selectPermissions = IR.TablePerm
|
tablePermissionsInfo selectPermissions = IR.TablePerm
|
||||||
{ IR._tpFilter = (fmap . fmap) partialSQLExpToUnpreparedValue $ spiFilter selectPermissions
|
{ IR._tpFilter = fmap partialSQLExpToUnpreparedValue <$> spiFilter selectPermissions
|
||||||
, IR._tpLimit = spiLimit selectPermissions
|
, IR._tpLimit = spiLimit selectPermissions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ convSelCol
|
|||||||
-> SelCol
|
-> SelCol
|
||||||
-> m [ExtCol ('Postgres 'Vanilla)]
|
-> m [ExtCol ('Postgres 'Vanilla)]
|
||||||
convSelCol _ _ (SCExtSimple cn) =
|
convSelCol _ _ (SCExtSimple cn) =
|
||||||
return [ECSimple cn]
|
pure [ECSimple cn]
|
||||||
convSelCol fieldInfoMap _ (SCExtRel rn malias selQ) = do
|
convSelCol fieldInfoMap _ (SCExtRel rn malias selQ) = do
|
||||||
-- Point to the name key
|
-- Point to the name key
|
||||||
let pgWhenRelErr = "only relationships can be expanded"
|
let pgWhenRelErr = "only relationships can be expanded"
|
||||||
@ -56,7 +56,7 @@ convSelCol fieldInfoMap _ (SCExtRel rn malias selQ) = do
|
|||||||
let (RelInfo _ _ _ relTab _ _ _) = relInfo
|
let (RelInfo _ _ _ relTab _ _ _) = relInfo
|
||||||
(rfim, rspi) <- fetchRelDet rn relTab
|
(rfim, rspi) <- fetchRelDet rn relTab
|
||||||
resolvedSelQ <- resolveStar rfim rspi selQ
|
resolvedSelQ <- resolveStar rfim rspi selQ
|
||||||
return [ECRel rn malias resolvedSelQ]
|
pure [ECRel rn malias resolvedSelQ]
|
||||||
convSelCol fieldInfoMap spi (SCStar wildcard) =
|
convSelCol fieldInfoMap spi (SCStar wildcard) =
|
||||||
convWildcard fieldInfoMap spi wildcard
|
convWildcard fieldInfoMap spi wildcard
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ convWildcard
|
|||||||
-> m [ExtCol ('Postgres 'Vanilla)]
|
-> m [ExtCol ('Postgres 'Vanilla)]
|
||||||
convWildcard fieldInfoMap selPermInfo wildcard =
|
convWildcard fieldInfoMap selPermInfo wildcard =
|
||||||
case wildcard of
|
case wildcard of
|
||||||
Star -> return simpleCols
|
Star -> pure simpleCols
|
||||||
(StarDot wc) -> (simpleCols ++) <$> (catMaybes <$> relExtCols wc)
|
(StarDot wc) -> (simpleCols ++) <$> (catMaybes <$> relExtCols wc)
|
||||||
where
|
where
|
||||||
cols = spiCols selPermInfo
|
cols = spiCols selPermInfo
|
||||||
@ -85,7 +85,7 @@ convWildcard fieldInfoMap selPermInfo wildcard =
|
|||||||
|
|
||||||
forM mRelSelPerm $ \relSelPermInfo -> do
|
forM mRelSelPerm $ \relSelPermInfo -> do
|
||||||
rExtCols <- convWildcard (_tciFieldInfoMap $ _tiCoreInfo relTabInfo) relSelPermInfo wc
|
rExtCols <- convWildcard (_tciFieldInfoMap $ _tiCoreInfo relTabInfo) relSelPermInfo wc
|
||||||
return $ ECRel relName Nothing $
|
pure $ ECRel relName Nothing $
|
||||||
SelectG rExtCols Nothing Nothing Nothing Nothing
|
SelectG rExtCols Nothing Nothing Nothing Nothing
|
||||||
|
|
||||||
relExtCols wc = mapM (mkRelCol wc) relColInfos
|
relExtCols wc = mapM (mkRelCol wc) relColInfos
|
||||||
@ -99,13 +99,13 @@ resolveStar
|
|||||||
resolveStar fim selPermInfo (SelectG selCols mWh mOb mLt mOf) = do
|
resolveStar fim selPermInfo (SelectG selCols mWh mOb mLt mOf) = do
|
||||||
procOverrides <- fmap (concat . catMaybes) $ withPathK "columns" $
|
procOverrides <- fmap (concat . catMaybes) $ withPathK "columns" $
|
||||||
indexedForM selCols $ \selCol -> case selCol of
|
indexedForM selCols $ \selCol -> case selCol of
|
||||||
(SCStar _) -> return Nothing
|
(SCStar _) -> pure Nothing
|
||||||
_ -> Just <$> convSelCol fim selPermInfo selCol
|
_ -> Just <$> convSelCol fim selPermInfo selCol
|
||||||
everything <- case wildcards of
|
everything <- case wildcards of
|
||||||
[] -> return []
|
[] -> pure []
|
||||||
_ -> convWildcard fim selPermInfo $ maximum wildcards
|
_ -> convWildcard fim selPermInfo $ maximum wildcards
|
||||||
let extCols = unionBy equals procOverrides everything
|
let extCols = unionBy equals procOverrides everything
|
||||||
return $ SelectG extCols mWh mOb mLt mOf
|
pure $ SelectG extCols mWh mOb mLt mOf
|
||||||
where
|
where
|
||||||
wildcards = lefts $ map mkEither selCols
|
wildcards = lefts $ map mkEither selCols
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ convOrderByElem
|
|||||||
=> SessVarBldr ('Postgres 'Vanilla) m
|
=> SessVarBldr ('Postgres 'Vanilla) m
|
||||||
-> (FieldInfoMap (FieldInfo ('Postgres 'Vanilla)), SelPermInfo ('Postgres 'Vanilla))
|
-> (FieldInfoMap (FieldInfo ('Postgres 'Vanilla)), SelPermInfo ('Postgres 'Vanilla))
|
||||||
-> OrderByCol
|
-> OrderByCol
|
||||||
-> m (AnnOrderByElement ('Postgres 'Vanilla) S.SQLExp)
|
-> m (AnnotatedOrderByElement ('Postgres 'Vanilla) S.SQLExp)
|
||||||
convOrderByElem sessVarBldr (flds, spi) = \case
|
convOrderByElem sessVarBldr (flds, spi) = \case
|
||||||
OCPG fldName -> do
|
OCPG fldName -> do
|
||||||
fldInfo <- askFieldInfo flds fldName
|
fldInfo <- askFieldInfo flds fldName
|
||||||
@ -134,7 +134,7 @@ convOrderByElem sessVarBldr (flds, spi) = \case
|
|||||||
[ fldName <<> " has type 'geometry'"
|
[ fldName <<> " has type 'geometry'"
|
||||||
, " and cannot be used in order_by"
|
, " and cannot be used in order_by"
|
||||||
]
|
]
|
||||||
else return $ AOCColumn colInfo
|
else pure $ AOCColumn colInfo
|
||||||
FIRelationship _ -> throw400 UnexpectedPayload $ mconcat
|
FIRelationship _ -> throw400 UnexpectedPayload $ mconcat
|
||||||
[ fldName <<> " is a"
|
[ fldName <<> " is a"
|
||||||
, " relationship and should be expanded"
|
, " relationship and should be expanded"
|
||||||
@ -165,8 +165,7 @@ convOrderByElem sessVarBldr (flds, spi) = \case
|
|||||||
]
|
]
|
||||||
(relFim, relSelPermInfo) <- fetchRelDet (riName relInfo) (riRTable relInfo)
|
(relFim, relSelPermInfo) <- fetchRelDet (riName relInfo) (riRTable relInfo)
|
||||||
resolvedSelFltr <- convAnnBoolExpPartialSQL sessVarBldr $ spiFilter relSelPermInfo
|
resolvedSelFltr <- convAnnBoolExpPartialSQL sessVarBldr $ spiFilter relSelPermInfo
|
||||||
AOCObjectRelation relInfo resolvedSelFltr <$>
|
AOCObjectRelation relInfo resolvedSelFltr <$> convOrderByElem sessVarBldr (relFim, relSelPermInfo) rest
|
||||||
convOrderByElem sessVarBldr (relFim, relSelPermInfo) rest
|
|
||||||
FIRemoteRelationship {} ->
|
FIRemoteRelationship {} ->
|
||||||
throw400 UnexpectedPayload (mconcat [ fldName <<> " is a remote field" ])
|
throw400 UnexpectedPayload (mconcat [ fldName <<> " is a remote field" ])
|
||||||
|
|
||||||
@ -195,11 +194,11 @@ convSelectQ table fieldInfoMap selPermInfo selQ sessVarBldr prepValBldr = do
|
|||||||
(colInfo, caseBoolExpMaybe) <- convExtSimple fieldInfoMap selPermInfo pgCol
|
(colInfo, caseBoolExpMaybe) <- convExtSimple fieldInfoMap selPermInfo pgCol
|
||||||
resolvedCaseBoolExp <-
|
resolvedCaseBoolExp <-
|
||||||
traverse (convAnnColumnCaseBoolExpPartialSQL sessVarBldr) caseBoolExpMaybe
|
traverse (convAnnColumnCaseBoolExpPartialSQL sessVarBldr) caseBoolExpMaybe
|
||||||
return (fromCol @('Postgres 'Vanilla) pgCol, mkAnnColumnField colInfo resolvedCaseBoolExp Nothing)
|
pure (fromCol @('Postgres 'Vanilla) pgCol, mkAnnColumnField colInfo resolvedCaseBoolExp Nothing)
|
||||||
(ECRel relName mAlias relSelQ) -> do
|
(ECRel relName mAlias relSelQ) -> do
|
||||||
annRel <- convExtRel fieldInfoMap relName mAlias
|
annRel <- convExtRel fieldInfoMap relName mAlias
|
||||||
relSelQ sessVarBldr prepValBldr
|
relSelQ sessVarBldr prepValBldr
|
||||||
return ( fromRel $ fromMaybe relName mAlias
|
pure ( fromRel $ fromMaybe relName mAlias
|
||||||
, either AFObjectRelation AFArrayRelation annRel
|
, either AFObjectRelation AFArrayRelation annRel
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -221,7 +220,7 @@ convSelectQ table fieldInfoMap selPermInfo selQ sessVarBldr prepValBldr = do
|
|||||||
tabArgs = SelectArgs wClause annOrdByM mQueryLimit (fromIntegral <$> mQueryOffset) Nothing
|
tabArgs = SelectArgs wClause annOrdByM mQueryLimit (fromIntegral <$> mQueryOffset) Nothing
|
||||||
|
|
||||||
strfyNum <- stringifyNum . _sccSQLGenCtx <$> askServerConfigCtx
|
strfyNum <- stringifyNum . _sccSQLGenCtx <$> askServerConfigCtx
|
||||||
return $ AnnSelectG annFlds tabFrom tabPerm tabArgs strfyNum
|
pure $ AnnSelectG annFlds tabFrom tabPerm tabArgs strfyNum
|
||||||
|
|
||||||
where
|
where
|
||||||
mQueryOffset = sqOffset selQ
|
mQueryOffset = sqOffset selQ
|
||||||
@ -264,10 +263,10 @@ convExtRel fieldInfoMap relName mAlias selQ sessVarBldr prepValBldr = do
|
|||||||
case relTy of
|
case relTy of
|
||||||
ObjRel -> do
|
ObjRel -> do
|
||||||
when misused $ throw400 UnexpectedPayload objRelMisuseMsg
|
when misused $ throw400 UnexpectedPayload objRelMisuseMsg
|
||||||
return $ Left $ AnnRelationSelectG (fromMaybe relName mAlias) colMapping $
|
pure $ Left $ AnnRelationSelectG (fromMaybe relName mAlias) colMapping $
|
||||||
AnnObjectSelectG (_asnFields annSel) relTab $ _tpFilter $ _asnPerm annSel
|
AnnObjectSelectG (_asnFields annSel) relTab $ _tpFilter $ _asnPerm annSel
|
||||||
ArrRel ->
|
ArrRel ->
|
||||||
return $ Right $ ASSimple $ AnnRelationSelectG (fromMaybe relName mAlias)
|
pure $ Right $ ASSimple $ AnnRelationSelectG (fromMaybe relName mAlias)
|
||||||
colMapping annSel
|
colMapping annSel
|
||||||
where
|
where
|
||||||
pgWhenRelErr = "only relationships can be expanded"
|
pgWhenRelErr = "only relationships can be expanded"
|
||||||
|
@ -96,9 +96,9 @@ data ConnectionSplit (b :: BackendType) v
|
|||||||
= ConnectionSplit
|
= ConnectionSplit
|
||||||
{ _csKind :: !ConnectionSplitKind
|
{ _csKind :: !ConnectionSplitKind
|
||||||
, _csValue :: !v
|
, _csValue :: !v
|
||||||
, _csOrderBy :: !(OrderByItemG b (AnnOrderByElementG b ()))
|
, _csOrderBy :: !(OrderByItemG b (AnnotatedOrderByElement b v))
|
||||||
} deriving (Functor, Generic, Foldable, Traversable)
|
} deriving (Functor, Generic, Foldable, Traversable)
|
||||||
instance (Backend b, Hashable (ColumnInfo b), Hashable v) => Hashable (ConnectionSplit b v)
|
instance (Backend b, Hashable (ColumnInfo b), Hashable v, Hashable (BooleanOperators b v)) => Hashable (ConnectionSplit b v)
|
||||||
|
|
||||||
data ConnectionSlice
|
data ConnectionSlice
|
||||||
= SliceFirst !Int
|
= SliceFirst !Int
|
||||||
@ -133,7 +133,7 @@ type SelectFrom b = SelectFromG b (SQLExpression b)
|
|||||||
data SelectArgsG (b :: BackendType) v
|
data SelectArgsG (b :: BackendType) v
|
||||||
= SelectArgs
|
= SelectArgs
|
||||||
{ _saWhere :: !(Maybe (AnnBoolExp b v))
|
{ _saWhere :: !(Maybe (AnnBoolExp b v))
|
||||||
, _saOrderBy :: !(Maybe (NE.NonEmpty (AnnOrderByItemG b v)))
|
, _saOrderBy :: !(Maybe (NE.NonEmpty (AnnotatedOrderByItemG b v)))
|
||||||
, _saLimit :: !(Maybe Int)
|
, _saLimit :: !(Maybe Int)
|
||||||
, _saOffset :: !(Maybe Int64)
|
, _saOffset :: !(Maybe Int64)
|
||||||
, _saDistinct :: !(Maybe (NE.NonEmpty (Column b)))
|
, _saDistinct :: !(Maybe (NE.NonEmpty (Column b)))
|
||||||
@ -159,24 +159,51 @@ noSelectArgs = SelectArgs Nothing Nothing Nothing Nothing Nothing
|
|||||||
|
|
||||||
-- Order by argument
|
-- Order by argument
|
||||||
|
|
||||||
data AnnOrderByElementG (b :: BackendType) v
|
-- | The order by element for a computed field based on its return type
|
||||||
= AOCColumn !(ColumnInfo b)
|
data ComputedFieldOrderByElement (b :: BackendType) v
|
||||||
| AOCObjectRelation !(RelInfo b) !v !(AnnOrderByElementG b v)
|
= CFOBEScalar !(ScalarType b)
|
||||||
| AOCArrayAggregation !(RelInfo b) !v !(AnnAggregateOrderBy b)
|
-- ^ Sort by the scalar computed field
|
||||||
|
| CFOBETableAggregation !(TableName b)
|
||||||
|
!(AnnBoolExp b v) -- ^ Permission filter of the retuning table
|
||||||
|
!(AnnotatedAggregateOrderBy b)
|
||||||
|
-- ^ Sort by aggregation fields of table rows returned by computed field
|
||||||
deriving (Generic, Functor, Foldable, Traversable)
|
deriving (Generic, Functor, Foldable, Traversable)
|
||||||
deriving instance (Backend b, Eq v) => Eq (AnnOrderByElementG b v)
|
deriving instance (Backend b, Eq v, Eq (BooleanOperators b v)) => Eq (ComputedFieldOrderByElement b v)
|
||||||
instance (Backend b, Hashable v) => Hashable (AnnOrderByElementG b v)
|
instance (Backend b, Hashable v, Hashable (BooleanOperators b v)) => Hashable (ComputedFieldOrderByElement b v)
|
||||||
|
|
||||||
data AnnAggregateOrderBy (b :: BackendType)
|
data ComputedFieldOrderBy (b :: BackendType) v
|
||||||
|
= ComputedFieldOrderBy
|
||||||
|
{ _cfobXField :: !(XComputedField b)
|
||||||
|
, _cfobName :: !ComputedFieldName
|
||||||
|
, _cfobFunction :: !(FunctionName b)
|
||||||
|
, _cfobFunctionArgsExp :: !(FunctionArgsExpTableRow b v)
|
||||||
|
, _cfobOrderByElement :: !(ComputedFieldOrderByElement b v)
|
||||||
|
} deriving (Generic, Functor, Foldable, Traversable)
|
||||||
|
deriving instance (Backend b, Eq v, Eq (BooleanOperators b v)) => Eq (ComputedFieldOrderBy b v)
|
||||||
|
instance (Backend b, Hashable v, Hashable (BooleanOperators b v)) => Hashable (ComputedFieldOrderBy b v)
|
||||||
|
|
||||||
|
data AnnotatedOrderByElement (b :: BackendType) v
|
||||||
|
= AOCColumn !(ColumnInfo b)
|
||||||
|
| AOCObjectRelation !(RelInfo b)
|
||||||
|
!(AnnBoolExp b v) -- ^ Permission filter of the remote table to which the relationship is defined
|
||||||
|
!(AnnotatedOrderByElement b v)
|
||||||
|
| AOCArrayAggregation !(RelInfo b)
|
||||||
|
!(AnnBoolExp b v) -- ^ Permission filter of the remote table to which the relationship is defined
|
||||||
|
!(AnnotatedAggregateOrderBy b)
|
||||||
|
| AOCComputedField !(ComputedFieldOrderBy b v)
|
||||||
|
deriving (Generic, Functor, Foldable, Traversable)
|
||||||
|
deriving instance (Backend b, Eq v, Eq (BooleanOperators b v)) => Eq (AnnotatedOrderByElement b v)
|
||||||
|
instance (Backend b, Hashable v, Hashable (BooleanOperators b v)) => Hashable (AnnotatedOrderByElement b v)
|
||||||
|
|
||||||
|
data AnnotatedAggregateOrderBy (b :: BackendType)
|
||||||
= AAOCount
|
= AAOCount
|
||||||
| AAOOp !Text !(ColumnInfo b)
|
| AAOOp !Text !(ColumnInfo b)
|
||||||
deriving (Generic)
|
deriving (Generic)
|
||||||
deriving instance (Backend b) => Eq (AnnAggregateOrderBy b)
|
deriving instance (Backend b) => Eq (AnnotatedAggregateOrderBy b)
|
||||||
instance (Backend b) => Hashable (AnnAggregateOrderBy b)
|
instance (Backend b) => Hashable (AnnotatedAggregateOrderBy b)
|
||||||
|
|
||||||
type AnnOrderByElement b v = AnnOrderByElementG b (AnnBoolExp b v)
|
type AnnotatedOrderByItemG b v = OrderByItemG b (AnnotatedOrderByElement b v)
|
||||||
type AnnOrderByItemG b v = OrderByItemG b (AnnOrderByElement b v)
|
type AnnotatedOrderByItem b = AnnotatedOrderByItemG b (SQLExpression b)
|
||||||
type AnnOrderByItem b = AnnOrderByItemG b (SQLExpression b)
|
|
||||||
|
|
||||||
|
|
||||||
-- Fields
|
-- Fields
|
||||||
@ -466,6 +493,17 @@ type FunctionArgExp b = FunctionArgsExpG (SQLExpression b)
|
|||||||
emptyFunctionArgsExp :: FunctionArgsExpG a
|
emptyFunctionArgsExp :: FunctionArgsExpG a
|
||||||
emptyFunctionArgsExp = FunctionArgsExp [] HM.empty
|
emptyFunctionArgsExp = FunctionArgsExp [] HM.empty
|
||||||
|
|
||||||
|
functionArgsWithTableRowAndSession
|
||||||
|
:: v
|
||||||
|
-> FunctionTableArgument
|
||||||
|
-> Maybe FunctionSessionArgument
|
||||||
|
-> [ArgumentExp b v]
|
||||||
|
functionArgsWithTableRowAndSession _ _ Nothing = [AETableRow Nothing] -- No session argument
|
||||||
|
functionArgsWithTableRowAndSession sess (FTAFirst) _ = [AETableRow Nothing, AESession sess]
|
||||||
|
functionArgsWithTableRowAndSession sess (FTANamed _ 0) _ = [AETableRow Nothing, AESession sess] -- Index is 0 implies table argument is first
|
||||||
|
functionArgsWithTableRowAndSession sess _ _ = [AESession sess, AETableRow Nothing]
|
||||||
|
|
||||||
|
|
||||||
-- | If argument positional index is less than or equal to length of
|
-- | If argument positional index is less than or equal to length of
|
||||||
-- 'positional' arguments then insert the value in 'positional' arguments else
|
-- 'positional' arguments then insert the value in 'positional' arguments else
|
||||||
-- insert the value with argument name in 'named' arguments
|
-- insert the value with argument name in 'named' arguments
|
||||||
@ -488,4 +526,4 @@ insertFunctionArg argName idx value (FunctionArgsExp positional named) =
|
|||||||
|
|
||||||
$(makeLenses ''AnnSelectG)
|
$(makeLenses ''AnnSelectG)
|
||||||
$(makePrisms ''AnnFieldG)
|
$(makePrisms ''AnnFieldG)
|
||||||
$(makePrisms ''AnnOrderByElementG)
|
$(makePrisms ''AnnotatedOrderByElement)
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
description: Fetch tracks order by their size which is a computed field
|
||||||
|
url: /v1/graphql
|
||||||
|
status: 200
|
||||||
|
query:
|
||||||
|
query: |
|
||||||
|
query {
|
||||||
|
Track(order_by: {size: desc}, limit: 2){
|
||||||
|
name
|
||||||
|
bytes
|
||||||
|
size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response:
|
||||||
|
data:
|
||||||
|
Track:
|
||||||
|
- name: Restless
|
||||||
|
bytes: 9836284
|
||||||
|
size: 9
|
||||||
|
- name: Mistress
|
||||||
|
bytes: 7521946
|
||||||
|
size: 7
|
@ -0,0 +1,31 @@
|
|||||||
|
description: Fetch author with order by using computed field aggregate returns set of articles with a search query via session variable
|
||||||
|
url: /v1/graphql
|
||||||
|
status: 200
|
||||||
|
headers:
|
||||||
|
X-Hasura-Role: admin
|
||||||
|
X-Hasura-Search: '1'
|
||||||
|
query:
|
||||||
|
query: |
|
||||||
|
query{
|
||||||
|
author(order_by: {get_articles_aggregate: {count: desc}}){
|
||||||
|
id
|
||||||
|
name
|
||||||
|
get_articles{
|
||||||
|
id
|
||||||
|
title
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response:
|
||||||
|
data:
|
||||||
|
author:
|
||||||
|
- id: 1
|
||||||
|
name: Author 1
|
||||||
|
get_articles:
|
||||||
|
- id: 1
|
||||||
|
title: Article 1
|
||||||
|
content: Sample article content 1
|
||||||
|
- id: 2
|
||||||
|
name: Author 2
|
||||||
|
get_articles: []
|
@ -11,11 +11,13 @@ args:
|
|||||||
phone INTEGER,
|
phone INTEGER,
|
||||||
address TEXT
|
address TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
create table author(
|
create table author(
|
||||||
id serial primary key,
|
id serial primary key,
|
||||||
name text unique,
|
name text unique,
|
||||||
contact_id INTEGER REFERENCES contact(id)
|
contact_id INTEGER REFERENCES contact(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE article (
|
CREATE TABLE article (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
title TEXT,
|
title TEXT,
|
||||||
@ -24,14 +26,27 @@ args:
|
|||||||
is_published BOOLEAN,
|
is_published BOOLEAN,
|
||||||
published_on TIMESTAMP
|
published_on TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE FUNCTION get_articles(hasura_session json, author_row author)
|
||||||
|
RETURNS SETOF article AS $$
|
||||||
|
SELECT *
|
||||||
|
FROM article
|
||||||
|
WHERE author_id = author_row.id AND
|
||||||
|
( title ilike ('%' || (hasura_session ->> 'x-hasura-search') || '%')
|
||||||
|
OR content ilike ('%' || (hasura_session ->> 'x-hasura-search') || '%')
|
||||||
|
)
|
||||||
|
$$ LANGUAGE SQL STABLE;
|
||||||
|
|
||||||
insert into contact (phone)
|
insert into contact (phone)
|
||||||
values
|
values
|
||||||
(1234567890),
|
(1234567890),
|
||||||
(1234567891);
|
(1234567891);
|
||||||
|
|
||||||
insert into author (name, contact_id)
|
insert into author (name, contact_id)
|
||||||
values
|
values
|
||||||
('Author 1', 2),
|
('Author 1', 2),
|
||||||
('Author 2', 1);
|
('Author 2', 1);
|
||||||
|
|
||||||
insert into article (title,content,author_id,is_published)
|
insert into article (title,content,author_id,is_published)
|
||||||
values
|
values
|
||||||
(
|
(
|
||||||
@ -56,6 +71,7 @@ args:
|
|||||||
album_id INTEGER NOT NULL PRIMARY KEY,
|
album_id INTEGER NOT NULL PRIMARY KEY,
|
||||||
title TEXT NOT NULL
|
title TEXT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "Track" (
|
create table "Track" (
|
||||||
track_id INTEGER NOT NULL PRIMARY KEY,
|
track_id INTEGER NOT NULL PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
@ -63,8 +79,10 @@ args:
|
|||||||
milliseconds INTEGER NOT NULL,
|
milliseconds INTEGER NOT NULL,
|
||||||
bytes INTEGER NOT NULL
|
bytes INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
insert into "Album" (album_id, title)
|
insert into "Album" (album_id, title)
|
||||||
values ( 1, 'Big Ones' ), (2, 'Face Lift');
|
values ( 1, 'Big Ones' ), (2, 'Face Lift');
|
||||||
|
|
||||||
insert into "Track"
|
insert into "Track"
|
||||||
(track_id, name, album_id, milliseconds, bytes)
|
(track_id, name, album_id, milliseconds, bytes)
|
||||||
values
|
values
|
||||||
@ -75,16 +93,24 @@ args:
|
|||||||
( 5, 'Random', 2, 1094732, 6032547) ,
|
( 5, 'Random', 2, 1094732, 6032547) ,
|
||||||
( 6, 'Good One', 2, 346208, 6732987) ,
|
( 6, 'Good One', 2, 346208, 6732987) ,
|
||||||
( 7, 'Mistress', 2, 420985, 7521946);
|
( 7, 'Mistress', 2, 420985, 7521946);
|
||||||
|
|
||||||
|
CREATE FUNCTION track_size_mb(track_row "Track")
|
||||||
|
RETURNS INTEGER AS $$
|
||||||
|
SELECT (track_row.bytes / 1048576)
|
||||||
|
$$ LANGUAGE SQL STABLE;
|
||||||
|
|
||||||
CREATE table "Tag" (
|
CREATE table "Tag" (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
album_id INTEGER NOT NULL REFERENCES "Album"(album_id)
|
album_id INTEGER NOT NULL REFERENCES "Album"(album_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT INTO "Tag" (name, album_id)
|
INSERT INTO "Tag" (name, album_id)
|
||||||
VALUES
|
VALUES
|
||||||
( 'Rock', 1),
|
( 'Rock', 1),
|
||||||
( 'Folk', 1),
|
( 'Folk', 1),
|
||||||
( 'Hip Hop', 2);
|
( 'Hip Hop', 2);
|
||||||
|
|
||||||
CREATE TABLE employee (
|
CREATE TABLE employee (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name TEXT NOT NULL UNIQUE,
|
name TEXT NOT NULL UNIQUE,
|
||||||
@ -109,6 +135,16 @@ args:
|
|||||||
schema: public
|
schema: public
|
||||||
name: article
|
name: article
|
||||||
|
|
||||||
|
# Computed field to author table
|
||||||
|
- type: add_computed_field
|
||||||
|
args:
|
||||||
|
table: author
|
||||||
|
name: get_articles
|
||||||
|
definition:
|
||||||
|
function: get_articles
|
||||||
|
table_argument: author_row
|
||||||
|
session_argument: hasura_session
|
||||||
|
|
||||||
#Object relationship
|
#Object relationship
|
||||||
- type: create_object_relationship
|
- type: create_object_relationship
|
||||||
args:
|
args:
|
||||||
@ -161,6 +197,14 @@ args:
|
|||||||
table: Track
|
table: Track
|
||||||
column: album_id
|
column: album_id
|
||||||
|
|
||||||
|
# Create computed field for Track table
|
||||||
|
- type: add_computed_field
|
||||||
|
args:
|
||||||
|
table: Track
|
||||||
|
name: size
|
||||||
|
definition:
|
||||||
|
function: track_size_mb
|
||||||
|
|
||||||
# Insert values in Album and Track
|
# Insert values in Album and Track
|
||||||
- type: track_table
|
- type: track_table
|
||||||
args:
|
args:
|
||||||
|
@ -3,9 +3,11 @@ args:
|
|||||||
- type: run_sql
|
- type: run_sql
|
||||||
args:
|
args:
|
||||||
sql: |
|
sql: |
|
||||||
|
DROP FUNCTION get_articles(json, author);
|
||||||
DROP TABLE article;
|
DROP TABLE article;
|
||||||
DROP TABLE author;
|
DROP TABLE author;
|
||||||
DROP TABLE contact;
|
DROP TABLE contact;
|
||||||
|
DROP FUNCTION track_size_mb("Track");
|
||||||
DROP TABLE "Track";
|
DROP TABLE "Track";
|
||||||
DROP TABLE "Tag";
|
DROP TABLE "Tag";
|
||||||
DROP TABLE "Album";
|
DROP TABLE "Album";
|
||||||
|
@ -894,6 +894,12 @@ class TestGraphQLQueryOrderBy:
|
|||||||
def test_album_order_by_tracks_tags(self, hge_ctx, transport):
|
def test_album_order_by_tracks_tags(self, hge_ctx, transport):
|
||||||
check_query_f(hge_ctx, self.dir() + '/album_order_by_tracks_tags.yaml', transport)
|
check_query_f(hge_ctx, self.dir() + '/album_order_by_tracks_tags.yaml', transport)
|
||||||
|
|
||||||
|
def test_Track_order_by_size(self, hge_ctx, transport):
|
||||||
|
check_query_f(hge_ctx, self.dir() + '/Track_order_by_size.yaml', transport)
|
||||||
|
|
||||||
|
def test_author_order_by_get_articles_aggregate(self, hge_ctx, transport):
|
||||||
|
check_query_f(hge_ctx, self.dir() + '/author_order_by_get_articles_aggregate.yaml', transport)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def dir(cls):
|
def dir(cls):
|
||||||
return 'queries/graphql_query/order_by'
|
return 'queries/graphql_query/order_by'
|
||||||
|
Loading…
Reference in New Issue
Block a user