-- | This module relates to the processing of Order-By clauses.
module Hasura.Backends.Postgres.Translate.Select.Internal.OrderBy
  ( processOrderByItems,
  )
where

import Control.Lens ((^?))
import Data.HashMap.Strict qualified as HM
import Data.List.NonEmpty qualified as NE
import Hasura.Backends.Postgres.SQL.DML qualified as S
import Hasura.Backends.Postgres.SQL.Types
  ( Identifier,
    IsIdentifier (toIdentifier),
    PGCol (..),
  )
import Hasura.Backends.Postgres.Translate.BoolExp (toSQLBoolExp)
import Hasura.Backends.Postgres.Translate.Select.Internal.Aliases
  ( mkAggregateOrderByAlias,
    mkAnnOrderByAlias,
    mkArrayRelationAlias,
    mkArrayRelationSourcePrefix,
    mkBaseTableAlias,
    mkBaseTableColumnAlias,
    mkComputedFieldTableAlias,
    mkObjectRelationTableAlias,
    mkOrderByFieldName,
  )
import Hasura.Backends.Postgres.Translate.Select.Internal.Extractor
  ( aggregateFieldsToExtractorExps,
    mkAggregateOrderByExtractorAndFields,
  )
import Hasura.Backends.Postgres.Translate.Select.Internal.Helpers
  ( fromTableRowArgs,
    functionToIdentifier,
    selectFromToFromItem,
  )
import Hasura.Backends.Postgres.Translate.Select.Internal.JoinTree
  ( withWriteArrayRelation,
    withWriteComputedFieldTableSet,
    withWriteObjectRelation,
  )
import Hasura.Backends.Postgres.Translate.Types
import Hasura.GraphQL.Schema.Options qualified as Options
import Hasura.Prelude
import Hasura.RQL.IR.OrderBy
  ( OrderByItemG (OrderByItemG, obiColumn),
  )
import Hasura.RQL.IR.Select
import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.Column
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.ComputedField
import Hasura.RQL.Types.Relationships.Local
import Hasura.SQL.Backend

{- Note [Optimizing queries using limit/offset]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Refer to the issue https://github.com/hasura/graphql-engine/issues/5745

Before this change, limit/offset/distinct_on is applied at outer selection
node along with order by clause. This greatly reduces query performance if
our base selection table contains many rows and relationships are selected
which joins remote tables. We need to optimize application of limit wrt to
order by input.

If "Order by" is not present:
  Apply limit/offset/distinct on at the base table selection
Else if "Order by" contains only columns:
  Apply limit/offset/distinct_on at the base table selection along with order by
Otherwise:
  Apply limit/offset/distinct_on at the node selection along with order by
-}

processOrderByItems ::
  forall pgKind m.
  ( MonadReader Options.StringifyNumbers m,
    MonadWriter JoinTree m,
    Backend ('Postgres pgKind)
  ) =>
  Identifier ->
  FieldName ->
  SimilarArrayFields ->
  Maybe (NE.NonEmpty PGCol) ->
  Maybe (NE.NonEmpty (AnnotatedOrderByItem ('Postgres pgKind))) ->
  m
    ( [(S.ColumnAlias, S.SQLExp)], -- Order by Extractors
      SelectSorting,
      Maybe S.SQLExp -- The cursor expression
    )
processOrderByItems :: Identifier
-> FieldName
-> SimilarArrayFields
-> Maybe (NonEmpty PGCol)
-> Maybe (NonEmpty (AnnotatedOrderByItem ('Postgres pgKind)))
-> m ([(ColumnAlias, SQLExp)], SelectSorting, Maybe SQLExp)
processOrderByItems Identifier
sourcePrefix' FieldName
fieldAlias' SimilarArrayFields
similarArrayFields Maybe (NonEmpty PGCol)
distOnCols = \case
  Maybe (NonEmpty (AnnotatedOrderByItem ('Postgres pgKind)))
Nothing -> ([(ColumnAlias, SQLExp)], SelectSorting, Maybe SQLExp)
-> m ([(ColumnAlias, SQLExp)], SelectSorting, Maybe SQLExp)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([], Maybe DistinctExpr -> SelectSorting
NoSorting (Maybe DistinctExpr -> SelectSorting)
-> Maybe DistinctExpr -> SelectSorting
forall a b. (a -> b) -> a -> b
$ NonEmpty PGCol -> DistinctExpr
applyDistinctOnAtBase (NonEmpty PGCol -> DistinctExpr)
-> Maybe (NonEmpty PGCol) -> Maybe DistinctExpr
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (NonEmpty PGCol)
distOnCols, Maybe SQLExp
forall a. Maybe a
Nothing)
  Just NonEmpty (AnnotatedOrderByItem ('Postgres pgKind))
orderByItems -> do
    NonEmpty
  (OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
      (ColumnAlias, SQLExp)))
orderByItemExps <- NonEmpty (AnnotatedOrderByItemG ('Postgres pgKind) SQLExp)
-> (AnnotatedOrderByItemG ('Postgres pgKind) SQLExp
    -> m (OrderByItemG
            ('Postgres pgKind)
            (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
             (ColumnAlias, SQLExp))))
-> m (NonEmpty
        (OrderByItemG
           ('Postgres pgKind)
           (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
            (ColumnAlias, SQLExp))))
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM NonEmpty (AnnotatedOrderByItem ('Postgres pgKind))
NonEmpty (AnnotatedOrderByItemG ('Postgres pgKind) SQLExp)
orderByItems AnnotatedOrderByItem ('Postgres pgKind)
-> m (OrderByItemG
        ('Postgres pgKind)
        (AnnotatedOrderByElement
           ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
         (ColumnAlias, SQLExpression ('Postgres pgKind))))
AnnotatedOrderByItemG ('Postgres pgKind) SQLExp
-> m (OrderByItemG
        ('Postgres pgKind)
        (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
         (ColumnAlias, SQLExp)))
processAnnOrderByItem
    let (SelectSorting
sorting, [(ColumnAlias, SQLExp)]
distinctOnExtractors) = NonEmpty
  (OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement
        ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
      (ColumnAlias, SQLExpression ('Postgres pgKind))))
-> (SelectSorting,
    [(ColumnAlias, SQLExpression ('Postgres pgKind))])
generateSorting NonEmpty
  (OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement
        ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
      (ColumnAlias, SQLExpression ('Postgres pgKind))))
NonEmpty
  (OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
      (ColumnAlias, SQLExp)))
orderByItemExps
        orderByExtractors :: [(ColumnAlias, SQLExp)]
orderByExtractors = [[(ColumnAlias, SQLExp)]] -> [(ColumnAlias, SQLExp)]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[(ColumnAlias, SQLExp)]] -> [(ColumnAlias, SQLExp)])
-> [[(ColumnAlias, SQLExp)]] -> [(ColumnAlias, SQLExp)]
forall a b. (a -> b) -> a -> b
$ NonEmpty [(ColumnAlias, SQLExp)] -> [[(ColumnAlias, SQLExp)]]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (NonEmpty [(ColumnAlias, SQLExp)] -> [[(ColumnAlias, SQLExp)]])
-> NonEmpty [(ColumnAlias, SQLExp)] -> [[(ColumnAlias, SQLExp)]]
forall a b. (a -> b) -> a -> b
$ ((AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
  (ColumnAlias, SQLExp))
 -> (ColumnAlias, SQLExp))
-> [(AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
     (ColumnAlias, SQLExp))]
-> [(ColumnAlias, SQLExp)]
forall a b. (a -> b) -> [a] -> [b]
map (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
 (ColumnAlias, SQLExp))
-> (ColumnAlias, SQLExp)
forall a b. (a, b) -> b
snd ([(AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
   (ColumnAlias, SQLExp))]
 -> [(ColumnAlias, SQLExp)])
-> (OrderByItemG
      ('Postgres pgKind)
      (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
       (ColumnAlias, SQLExp))
    -> [(AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
         (ColumnAlias, SQLExp))])
-> OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
      (ColumnAlias, SQLExp))
-> [(ColumnAlias, SQLExp)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OrderByItemG
  ('Postgres pgKind)
  (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
   (ColumnAlias, SQLExp))
-> [(AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
     (ColumnAlias, SQLExp))]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
    (ColumnAlias, SQLExp))
 -> [(ColumnAlias, SQLExp)])
-> NonEmpty
     (OrderByItemG
        ('Postgres pgKind)
        (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
         (ColumnAlias, SQLExp)))
-> NonEmpty [(ColumnAlias, SQLExp)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty
  (OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
      (ColumnAlias, SQLExp)))
orderByItemExps
        cursor :: SQLExp
cursor = [OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement
      ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
    (ColumnAlias, SQLExpression ('Postgres pgKind)))]
-> SQLExp
mkCursorExp ([OrderByItemG
    ('Postgres pgKind)
    (AnnotatedOrderByElement
       ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
     (ColumnAlias, SQLExpression ('Postgres pgKind)))]
 -> SQLExp)
-> [OrderByItemG
      ('Postgres pgKind)
      (AnnotatedOrderByElement
         ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
       (ColumnAlias, SQLExpression ('Postgres pgKind)))]
-> SQLExp
forall a b. (a -> b) -> a -> b
$ NonEmpty
  (OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
      (ColumnAlias, SQLExp)))
-> [OrderByItemG
      ('Postgres pgKind)
      (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
       (ColumnAlias, SQLExp))]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList NonEmpty
  (OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
      (ColumnAlias, SQLExp)))
orderByItemExps
    ([(ColumnAlias, SQLExp)], SelectSorting, Maybe SQLExp)
-> m ([(ColumnAlias, SQLExp)], SelectSorting, Maybe SQLExp)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([(ColumnAlias, SQLExp)]
orderByExtractors [(ColumnAlias, SQLExp)]
-> [(ColumnAlias, SQLExp)] -> [(ColumnAlias, SQLExp)]
forall a. Semigroup a => a -> a -> a
<> [(ColumnAlias, SQLExp)]
distinctOnExtractors, SelectSorting
sorting, SQLExp -> Maybe SQLExp
forall a. a -> Maybe a
Just SQLExp
cursor)
  where
    processAnnOrderByItem ::
      AnnotatedOrderByItem ('Postgres pgKind) ->
      m (OrderByItemG ('Postgres pgKind) (AnnotatedOrderByElement ('Postgres pgKind) (SQLExpression ('Postgres pgKind)), (S.ColumnAlias, SQLExpression ('Postgres pgKind))))
    processAnnOrderByItem :: AnnotatedOrderByItem ('Postgres pgKind)
-> m (OrderByItemG
        ('Postgres pgKind)
        (AnnotatedOrderByElement
           ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
         (ColumnAlias, SQLExpression ('Postgres pgKind))))
processAnnOrderByItem AnnotatedOrderByItem ('Postgres pgKind)
orderByItem =
      AnnotatedOrderByItemG ('Postgres pgKind) SQLExp
-> (AnnotatedOrderByElement ('Postgres pgKind) SQLExp
    -> m (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
          (ColumnAlias, SQLExp)))
-> m (OrderByItemG
        ('Postgres pgKind)
        (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
         (ColumnAlias, SQLExp)))
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM AnnotatedOrderByItem ('Postgres pgKind)
AnnotatedOrderByItemG ('Postgres pgKind) SQLExp
orderByItem ((AnnotatedOrderByElement ('Postgres pgKind) SQLExp
  -> m (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
        (ColumnAlias, SQLExp)))
 -> m (OrderByItemG
         ('Postgres pgKind)
         (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
          (ColumnAlias, SQLExp))))
-> (AnnotatedOrderByElement ('Postgres pgKind) SQLExp
    -> m (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
          (ColumnAlias, SQLExp)))
-> m (OrderByItemG
        ('Postgres pgKind)
        (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
         (ColumnAlias, SQLExp)))
forall a b. (a -> b) -> a -> b
$ \AnnotatedOrderByElement ('Postgres pgKind) SQLExp
ordByCol ->
        (AnnotatedOrderByElement ('Postgres pgKind) SQLExp
ordByCol,)
          ((ColumnAlias, SQLExp)
 -> (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
     (ColumnAlias, SQLExp)))
-> m (ColumnAlias, SQLExp)
-> m (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
      (ColumnAlias, SQLExp))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Identifier
-> FieldName
-> AnnotatedOrderByElement ('Postgres pgKind) SQLExp
-> m (ColumnAlias, SQLExpression ('Postgres pgKind))
processAnnotatedOrderByElement Identifier
sourcePrefix' FieldName
fieldAlias' AnnotatedOrderByElement ('Postgres pgKind) SQLExp
ordByCol

    processAnnotatedOrderByElement ::
      Identifier -> FieldName -> AnnotatedOrderByElement ('Postgres pgKind) S.SQLExp -> m (S.ColumnAlias, (SQLExpression ('Postgres pgKind)))
    processAnnotatedOrderByElement :: Identifier
-> FieldName
-> AnnotatedOrderByElement ('Postgres pgKind) SQLExp
-> m (ColumnAlias, SQLExpression ('Postgres pgKind))
processAnnotatedOrderByElement Identifier
sourcePrefix FieldName
fieldAlias AnnotatedOrderByElement ('Postgres pgKind) SQLExp
annObCol = do
      let ordByAlias :: ColumnAlias
ordByAlias = Identifier
-> FieldName
-> SimilarArrayFields
-> AnnotatedOrderByElement ('Postgres pgKind) SQLExp
-> ColumnAlias
forall (pgKind :: PostgresKind) v.
Identifier
-> FieldName
-> SimilarArrayFields
-> AnnotatedOrderByElement ('Postgres pgKind) v
-> ColumnAlias
mkAnnOrderByAlias Identifier
sourcePrefix FieldName
fieldAlias SimilarArrayFields
similarArrayFields AnnotatedOrderByElement ('Postgres pgKind) SQLExp
annObCol
      (ColumnAlias
ordByAlias,) (SQLExp -> (ColumnAlias, SQLExp))
-> m SQLExp -> m (ColumnAlias, SQLExp)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> case AnnotatedOrderByElement ('Postgres pgKind) SQLExp
annObCol of
        AOCColumn ColumnInfo ('Postgres pgKind)
pgColInfo ->
          SQLExp -> m SQLExp
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SQLExp -> m SQLExp) -> SQLExp -> m SQLExp
forall a b. (a -> b) -> a -> b
$
            TableAlias -> Identifier -> SQLExp
forall a b. (IsIdentifier a, IsIdentifier b) => a -> b -> SQLExp
S.mkQIdenExp (Identifier -> TableAlias
mkBaseTableAlias Identifier
sourcePrefix) (Identifier -> SQLExp) -> Identifier -> SQLExp
forall a b. (a -> b) -> a -> b
$ PGCol -> Identifier
forall a. IsIdentifier a => a -> Identifier
toIdentifier (PGCol -> Identifier) -> PGCol -> Identifier
forall a b. (a -> b) -> a -> b
$ ColumnInfo ('Postgres pgKind) -> Column ('Postgres pgKind)
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo ('Postgres pgKind)
pgColInfo
        AOCObjectRelation RelInfo ('Postgres pgKind)
relInfo AnnBoolExp ('Postgres pgKind) SQLExp
relFilter AnnotatedOrderByElement ('Postgres pgKind) SQLExp
rest -> m (ObjectRelationSource, HashMap ColumnAlias SQLExp, SQLExp)
-> m SQLExp
forall (m :: * -> *) a.
MonadWriter JoinTree m =>
m (ObjectRelationSource, HashMap ColumnAlias SQLExp, a) -> m a
withWriteObjectRelation (m (ObjectRelationSource, HashMap ColumnAlias SQLExp, SQLExp)
 -> m SQLExp)
-> m (ObjectRelationSource, HashMap ColumnAlias SQLExp, SQLExp)
-> m SQLExp
forall a b. (a -> b) -> a -> b
$ do
          let RelInfo RelName
relName RelType
_ HashMap (Column ('Postgres pgKind)) (Column ('Postgres pgKind))
colMapping TableName ('Postgres pgKind)
relTable Bool
_ InsertOrder
_ = RelInfo ('Postgres pgKind)
relInfo
              relSourcePrefix :: Identifier
relSourcePrefix = Identifier -> RelName -> Identifier
mkObjectRelationTableAlias Identifier
sourcePrefix RelName
relName
              fieldName :: FieldName
fieldName = RelName -> FieldName
forall a. ToTxt a => a -> FieldName
mkOrderByFieldName RelName
relName
          (ColumnAlias
relOrderByAlias, SQLExp
relOrdByExp) <-
            Identifier
-> FieldName
-> AnnotatedOrderByElement ('Postgres pgKind) SQLExp
-> m (ColumnAlias, SQLExpression ('Postgres pgKind))
processAnnotatedOrderByElement Identifier
relSourcePrefix FieldName
fieldName AnnotatedOrderByElement ('Postgres pgKind) SQLExp
rest
          let selectSource :: ObjectSelectSource
selectSource =
                Identifier -> FromItem -> BoolExp -> ObjectSelectSource
ObjectSelectSource
                  Identifier
relSourcePrefix
                  (QualifiedTable -> Maybe TableAlias -> FromItem
S.FISimple TableName ('Postgres pgKind)
QualifiedTable
relTable Maybe TableAlias
forall a. Maybe a
Nothing)
                  (Qual -> AnnBoolExpSQL ('Postgres pgKind) -> BoolExp
forall (pgKind :: PostgresKind).
Backend ('Postgres pgKind) =>
Qual -> AnnBoolExpSQL ('Postgres pgKind) -> BoolExp
toSQLBoolExp (QualifiedTable -> Qual
S.QualTable TableName ('Postgres pgKind)
QualifiedTable
relTable) AnnBoolExpSQL ('Postgres pgKind)
AnnBoolExp ('Postgres pgKind) SQLExp
relFilter)
              relSource :: ObjectRelationSource
relSource = RelName
-> HashMap PGCol PGCol
-> ObjectSelectSource
-> ObjectRelationSource
ObjectRelationSource RelName
relName HashMap (Column ('Postgres pgKind)) (Column ('Postgres pgKind))
HashMap PGCol PGCol
colMapping ObjectSelectSource
selectSource
          (ObjectRelationSource, HashMap ColumnAlias SQLExp, SQLExp)
-> m (ObjectRelationSource, HashMap ColumnAlias SQLExp, SQLExp)
forall (f :: * -> *) a. Applicative f => a -> f a
pure
            ( ObjectRelationSource
relSource,
              ColumnAlias -> SQLExp -> HashMap ColumnAlias SQLExp
forall k v. Hashable k => k -> v -> HashMap k v
HM.singleton ColumnAlias
relOrderByAlias SQLExp
relOrdByExp,
              Identifier -> ColumnAlias -> SQLExp
forall a b. (IsIdentifier a, IsIdentifier b) => a -> b -> SQLExp
S.mkQIdenExp Identifier
relSourcePrefix ColumnAlias
relOrderByAlias
            )
        AOCArrayAggregation RelInfo ('Postgres pgKind)
relInfo AnnBoolExp ('Postgres pgKind) SQLExp
relFilter AnnotatedAggregateOrderBy ('Postgres pgKind)
aggOrderBy -> m (ArrayRelationSource, Extractor, HashMap ColumnAlias SQLExp,
   SQLExp)
-> m SQLExp
forall (m :: * -> *) a.
MonadWriter JoinTree m =>
m (ArrayRelationSource, Extractor, HashMap ColumnAlias SQLExp, a)
-> m a
withWriteArrayRelation (m (ArrayRelationSource, Extractor, HashMap ColumnAlias SQLExp,
    SQLExp)
 -> m SQLExp)
-> m (ArrayRelationSource, Extractor, HashMap ColumnAlias SQLExp,
      SQLExp)
-> m SQLExp
forall a b. (a -> b) -> a -> b
$ do
          let RelInfo RelName
relName RelType
_ HashMap (Column ('Postgres pgKind)) (Column ('Postgres pgKind))
colMapping TableName ('Postgres pgKind)
relTable Bool
_ InsertOrder
_ = RelInfo ('Postgres pgKind)
relInfo
              fieldName :: FieldName
fieldName = RelName -> FieldName
forall a. ToTxt a => a -> FieldName
mkOrderByFieldName RelName
relName
              relSourcePrefix :: Identifier
relSourcePrefix =
                Identifier
-> FieldName -> SimilarArrayFields -> FieldName -> Identifier
mkArrayRelationSourcePrefix
                  Identifier
sourcePrefix
                  FieldName
fieldAlias
                  SimilarArrayFields
similarArrayFields
                  FieldName
fieldName
              relAlias :: TableAlias
relAlias = FieldName -> SimilarArrayFields -> FieldName -> TableAlias
mkArrayRelationAlias FieldName
fieldAlias SimilarArrayFields
similarArrayFields FieldName
fieldName
              (Extractor
topExtractor, AggregateFields ('Postgres pgKind)
fields) = AnnotatedAggregateOrderBy ('Postgres pgKind)
-> (Extractor, AggregateFields ('Postgres pgKind))
forall (pgKind :: PostgresKind).
Backend ('Postgres pgKind) =>
AnnotatedAggregateOrderBy ('Postgres pgKind)
-> (Extractor, AggregateFields ('Postgres pgKind))
mkAggregateOrderByExtractorAndFields AnnotatedAggregateOrderBy ('Postgres pgKind)
aggOrderBy
              selectSource :: SelectSource
selectSource =
                Identifier
-> FromItem -> BoolExp -> SortingAndSlicing -> SelectSource
SelectSource
                  Identifier
relSourcePrefix
                  (QualifiedTable -> Maybe TableAlias -> FromItem
S.FISimple TableName ('Postgres pgKind)
QualifiedTable
relTable Maybe TableAlias
forall a. Maybe a
Nothing)
                  (Qual -> AnnBoolExpSQL ('Postgres pgKind) -> BoolExp
forall (pgKind :: PostgresKind).
Backend ('Postgres pgKind) =>
Qual -> AnnBoolExpSQL ('Postgres pgKind) -> BoolExp
toSQLBoolExp (QualifiedTable -> Qual
S.QualTable TableName ('Postgres pgKind)
QualifiedTable
relTable) AnnBoolExpSQL ('Postgres pgKind)
AnnBoolExp ('Postgres pgKind) SQLExp
relFilter)
                  SortingAndSlicing
noSortingAndSlicing
              relSource :: ArrayRelationSource
relSource = TableAlias
-> HashMap PGCol PGCol -> SelectSource -> ArrayRelationSource
ArrayRelationSource TableAlias
relAlias HashMap (Column ('Postgres pgKind)) (Column ('Postgres pgKind))
HashMap PGCol PGCol
colMapping SelectSource
selectSource
          (ArrayRelationSource, Extractor, HashMap ColumnAlias SQLExp,
 SQLExp)
-> m (ArrayRelationSource, Extractor, HashMap ColumnAlias SQLExp,
      SQLExp)
forall (f :: * -> *) a. Applicative f => a -> f a
pure
            ( ArrayRelationSource
relSource,
              Extractor
topExtractor,
              [(ColumnAlias, SQLExp)] -> HashMap ColumnAlias SQLExp
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HM.fromList ([(ColumnAlias, SQLExp)] -> HashMap ColumnAlias SQLExp)
-> [(ColumnAlias, SQLExp)] -> HashMap ColumnAlias SQLExp
forall a b. (a -> b) -> a -> b
$ Identifier
-> AggregateFields ('Postgres pgKind) -> [(ColumnAlias, SQLExp)]
forall (pgKind :: PostgresKind).
Identifier
-> AggregateFields ('Postgres pgKind) -> [(ColumnAlias, SQLExp)]
aggregateFieldsToExtractorExps Identifier
relSourcePrefix AggregateFields ('Postgres pgKind)
fields,
              Identifier -> ColumnAlias -> SQLExp
forall a b. (IsIdentifier a, IsIdentifier b) => a -> b -> SQLExp
S.mkQIdenExp Identifier
relSourcePrefix (AnnotatedAggregateOrderBy ('Postgres pgKind) -> ColumnAlias
forall (pgKind :: PostgresKind).
AnnotatedAggregateOrderBy ('Postgres pgKind) -> ColumnAlias
mkAggregateOrderByAlias AnnotatedAggregateOrderBy ('Postgres pgKind)
aggOrderBy)
            )
        AOCComputedField ComputedFieldOrderBy {FunctionName ('Postgres pgKind)
XComputedField ('Postgres pgKind)
FunctionArgsExp ('Postgres pgKind) SQLExp
ComputedFieldName
ComputedFieldOrderByElement ('Postgres pgKind) SQLExp
$sel:_cfobOrderByElement:ComputedFieldOrderBy :: forall (b :: BackendType) v.
ComputedFieldOrderBy b v -> ComputedFieldOrderByElement b v
$sel:_cfobFunctionArgsExp:ComputedFieldOrderBy :: forall (b :: BackendType) v.
ComputedFieldOrderBy b v -> FunctionArgsExp b v
$sel:_cfobFunction:ComputedFieldOrderBy :: forall (b :: BackendType) v.
ComputedFieldOrderBy b v -> FunctionName b
$sel:_cfobName:ComputedFieldOrderBy :: forall (b :: BackendType) v.
ComputedFieldOrderBy b v -> ComputedFieldName
$sel:_cfobXField:ComputedFieldOrderBy :: forall (b :: BackendType) v.
ComputedFieldOrderBy b v -> XComputedField b
_cfobOrderByElement :: ComputedFieldOrderByElement ('Postgres pgKind) SQLExp
_cfobFunctionArgsExp :: FunctionArgsExp ('Postgres pgKind) SQLExp
_cfobFunction :: FunctionName ('Postgres pgKind)
_cfobName :: ComputedFieldName
_cfobXField :: XComputedField ('Postgres pgKind)
..} ->
          case ComputedFieldOrderByElement ('Postgres pgKind) SQLExp
_cfobOrderByElement of
            CFOBEScalar ScalarType ('Postgres pgKind)
_ -> do
              let functionArgs :: FunctionArgs
functionArgs = Identifier -> FunctionArgsExpG (ArgumentExp SQLExp) -> FunctionArgs
fromTableRowArgs Identifier
sourcePrefix FunctionArgsExp ('Postgres pgKind) SQLExp
FunctionArgsExpG (ArgumentExp SQLExp)
_cfobFunctionArgsExp
                  functionExp :: FunctionExp
functionExp = QualifiedFunction
-> FunctionArgs -> Maybe FunctionAlias -> FunctionExp
S.FunctionExp FunctionName ('Postgres pgKind)
QualifiedFunction
_cfobFunction FunctionArgs
functionArgs Maybe FunctionAlias
forall a. Maybe a
Nothing
              SQLExp -> m SQLExp
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SQLExp -> m SQLExp) -> SQLExp -> m SQLExp
forall a b. (a -> b) -> a -> b
$ FunctionExp -> SQLExp
S.SEFunction FunctionExp
functionExp
            CFOBETableAggregation TableName ('Postgres pgKind)
_ AnnBoolExp ('Postgres pgKind) SQLExp
tableFilter AnnotatedAggregateOrderBy ('Postgres pgKind)
aggOrderBy -> m (ComputedFieldTableSetSource, Extractor,
   HashMap ColumnAlias SQLExp, SQLExp)
-> m SQLExp
forall (m :: * -> *) a.
MonadWriter JoinTree m =>
m (ComputedFieldTableSetSource, Extractor,
   HashMap ColumnAlias SQLExp, a)
-> m a
withWriteComputedFieldTableSet (m (ComputedFieldTableSetSource, Extractor,
    HashMap ColumnAlias SQLExp, SQLExp)
 -> m SQLExp)
-> m (ComputedFieldTableSetSource, Extractor,
      HashMap ColumnAlias SQLExp, SQLExp)
-> m SQLExp
forall a b. (a -> b) -> a -> b
$ do
              let fieldName :: FieldName
fieldName = ComputedFieldName -> FieldName
forall a. ToTxt a => a -> FieldName
mkOrderByFieldName ComputedFieldName
_cfobName
                  computedFieldSourcePrefix :: Identifier
computedFieldSourcePrefix = Identifier -> FieldName -> Identifier
mkComputedFieldTableAlias Identifier
sourcePrefix FieldName
fieldName
                  (Extractor
topExtractor, AggregateFields ('Postgres pgKind)
fields) = AnnotatedAggregateOrderBy ('Postgres pgKind)
-> (Extractor, AggregateFields ('Postgres pgKind))
forall (pgKind :: PostgresKind).
Backend ('Postgres pgKind) =>
AnnotatedAggregateOrderBy ('Postgres pgKind)
-> (Extractor, AggregateFields ('Postgres pgKind))
mkAggregateOrderByExtractorAndFields AnnotatedAggregateOrderBy ('Postgres pgKind)
aggOrderBy
                  fromItem :: FromItem
fromItem =
                    Identifier -> SelectFrom ('Postgres Any) -> FromItem
forall (pgKind :: PostgresKind).
Identifier -> SelectFrom ('Postgres pgKind) -> FromItem
selectFromToFromItem Identifier
sourcePrefix (SelectFrom ('Postgres Any) -> FromItem)
-> SelectFrom ('Postgres Any) -> FromItem
forall a b. (a -> b) -> a -> b
$
                      FunctionName ('Postgres Any)
-> FunctionArgsExp ('Postgres Any) SQLExp
-> Maybe [(Column ('Postgres Any), ScalarType ('Postgres Any))]
-> SelectFromG ('Postgres Any) SQLExp
forall (b :: BackendType) v.
FunctionName b
-> FunctionArgsExp b v
-> Maybe [(Column b, ScalarType b)]
-> SelectFromG b v
FromFunction FunctionName ('Postgres pgKind)
FunctionName ('Postgres Any)
_cfobFunction FunctionArgsExp ('Postgres pgKind) SQLExp
FunctionArgsExp ('Postgres Any) SQLExp
_cfobFunctionArgsExp Maybe [(Column ('Postgres Any), ScalarType ('Postgres Any))]
forall a. Maybe a
Nothing
                  functionQual :: Qual
functionQual = Identifier -> Maybe TypeAnn -> Qual
S.QualifiedIdentifier (QualifiedFunction -> Identifier
functionToIdentifier FunctionName ('Postgres pgKind)
QualifiedFunction
_cfobFunction) Maybe TypeAnn
forall a. Maybe a
Nothing
                  selectSource :: SelectSource
selectSource =
                    Identifier
-> FromItem -> BoolExp -> SortingAndSlicing -> SelectSource
SelectSource
                      Identifier
computedFieldSourcePrefix
                      FromItem
fromItem
                      (Qual -> AnnBoolExpSQL ('Postgres pgKind) -> BoolExp
forall (pgKind :: PostgresKind).
Backend ('Postgres pgKind) =>
Qual -> AnnBoolExpSQL ('Postgres pgKind) -> BoolExp
toSQLBoolExp Qual
functionQual AnnBoolExpSQL ('Postgres pgKind)
AnnBoolExp ('Postgres pgKind) SQLExp
tableFilter)
                      SortingAndSlicing
noSortingAndSlicing
                  source :: ComputedFieldTableSetSource
source = FieldName -> SelectSource -> ComputedFieldTableSetSource
ComputedFieldTableSetSource FieldName
fieldName SelectSource
selectSource
              (ComputedFieldTableSetSource, Extractor,
 HashMap ColumnAlias SQLExp, SQLExp)
-> m (ComputedFieldTableSetSource, Extractor,
      HashMap ColumnAlias SQLExp, SQLExp)
forall (f :: * -> *) a. Applicative f => a -> f a
pure
                ( ComputedFieldTableSetSource
source,
                  Extractor
topExtractor,
                  [(ColumnAlias, SQLExp)] -> HashMap ColumnAlias SQLExp
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HM.fromList ([(ColumnAlias, SQLExp)] -> HashMap ColumnAlias SQLExp)
-> [(ColumnAlias, SQLExp)] -> HashMap ColumnAlias SQLExp
forall a b. (a -> b) -> a -> b
$ Identifier
-> AggregateFields ('Postgres pgKind) -> [(ColumnAlias, SQLExp)]
forall (pgKind :: PostgresKind).
Identifier
-> AggregateFields ('Postgres pgKind) -> [(ColumnAlias, SQLExp)]
aggregateFieldsToExtractorExps Identifier
computedFieldSourcePrefix AggregateFields ('Postgres pgKind)
fields,
                  Identifier -> ColumnAlias -> SQLExp
forall a b. (IsIdentifier a, IsIdentifier b) => a -> b -> SQLExp
S.mkQIdenExp Identifier
computedFieldSourcePrefix (AnnotatedAggregateOrderBy ('Postgres pgKind) -> ColumnAlias
forall (pgKind :: PostgresKind).
AnnotatedAggregateOrderBy ('Postgres pgKind) -> ColumnAlias
mkAggregateOrderByAlias AnnotatedAggregateOrderBy ('Postgres pgKind)
aggOrderBy)
                )

    generateSorting ::
      NE.NonEmpty (OrderByItemG ('Postgres pgKind) (AnnotatedOrderByElement ('Postgres pgKind) (SQLExpression ('Postgres pgKind)), (S.ColumnAlias, SQLExpression ('Postgres pgKind)))) ->
      ( SelectSorting,
        [(S.ColumnAlias, SQLExpression ('Postgres pgKind))] -- 'distinct on' column extractors
      )
    generateSorting :: NonEmpty
  (OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement
        ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
      (ColumnAlias, SQLExpression ('Postgres pgKind))))
-> (SelectSorting,
    [(ColumnAlias, SQLExpression ('Postgres pgKind))])
generateSorting orderByExps :: NonEmpty
  (OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement
        ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
      (ColumnAlias, SQLExpression ('Postgres pgKind))))
orderByExps@(OrderByItemG
  ('Postgres pgKind)
  (AnnotatedOrderByElement
     ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
   (ColumnAlias, SQLExpression ('Postgres pgKind)))
firstOrderBy NE.:| [OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement
      ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
    (ColumnAlias, SQLExpression ('Postgres pgKind)))]
restOrderBys) =
      case (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
 (ColumnAlias, SQLExp))
-> AnnotatedOrderByElement ('Postgres pgKind) SQLExp
forall a b. (a, b) -> a
fst ((AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
  (ColumnAlias, SQLExp))
 -> AnnotatedOrderByElement ('Postgres pgKind) SQLExp)
-> (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
    (ColumnAlias, SQLExp))
-> AnnotatedOrderByElement ('Postgres pgKind) SQLExp
forall a b. (a -> b) -> a -> b
$ OrderByItemG
  ('Postgres pgKind)
  (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
   (ColumnAlias, SQLExp))
-> (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
    (ColumnAlias, SQLExp))
forall (b :: BackendType) a. OrderByItemG b a -> a
obiColumn OrderByItemG
  ('Postgres pgKind)
  (AnnotatedOrderByElement
     ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
   (ColumnAlias, SQLExpression ('Postgres pgKind)))
OrderByItemG
  ('Postgres pgKind)
  (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
   (ColumnAlias, SQLExp))
firstOrderBy of
        AOCColumn ColumnInfo ('Postgres pgKind)
columnInfo ->
          -- If rest order by expressions are all columns then apply order by clause at base selection.
          if (OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
    (ColumnAlias, SQLExp))
 -> Bool)
-> [OrderByItemG
      ('Postgres pgKind)
      (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
       (ColumnAlias, SQLExp))]
-> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Maybe (ColumnInfo ('Postgres pgKind)) -> Bool
forall a. Maybe a -> Bool
isJust (Maybe (ColumnInfo ('Postgres pgKind)) -> Bool)
-> (OrderByItemG
      ('Postgres pgKind)
      (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
       (ColumnAlias, SQLExp))
    -> Maybe (ColumnInfo ('Postgres pgKind)))
-> OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
      (ColumnAlias, SQLExp))
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
 (ColumnAlias, SQLExp))
-> Maybe (ColumnInfo ('Postgres pgKind))
forall (b :: BackendType) v b.
(AnnotatedOrderByElement b v, b) -> Maybe (ColumnInfo b)
getColumnOrderBy ((AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
  (ColumnAlias, SQLExp))
 -> Maybe (ColumnInfo ('Postgres pgKind)))
-> (OrderByItemG
      ('Postgres pgKind)
      (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
       (ColumnAlias, SQLExp))
    -> (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
        (ColumnAlias, SQLExp)))
-> OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
      (ColumnAlias, SQLExp))
-> Maybe (ColumnInfo ('Postgres pgKind))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OrderByItemG
  ('Postgres pgKind)
  (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
   (ColumnAlias, SQLExp))
-> (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
    (ColumnAlias, SQLExp))
forall (b :: BackendType) a. OrderByItemG b a -> a
obiColumn) [OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement
      ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
    (ColumnAlias, SQLExpression ('Postgres pgKind)))]
[OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
    (ColumnAlias, SQLExp))]
restOrderBys
            then -- Collect column order by expressions from the rest.

              let restColumnOrderBys :: [OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind))]
restColumnOrderBys = (OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
    (ColumnAlias, SQLExp))
 -> Maybe
      (OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind))))
-> [OrderByItemG
      ('Postgres pgKind)
      (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
       (ColumnAlias, SQLExp))]
-> [OrderByItemG
      ('Postgres pgKind) (ColumnInfo ('Postgres pgKind))]
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe (((AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
  (ColumnAlias, SQLExp))
 -> Maybe (ColumnInfo ('Postgres pgKind)))
-> OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
      (ColumnAlias, SQLExp))
-> Maybe
     (OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind)))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
 (ColumnAlias, SQLExp))
-> Maybe (ColumnInfo ('Postgres pgKind))
forall (b :: BackendType) v b.
(AnnotatedOrderByElement b v, b) -> Maybe (ColumnInfo b)
getColumnOrderBy) [OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement
      ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
    (ColumnAlias, SQLExpression ('Postgres pgKind)))]
[OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
    (ColumnAlias, SQLExp))]
restOrderBys
                  firstColumnOrderBy :: OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind))
firstColumnOrderBy = OrderByItemG
  ('Postgres pgKind)
  (AnnotatedOrderByElement
     ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
   (ColumnAlias, SQLExpression ('Postgres pgKind)))
OrderByItemG
  ('Postgres pgKind)
  (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
   (ColumnAlias, SQLExp))
firstOrderBy {obiColumn :: ColumnInfo ('Postgres pgKind)
obiColumn = ColumnInfo ('Postgres pgKind)
columnInfo}
               in NonEmpty
  (OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind)))
-> (SelectSorting, [(ColumnAlias, SQLExp)])
sortAtNodeAndBase (NonEmpty
   (OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind)))
 -> (SelectSorting, [(ColumnAlias, SQLExp)]))
-> NonEmpty
     (OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind)))
-> (SelectSorting, [(ColumnAlias, SQLExp)])
forall a b. (a -> b) -> a -> b
$ OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind))
firstColumnOrderBy OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind))
-> [OrderByItemG
      ('Postgres pgKind) (ColumnInfo ('Postgres pgKind))]
-> NonEmpty
     (OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind)))
forall a. a -> [a] -> NonEmpty a
NE.:| [OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind))]
restColumnOrderBys
            else -- Else rest order by expressions contain atleast one non-column order by.
            -- So, apply order by clause at node selection.
              (SelectSorting, [(ColumnAlias, SQLExpression ('Postgres pgKind))])
(SelectSorting, [(ColumnAlias, SQLExp)])
sortOnlyAtNode
        AnnotatedOrderByElement ('Postgres pgKind) SQLExp
_ ->
          -- First order by expression is non-column. So, apply order by clause at node selection.
          (SelectSorting, [(ColumnAlias, SQLExpression ('Postgres pgKind))])
(SelectSorting, [(ColumnAlias, SQLExp)])
sortOnlyAtNode
      where
        getColumnOrderBy :: (AnnotatedOrderByElement b v, b) -> Maybe (ColumnInfo b)
getColumnOrderBy = (AnnotatedOrderByElement b v
-> Getting
     (First (ColumnInfo b)) (AnnotatedOrderByElement b v) (ColumnInfo b)
-> Maybe (ColumnInfo b)
forall s a. s -> Getting (First a) s a -> Maybe a
^? Getting
  (First (ColumnInfo b)) (AnnotatedOrderByElement b v) (ColumnInfo b)
forall (b :: BackendType) v.
Prism' (AnnotatedOrderByElement b v) (ColumnInfo b)
_AOCColumn) (AnnotatedOrderByElement b v -> Maybe (ColumnInfo b))
-> ((AnnotatedOrderByElement b v, b)
    -> AnnotatedOrderByElement b v)
-> (AnnotatedOrderByElement b v, b)
-> Maybe (ColumnInfo b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AnnotatedOrderByElement b v, b) -> AnnotatedOrderByElement b v
forall a b. (a, b) -> a
fst

        (OrderByExp
nodeOrderBy, Maybe DistinctExpr
nodeDistinctOn, [(ColumnAlias, SQLExp)]
nodeDistinctOnExtractors) =
          let toOrderByExp :: OrderByItemG b (a, (a, b)) -> OrderByItem
toOrderByExp OrderByItemG b (a, (a, b))
orderByItemExp =
                let OrderByItemG Maybe (BasicOrderType b)
obTyM a
expAlias Maybe (NullsOrderType b)
obNullsM = (a, b) -> a
forall a b. (a, b) -> a
fst ((a, b) -> a) -> ((a, (a, b)) -> (a, b)) -> (a, (a, b)) -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a, (a, b)) -> (a, b)
forall a b. (a, b) -> b
snd ((a, (a, b)) -> a)
-> OrderByItemG b (a, (a, b)) -> OrderByItemG b a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> OrderByItemG b (a, (a, b))
orderByItemExp
                 in SQLExp -> Maybe OrderType -> Maybe NullsOrder -> OrderByItem
S.OrderByItem (Identifier -> SQLExp
S.SEIdentifier (Identifier -> SQLExp) -> Identifier -> SQLExp
forall a b. (a -> b) -> a -> b
$ a -> Identifier
forall a. IsIdentifier a => a -> Identifier
toIdentifier a
expAlias) Maybe (BasicOrderType b)
Maybe OrderType
obTyM Maybe (NullsOrderType b)
Maybe NullsOrder
obNullsM
              orderByExp :: OrderByExp
orderByExp = NonEmpty OrderByItem -> OrderByExp
S.OrderByExp (NonEmpty OrderByItem -> OrderByExp)
-> NonEmpty OrderByItem -> OrderByExp
forall a b. (a -> b) -> a -> b
$ OrderByItemG
  ('Postgres pgKind)
  (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
   (ColumnAlias, SQLExp))
-> OrderByItem
forall a (b :: BackendType) a b.
(IsIdentifier a, BasicOrderType b ~ OrderType,
 NullsOrderType b ~ NullsOrder) =>
OrderByItemG b (a, (a, b)) -> OrderByItem
toOrderByExp (OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
    (ColumnAlias, SQLExp))
 -> OrderByItem)
-> NonEmpty
     (OrderByItemG
        ('Postgres pgKind)
        (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
         (ColumnAlias, SQLExp)))
-> NonEmpty OrderByItem
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty
  (OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement
        ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
      (ColumnAlias, SQLExpression ('Postgres pgKind))))
NonEmpty
  (OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
      (ColumnAlias, SQLExp)))
orderByExps
              (Maybe DistinctExpr
maybeDistOn, Maybe [(ColumnAlias, SQLExp)]
distOnExtrs) = Maybe (DistinctExpr, [(ColumnAlias, SQLExp)])
-> (Maybe DistinctExpr, Maybe [(ColumnAlias, SQLExp)])
forall (f :: * -> *) a b. Functor f => f (a, b) -> (f a, f b)
NE.unzip (Maybe (DistinctExpr, [(ColumnAlias, SQLExp)])
 -> (Maybe DistinctExpr, Maybe [(ColumnAlias, SQLExp)]))
-> Maybe (DistinctExpr, [(ColumnAlias, SQLExp)])
-> (Maybe DistinctExpr, Maybe [(ColumnAlias, SQLExp)])
forall a b. (a -> b) -> a -> b
$ Identifier
-> NonEmpty PGCol -> (DistinctExpr, [(ColumnAlias, SQLExp)])
applyDistinctOnAtNode Identifier
sourcePrefix' (NonEmpty PGCol -> (DistinctExpr, [(ColumnAlias, SQLExp)]))
-> Maybe (NonEmpty PGCol)
-> Maybe (DistinctExpr, [(ColumnAlias, SQLExp)])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (NonEmpty PGCol)
distOnCols
           in (OrderByExp
orderByExp, Maybe DistinctExpr
maybeDistOn, [(ColumnAlias, SQLExp)]
-> Maybe [(ColumnAlias, SQLExp)] -> [(ColumnAlias, SQLExp)]
forall a. a -> Maybe a -> a
fromMaybe [] Maybe [(ColumnAlias, SQLExp)]
distOnExtrs)

        sortOnlyAtNode :: (SelectSorting, [(ColumnAlias, SQLExp)])
sortOnlyAtNode =
          (DistinctAndOrderByExpr -> SelectSorting
Sorting (DistinctAndOrderByExpr -> SelectSorting)
-> DistinctAndOrderByExpr -> SelectSorting
forall a b. (a -> b) -> a -> b
$ (OrderByExp, Maybe DistinctExpr)
-> Maybe (OrderByExp, Maybe DistinctExpr) -> DistinctAndOrderByExpr
ASorting (OrderByExp
nodeOrderBy, Maybe DistinctExpr
nodeDistinctOn) Maybe (OrderByExp, Maybe DistinctExpr)
forall a. Maybe a
Nothing, [(ColumnAlias, SQLExp)]
nodeDistinctOnExtractors)

        sortAtNodeAndBase :: NonEmpty
  (OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind)))
-> (SelectSorting, [(ColumnAlias, SQLExp)])
sortAtNodeAndBase NonEmpty
  (OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind)))
baseColumnOrderBys =
          let mkBaseOrderByItem :: OrderByItemG b (ColumnInfo b) -> OrderByItem
mkBaseOrderByItem (OrderByItemG Maybe (BasicOrderType b)
orderByType ColumnInfo b
columnInfo Maybe (NullsOrderType b)
nullsOrder) =
                SQLExp -> Maybe OrderType -> Maybe NullsOrder -> OrderByItem
S.OrderByItem
                  (Identifier -> SQLExp
S.SEIdentifier (Identifier -> SQLExp) -> Identifier -> SQLExp
forall a b. (a -> b) -> a -> b
$ Column b -> Identifier
forall a. IsIdentifier a => a -> Identifier
toIdentifier (Column b -> Identifier) -> Column b -> Identifier
forall a b. (a -> b) -> a -> b
$ ColumnInfo b -> Column b
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo b
columnInfo)
                  Maybe (BasicOrderType b)
Maybe OrderType
orderByType
                  Maybe (NullsOrderType b)
Maybe NullsOrder
nullsOrder
              baseOrderByExp :: OrderByExp
baseOrderByExp = NonEmpty OrderByItem -> OrderByExp
S.OrderByExp (NonEmpty OrderByItem -> OrderByExp)
-> NonEmpty OrderByItem -> OrderByExp
forall a b. (a -> b) -> a -> b
$ OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind))
-> OrderByItem
forall (b :: BackendType) (b :: BackendType).
(IsIdentifier (Column b), BasicOrderType b ~ OrderType,
 NullsOrderType b ~ NullsOrder) =>
OrderByItemG b (ColumnInfo b) -> OrderByItem
mkBaseOrderByItem (OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind))
 -> OrderByItem)
-> NonEmpty
     (OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind)))
-> NonEmpty OrderByItem
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty
  (OrderByItemG ('Postgres pgKind) (ColumnInfo ('Postgres pgKind)))
baseColumnOrderBys
              baseDistOnExp :: Maybe DistinctExpr
baseDistOnExp = NonEmpty PGCol -> DistinctExpr
applyDistinctOnAtBase (NonEmpty PGCol -> DistinctExpr)
-> Maybe (NonEmpty PGCol) -> Maybe DistinctExpr
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (NonEmpty PGCol)
distOnCols
              sorting :: SelectSorting
sorting = DistinctAndOrderByExpr -> SelectSorting
Sorting (DistinctAndOrderByExpr -> SelectSorting)
-> DistinctAndOrderByExpr -> SelectSorting
forall a b. (a -> b) -> a -> b
$ (OrderByExp, Maybe DistinctExpr)
-> Maybe (OrderByExp, Maybe DistinctExpr) -> DistinctAndOrderByExpr
ASorting (OrderByExp
nodeOrderBy, Maybe DistinctExpr
nodeDistinctOn) (Maybe (OrderByExp, Maybe DistinctExpr) -> DistinctAndOrderByExpr)
-> Maybe (OrderByExp, Maybe DistinctExpr) -> DistinctAndOrderByExpr
forall a b. (a -> b) -> a -> b
$ (OrderByExp, Maybe DistinctExpr)
-> Maybe (OrderByExp, Maybe DistinctExpr)
forall a. a -> Maybe a
Just (OrderByExp
baseOrderByExp, Maybe DistinctExpr
baseDistOnExp)
           in (SelectSorting
sorting, [(ColumnAlias, SQLExp)]
nodeDistinctOnExtractors)

    mkCursorExp ::
      [OrderByItemG ('Postgres pgKind) (AnnotatedOrderByElement ('Postgres pgKind) (SQLExpression ('Postgres pgKind)), (S.ColumnAlias, SQLExpression ('Postgres pgKind)))] ->
      S.SQLExp
    mkCursorExp :: [OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement
      ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
    (ColumnAlias, SQLExpression ('Postgres pgKind)))]
-> SQLExp
mkCursorExp [OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement
      ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
    (ColumnAlias, SQLExpression ('Postgres pgKind)))]
orderByItemExps =
      [SQLExp] -> SQLExp
S.applyJsonBuildObj ([SQLExp] -> SQLExp) -> [SQLExp] -> SQLExp
forall a b. (a -> b) -> a -> b
$
        ((OrderByItemG
    ('Postgres pgKind)
    (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
     (ColumnAlias, SQLExp))
  -> [SQLExp])
 -> [OrderByItemG
       ('Postgres pgKind)
       (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
        (ColumnAlias, SQLExp))]
 -> [SQLExp])
-> [OrderByItemG
      ('Postgres pgKind)
      (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
       (ColumnAlias, SQLExp))]
-> (OrderByItemG
      ('Postgres pgKind)
      (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
       (ColumnAlias, SQLExp))
    -> [SQLExp])
-> [SQLExp]
forall a b c. (a -> b -> c) -> b -> a -> c
flip (OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
    (ColumnAlias, SQLExp))
 -> [SQLExp])
-> [OrderByItemG
      ('Postgres pgKind)
      (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
       (ColumnAlias, SQLExp))]
-> [SQLExp]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap [OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement
      ('Postgres pgKind) (SQLExpression ('Postgres pgKind)),
    (ColumnAlias, SQLExpression ('Postgres pgKind)))]
[OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
    (ColumnAlias, SQLExp))]
orderByItemExps ((OrderByItemG
    ('Postgres pgKind)
    (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
     (ColumnAlias, SQLExp))
  -> [SQLExp])
 -> [SQLExp])
-> (OrderByItemG
      ('Postgres pgKind)
      (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
       (ColumnAlias, SQLExp))
    -> [SQLExp])
-> [SQLExp]
forall a b. (a -> b) -> a -> b
$
          \OrderByItemG
  ('Postgres pgKind)
  (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
   (ColumnAlias, SQLExp))
orderByItemExp ->
            let OrderByItemG Maybe (BasicOrderType ('Postgres pgKind))
_ (AnnotatedOrderByElement ('Postgres pgKind) SQLExp
annObCol, (ColumnAlias
_, SQLExp
valExp)) Maybe (NullsOrderType ('Postgres pgKind))
_ = OrderByItemG
  ('Postgres pgKind)
  (AnnotatedOrderByElement ('Postgres pgKind) SQLExp,
   (ColumnAlias, SQLExp))
orderByItemExp
             in SQLExp
-> AnnotatedOrderByElement ('Postgres pgKind) SQLExp -> [SQLExp]
forall (b :: BackendType) v.
(Column b ~ PGCol) =>
SQLExp -> AnnotatedOrderByElement b v -> [SQLExp]
annObColToJSONField SQLExp
valExp AnnotatedOrderByElement ('Postgres pgKind) SQLExp
annObCol
      where
        mkAggOrderByValExp :: SQLExp -> AnnotatedAggregateOrderBy b -> [SQLExp]
mkAggOrderByValExp SQLExp
valExp = \case
          AnnotatedAggregateOrderBy b
AAOCount -> [Text -> SQLExp
S.SELit Text
"count", SQLExp
valExp]
          AAOOp Text
opText ColumnInfo b
colInfo ->
            [ Text -> SQLExp
S.SELit Text
opText,
              [SQLExp] -> SQLExp
S.applyJsonBuildObj [Text -> SQLExp
S.SELit (Text -> SQLExp) -> Text -> SQLExp
forall a b. (a -> b) -> a -> b
$ PGCol -> Text
getPGColTxt (PGCol -> Text) -> PGCol -> Text
forall a b. (a -> b) -> a -> b
$ ColumnInfo b -> Column b
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo b
colInfo, SQLExp
valExp]
            ]

        annObColToJSONField :: SQLExp -> AnnotatedOrderByElement b v -> [SQLExp]
annObColToJSONField SQLExp
valExp = \case
          AOCColumn ColumnInfo b
pgCol -> [Text -> SQLExp
S.SELit (Text -> SQLExp) -> Text -> SQLExp
forall a b. (a -> b) -> a -> b
$ PGCol -> Text
getPGColTxt (PGCol -> Text) -> PGCol -> Text
forall a b. (a -> b) -> a -> b
$ ColumnInfo b -> Column b
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo b
pgCol, SQLExp
valExp]
          AOCObjectRelation RelInfo b
relInfo AnnBoolExp b v
_ AnnotatedOrderByElement b v
obCol ->
            [ Text -> SQLExp
S.SELit (Text -> SQLExp) -> Text -> SQLExp
forall a b. (a -> b) -> a -> b
$ RelName -> Text
relNameToTxt (RelName -> Text) -> RelName -> Text
forall a b. (a -> b) -> a -> b
$ RelInfo b -> RelName
forall (b :: BackendType). RelInfo b -> RelName
riName RelInfo b
relInfo,
              [SQLExp] -> SQLExp
S.applyJsonBuildObj ([SQLExp] -> SQLExp) -> [SQLExp] -> SQLExp
forall a b. (a -> b) -> a -> b
$ SQLExp -> AnnotatedOrderByElement b v -> [SQLExp]
annObColToJSONField SQLExp
valExp AnnotatedOrderByElement b v
obCol
            ]
          AOCArrayAggregation RelInfo b
relInfo AnnBoolExp b v
_ AnnotatedAggregateOrderBy b
aggOrderBy ->
            [ Text -> SQLExp
S.SELit (Text -> SQLExp) -> Text -> SQLExp
forall a b. (a -> b) -> a -> b
$ RelName -> Text
relNameToTxt (RelInfo b -> RelName
forall (b :: BackendType). RelInfo b -> RelName
riName RelInfo b
relInfo) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_aggregate",
              [SQLExp] -> SQLExp
S.applyJsonBuildObj ([SQLExp] -> SQLExp) -> [SQLExp] -> SQLExp
forall a b. (a -> b) -> a -> b
$ SQLExp -> AnnotatedAggregateOrderBy b -> [SQLExp]
forall (b :: BackendType).
(Column b ~ PGCol) =>
SQLExp -> AnnotatedAggregateOrderBy b -> [SQLExp]
mkAggOrderByValExp SQLExp
valExp AnnotatedAggregateOrderBy b
aggOrderBy
            ]
          AOCComputedField ComputedFieldOrderBy b v
cfOrderBy ->
            let fieldNameText :: Text
fieldNameText = ComputedFieldName -> Text
computedFieldNameToText (ComputedFieldName -> Text) -> ComputedFieldName -> Text
forall a b. (a -> b) -> a -> b
$ ComputedFieldOrderBy b v -> ComputedFieldName
forall (b :: BackendType) v.
ComputedFieldOrderBy b v -> ComputedFieldName
_cfobName ComputedFieldOrderBy b v
cfOrderBy
             in case ComputedFieldOrderBy b v -> ComputedFieldOrderByElement b v
forall (b :: BackendType) v.
ComputedFieldOrderBy b v -> ComputedFieldOrderByElement b v
_cfobOrderByElement ComputedFieldOrderBy b v
cfOrderBy of
                  CFOBEScalar ScalarType b
_ -> [Text -> SQLExp
S.SELit Text
fieldNameText, SQLExp
valExp]
                  CFOBETableAggregation TableName b
_ AnnBoolExp b v
_ AnnotatedAggregateOrderBy b
aggOrderBy ->
                    [ Text -> SQLExp
S.SELit (Text -> SQLExp) -> Text -> SQLExp
forall a b. (a -> b) -> a -> b
$ Text
fieldNameText Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_aggregate",
                      [SQLExp] -> SQLExp
S.applyJsonBuildObj ([SQLExp] -> SQLExp) -> [SQLExp] -> SQLExp
forall a b. (a -> b) -> a -> b
$ SQLExp -> AnnotatedAggregateOrderBy b -> [SQLExp]
forall (b :: BackendType).
(Column b ~ PGCol) =>
SQLExp -> AnnotatedAggregateOrderBy b -> [SQLExp]
mkAggOrderByValExp SQLExp
valExp AnnotatedAggregateOrderBy b
aggOrderBy
                    ]

applyDistinctOnAtBase ::
  NE.NonEmpty PGCol -> S.DistinctExpr
applyDistinctOnAtBase :: NonEmpty PGCol -> DistinctExpr
applyDistinctOnAtBase =
  [SQLExp] -> DistinctExpr
S.DistinctOn ([SQLExp] -> DistinctExpr)
-> (NonEmpty PGCol -> [SQLExp]) -> NonEmpty PGCol -> DistinctExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PGCol -> SQLExp) -> [PGCol] -> [SQLExp]
forall a b. (a -> b) -> [a] -> [b]
map (Identifier -> SQLExp
S.SEIdentifier (Identifier -> SQLExp) -> (PGCol -> Identifier) -> PGCol -> SQLExp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PGCol -> Identifier
forall a. IsIdentifier a => a -> Identifier
toIdentifier) ([PGCol] -> [SQLExp])
-> (NonEmpty PGCol -> [PGCol]) -> NonEmpty PGCol -> [SQLExp]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty PGCol -> [PGCol]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList

applyDistinctOnAtNode ::
  Identifier ->
  NE.NonEmpty PGCol ->
  ( S.DistinctExpr,
    [(S.ColumnAlias, S.SQLExp)] -- additional column extractors
  )
applyDistinctOnAtNode :: Identifier
-> NonEmpty PGCol -> (DistinctExpr, [(ColumnAlias, SQLExp)])
applyDistinctOnAtNode Identifier
pfx NonEmpty PGCol
neCols = (DistinctExpr
distOnExp, [(ColumnAlias, SQLExp)]
colExtrs)
  where
    cols :: [PGCol]
cols = NonEmpty PGCol -> [PGCol]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList NonEmpty PGCol
neCols
    distOnExp :: DistinctExpr
distOnExp = [SQLExp] -> DistinctExpr
S.DistinctOn ([SQLExp] -> DistinctExpr) -> [SQLExp] -> DistinctExpr
forall a b. (a -> b) -> a -> b
$ (PGCol -> SQLExp) -> [PGCol] -> [SQLExp]
forall a b. (a -> b) -> [a] -> [b]
map (Identifier -> SQLExp
S.SEIdentifier (Identifier -> SQLExp) -> (PGCol -> Identifier) -> PGCol -> SQLExp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ColumnAlias -> Identifier
forall a. IsIdentifier a => a -> Identifier
toIdentifier (ColumnAlias -> Identifier)
-> (PGCol -> ColumnAlias) -> PGCol -> Identifier
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PGCol -> ColumnAlias
mkQColAls) [PGCol]
cols
    mkQCol :: PGCol -> SQLExp
mkQCol PGCol
c = TableAlias -> Identifier -> SQLExp
forall a b. (IsIdentifier a, IsIdentifier b) => a -> b -> SQLExp
S.mkQIdenExp (Identifier -> TableAlias
mkBaseTableAlias Identifier
pfx) (Identifier -> SQLExp) -> Identifier -> SQLExp
forall a b. (a -> b) -> a -> b
$ PGCol -> Identifier
forall a. IsIdentifier a => a -> Identifier
toIdentifier PGCol
c
    mkQColAls :: PGCol -> ColumnAlias
mkQColAls = Identifier -> PGCol -> ColumnAlias
mkBaseTableColumnAlias Identifier
pfx
    colExtrs :: [(ColumnAlias, SQLExp)]
colExtrs = ((PGCol -> (ColumnAlias, SQLExp))
 -> [PGCol] -> [(ColumnAlias, SQLExp)])
-> [PGCol]
-> (PGCol -> (ColumnAlias, SQLExp))
-> [(ColumnAlias, SQLExp)]
forall a b c. (a -> b -> c) -> b -> a -> c
flip (PGCol -> (ColumnAlias, SQLExp))
-> [PGCol] -> [(ColumnAlias, SQLExp)]
forall a b. (a -> b) -> [a] -> [b]
map [PGCol]
cols ((PGCol -> (ColumnAlias, SQLExp)) -> [(ColumnAlias, SQLExp)])
-> (PGCol -> (ColumnAlias, SQLExp)) -> [(ColumnAlias, SQLExp)]
forall a b. (a -> b) -> a -> b
$ PGCol -> ColumnAlias
mkQColAls (PGCol -> ColumnAlias)
-> (PGCol -> SQLExp) -> PGCol -> (ColumnAlias, SQLExp)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& PGCol -> SQLExp
mkQCol