这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions docs/graphql/manual/api-reference/query.rst
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,12 @@ or

order_by: [{id: desc}, {author: {id: asc}}]

or

.. parsed-literal::

order_by: {articles_aggregate: {count: asc}}


TableOrderBy
************
Expand All @@ -394,6 +400,11 @@ For object relations:
.. parsed-literal::
{relation-name: TableOrderBy_}

For array relations aggregate:

.. parsed-literal::
{relation-name_aggregate: AggregateOrderBy_}

E.g.

Order by type for "article" table:
Expand All @@ -407,8 +418,34 @@ Order by type for "article" table:
author_id: order_by
#order by using "author" object relationship columns
author: author_order_by
#order by using "likes" array relationship aggregates
likes_aggregate: likes_aggregate_order_by
}

AggregateOrderBy
***************

Count aggregate

.. parsed-literal::
{count: OrderByEnum_}

Operation aggregate

.. parsed-literal::
{op_name: TableAggOpOrderBy_}

Available operations are ``sum``, ``avg``, ``max``, ``min``, ``stddev``, ``stddev_samp``,
``stddev_pop``, ``variance``, ``var_samp`` and ``var_pop``

TableAggOpOrderBy
*****************

.. parsed-literal::
{column: OrderByEnum_}



OrderByEnum
***********

Expand Down
70 changes: 70 additions & 0 deletions docs/graphql/manual/queries/sorting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ The ``order_by`` argument takes an array of objects to allow sorting by multiple
author_id: order_by
#order by using "author" object relationship columns
author: author_order_by
#order by using "likes" array relationship aggregates
likes_aggregate: likes_aggregate_order_by
}

#the likes_aggregate_order_by type
input likes_aggregate_order_by {
count: order_by
op_name: likes_op_name_order_by
}
#Available "op_name"s are 'max', 'min', 'sum', 'avg', 'stddev', 'stddev_samp', 'stddev_pop', 'variance', 'var_samp' and 'var_pop'

#the likes_<op-name>_order_by type
input likes_sum_order_by {
like_id: order_by
}

#the order_by enum type
Expand All @@ -50,8 +64,10 @@ The ``order_by`` argument takes an array of objects to allow sorting by multiple
desc_nulls_last
}


.. Note::
Only columns from **object** relationships are allowed for sorting.
Only aggregates from **array** relationships are allowed for sorting.

The following are example queries for different sorting use cases:

Expand Down Expand Up @@ -238,6 +254,60 @@ Only columns in object relationships are allowed:
}
}

Sorting by array relationship aggregates
---------------------------------------
Fetch a list of authors sorted by their article count.

.. graphiql::
:view_only:
:query:
query {
author(order_by: {articles_aggregate: {count: desc}}) {
id
name
articles_aggregate {
aggregate{
count
}
}
}
}
:response:
{
"data": {
"author": [
{
"id": 5,
"name": "Amii",
"articles_aggregate":{
"aggregate": {
"count": 3
}
}
},
{
"id": 4,
"name": "Anjela",
"articles_aggregate":{
"aggregate": {
"count": 2
}
}
},
{
"id": 8,
"name": "April",
"articles_aggregate":{
"aggregate": {
"count": 2
}
}
}
]
}
}


Sorting by multiple fields
--------------------------
Fetch a list of articles that is sorted by their rating (descending) and then on their published date (ascending with
Expand Down
1 change: 1 addition & 0 deletions server/graphql-engine.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ library
, Hasura.RQL.DML.Insert
, Hasura.RQL.DML.Returning
, Hasura.RQL.DML.Select.Internal
, Hasura.RQL.DML.Select.Types
, Hasura.RQL.DML.Select
, Hasura.RQL.DML.Update
, Hasura.RQL.DML.Count
Expand Down
18 changes: 4 additions & 14 deletions server/src-lib/Hasura/GraphQL/Resolve/BoolExp.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import qualified Data.HashMap.Strict as Map
import qualified Data.HashMap.Strict.InsOrd as OMap
import qualified Language.GraphQL.Draft.Syntax as G

import qualified Hasura.SQL.DML as S

import Hasura.GraphQL.Resolve.Context
import Hasura.GraphQL.Resolve.InputValue
import Hasura.GraphQL.Validate.Types
Expand Down Expand Up @@ -87,12 +85,8 @@ parseAsEqOp annVal = do

parseColExp
:: (MonadError QErr m, MonadReader r m, Has FieldMap r)
=> ((PGColType, PGColValue) -> m S.SQLExp)
-> G.NamedType
-> G.Name
-> AnnGValue
-> (AnnGValue -> m [OpExp])
-> m AnnBoolExpFldSQL
=> PrepFn m -> G.NamedType -> G.Name -> AnnGValue
-> (AnnGValue -> m [OpExp]) -> m AnnBoolExpFldSQL
parseColExp f nt n val expParser = do
fldInfo <- getFldInfo nt n
case fldInfo of
Expand All @@ -105,9 +99,7 @@ parseColExp f nt n val expParser = do

parseBoolExp
:: (MonadError QErr m, MonadReader r m, Has FieldMap r)
=> ((PGColType, PGColValue) -> m S.SQLExp)
-> AnnGValue
-> m AnnBoolExpSQL
=> PrepFn m -> AnnGValue -> m AnnBoolExpSQL
parseBoolExp f annGVal = do
boolExpsM <-
flip withObjectM annGVal
Expand All @@ -124,9 +116,7 @@ type PGColValMap = Map.HashMap G.Name AnnGValue

pgColValToBoolExp
:: (MonadError QErr m, MonadReader r m, Has FieldMap r)
=> ((PGColType, PGColValue) -> m S.SQLExp)
-> PGColValMap
-> m AnnBoolExpSQL
=> PrepFn m -> PGColValMap -> m AnnBoolExpSQL
pgColValToBoolExp f colValMap = do
colExps <- forM colVals $ \(name, val) -> do
(ty, _) <- asPGColVal val
Expand Down
6 changes: 4 additions & 2 deletions server/src-lib/Hasura/GraphQL/Resolve/Context.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module Hasura.GraphQL.Resolve.Context
, InsCtx(..)
, InsCtxMap
, RespTx
, PrepFn
, InsertTxConflictCtx(..)
, getFldInfo
, getPGColInfo
Expand Down Expand Up @@ -73,11 +74,13 @@ $(J.deriveJSON (J.aesonDrop 3 J.snakeCase) ''InsResp)
-- deriving (Show, Eq)

type RespTx = Q.TxE QErr BL.ByteString
type PrepFn m = (PGColType, PGColValue) -> m S.SQLExp

-- -- order by context
-- data OrdByItem
-- = OBIPGCol !PGColInfo
-- | OBIRel !RelInfo !AnnBoolExpSQL
-- | OBIAgg !RelInfo !AnnBoolExpSQL
-- deriving (Show, Eq)

-- type OrdByItemMap = Map.HashMap G.Name OrdByItem
Expand Down Expand Up @@ -163,8 +166,7 @@ type Convert =
StateT PrepArgs (ReaderT (FieldMap, OrdByCtx, InsCtxMap) (Except QErr))

prepare
:: (MonadState PrepArgs m)
=> (PGColType, PGColValue) -> m S.SQLExp
:: (MonadState PrepArgs m) => PrepFn m
prepare (colTy, colVal) = do
preparedArgs <- get
put (preparedArgs Seq.|> binEncoder colVal)
Expand Down
1 change: 1 addition & 0 deletions server/src-lib/Hasura/GraphQL/Resolve/ContextTypes.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type FieldMap
data OrdByItem
= OBIPGCol !PGColInfo
| OBIRel !RelInfo !AnnBoolExpSQL
| OBIAgg !RelInfo !AnnBoolExpSQL
deriving (Show, Eq)

type OrdByItemMap = Map.HashMap G.Name OrdByItem
Expand Down
69 changes: 50 additions & 19 deletions server/src-lib/Hasura/GraphQL/Resolve/Select.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ module Hasura.GraphQL.Resolve.Select
, fromAggField
) where

import Control.Arrow (first)
import Data.Has
import Hasura.Prelude

import qualified Data.HashMap.Strict as Map
import qualified Data.HashMap.Strict.InsOrd as OMap
import qualified Data.List.NonEmpty as NE
import qualified Data.Text as T
import qualified Language.GraphQL.Draft.Syntax as G

import qualified Hasura.RQL.DML.Select as RS
Expand All @@ -49,10 +51,7 @@ withSelSet selSet f =

fromSelSet
:: (MonadError QErr m, MonadReader r m, Has FieldMap r, Has OrdByCtx r)
=> ((PGColType, PGColValue) -> m S.SQLExp)
-> G.NamedType
-> SelSet
-> m [(FieldName, RS.AnnFld)]
=> PrepFn m -> G.NamedType -> SelSet -> m [(FieldName, RS.AnnFld)]
fromSelSet f fldTy flds =
forM (toList flds) $ \fld -> do
let fldName = _fName fld
Expand All @@ -66,23 +65,23 @@ fromSelSet f fldTy flds =
Right (relInfo, isAgg, tableFilter, tableLimit) -> do
let relTN = riRTable relInfo
colMapping = riMapping relInfo
rn = riName relInfo
if isAgg then do
aggSel <- fromAggField f relTN tableFilter tableLimit fld
return $ RS.FAgg $ RS.AggSel colMapping aggSel
return $ RS.FArr $ RS.ASAgg $ RS.AnnRelG rn colMapping aggSel
else do
annSel <- fromField f relTN tableFilter tableLimit fld
let annRel = RS.AnnRel (riName relInfo) (riType relInfo)
colMapping annSel
return $ RS.FRel annRel
let annRel = RS.AnnRelG rn colMapping annSel
return $ case riType relInfo of
ObjRel -> RS.FObj annRel
ArrRel -> RS.FArr $ RS.ASSimple annRel

fieldAsPath :: (MonadError QErr m) => Field -> m a -> m a
fieldAsPath = nameAsPath . _fName


parseTableArgs
:: (MonadError QErr m, MonadReader r m, Has FieldMap r, Has OrdByCtx r)
=> ((PGColType, PGColValue) -> m S.SQLExp)
-> ArgsMap -> m RS.TableArgs
=> PrepFn m -> ArgsMap -> m RS.TableArgs
parseTableArgs f args = do
whereExpM <- withArgM args "where" $ parseBoolExp f
ordByExpML <- withArgM args "order_by" parseOrderBy
Expand Down Expand Up @@ -110,8 +109,8 @@ parseTableArgs f args = do

fromField
:: (MonadError QErr m, MonadReader r m, Has FieldMap r, Has OrdByCtx r)
=> ((PGColType, PGColValue) -> m S.SQLExp)
-> QualifiedTable -> AnnBoolExpSQL -> Maybe Int -> Field -> m RS.AnnSel
=> PrepFn m -> QualifiedTable -> AnnBoolExpSQL
-> Maybe Int -> Field -> m RS.AnnSel
fromField f tn permFilter permLimitM fld =
fieldAsPath fld $ do
tableArgs <- parseTableArgs f args
Expand Down Expand Up @@ -164,10 +163,38 @@ getAnnObItems f nt obj = do
(_, enumVal) <- asEnumVal v
(ordTy, nullsOrd) <- parseOrderByEnum enumVal
return [OrderByItemG (Just ordTy) aobCol (Just nullsOrd)]

OBIRel ri fltr -> do
let annObColFn = f . RS.AOCRel ri fltr
let annObColFn = f . RS.AOCObj ri fltr
withObject (getAnnObItems annObColFn) v

OBIAgg ri fltr -> do
let aobColFn = f . RS.AOCAgg ri fltr
flip withObject v $ \_ o -> parseAggOrdBy aobColFn o

parseAggOrdBy
:: (MonadError QErr m)
=> (RS.AnnAggOrdBy -> RS.AnnObCol)
-> AnnGObject
-> m [RS.AnnOrderByItem]
parseAggOrdBy f annObj =
fmap concat <$> forM (OMap.toList annObj) $ \(op, obVal) ->
case op of
"count" -> do
(ordTy, nullsOrd) <- parseAsEnum obVal
return [OrderByItemG (Just ordTy) (f RS.AAOCount) $ Just nullsOrd]

G.Name opT ->
flip withObject obVal $ \_ opObObj ->
forM (OMap.toList opObObj) $ \(col, eVal) -> do
(ordTy, nullsOrd) <- parseAsEnum eVal
let aobCol = f $ RS.AAOOp opT $ PGCol $ G.unName col
return $ OrderByItemG (Just ordTy) aobCol $ Just nullsOrd
where
parseAsEnum v = do
(_, enumVal) <- asEnumVal v
parseOrderByEnum enumVal

parseOrderByEnum
:: (MonadError QErr m)
=> G.EnumValue
Expand Down Expand Up @@ -244,9 +271,12 @@ convertCount args = do
mkCType isDistinct cols = return $
bool (S.CTSimple cols) (S.CTDistinct cols) isDistinct

toFields :: [(T.Text, a)] -> [(FieldName, a)]
toFields = map (first FieldName)

convertColFlds
:: Monad m => G.NamedType -> SelSet -> m RS.ColFlds
convertColFlds ty selSet =
convertColFlds ty selSet = fmap toFields $
withSelSet selSet $ \fld ->
case _fName fld of
"__typename" -> return $ RS.PCFExp $ G.unName $ G.unNamedType ty
Expand All @@ -255,7 +285,7 @@ convertColFlds ty selSet =
convertAggFld
:: (Monad m, MonadError QErr m)
=> G.NamedType -> SelSet -> m RS.AggFlds
convertAggFld ty selSet =
convertAggFld ty selSet = fmap toFields $
withSelSet selSet $ \fld -> do
let fType = _fType fld
fSelSet = _fSelSet fld
Expand All @@ -272,11 +302,12 @@ convertAggFld ty selSet =

fromAggField
:: (MonadError QErr m, MonadReader r m, Has FieldMap r, Has OrdByCtx r)
=> ((PGColType, PGColValue) -> m S.SQLExp)
-> QualifiedTable -> AnnBoolExpSQL -> Maybe Int -> Field -> m RS.AnnAggSel
=> PrepFn m -> QualifiedTable -> AnnBoolExpSQL
-> Maybe Int -> Field -> m RS.AnnAggSel
fromAggField fn tn permFilter permLimitM fld = fieldAsPath fld $ do
tableArgs <- parseTableArgs fn args
aggSelFlds <- fromAggSel (_fType fld) $ _fSelSet fld
aggSelFlds <- toFields <$>
fromAggSel (_fType fld) (_fSelSet fld)
let tabFrom = RS.TableFrom tn Nothing
tabPerm = RS.TablePerm permFilter permLimitM
return $ RS.AnnSelG aggSelFlds tabFrom tabPerm tableArgs
Expand Down
Loading