-- | This module defines the top-level translation functions pertaining to
-- streaming selects into Postgres AST.
--
-- Streaming subscriptions are subscriptions based on a user-provided cursor
-- column. Unlike live queries, streaming subscriptions can be used to only get
-- the part that has changed in the query's response, although this will be
-- dependent on the user's choice of the cursor column. The streaming starts
-- from the initial value provided by the user.
module Hasura.Backends.Postgres.Translate.Select.Streaming
  ( mkStreamSQLSelect,
    selectStreamQuerySQL,
  )
where

import Control.Monad.Writer.Strict (runWriter)
import Database.PG.Query (Query, fromBuilder)
import Hasura.Backends.Postgres.SQL.DML qualified as S
import Hasura.Backends.Postgres.SQL.RenameIdentifiers (renameIdentifiers)
import Hasura.Backends.Postgres.SQL.Types
import Hasura.Backends.Postgres.SQL.Value (withConstructorFn)
import Hasura.Backends.Postgres.Translate.Select.AnnotatedFieldJSON
import Hasura.Backends.Postgres.Translate.Select.Internal.Aliases (mkBaseTableColumnAlias)
import Hasura.Backends.Postgres.Translate.Select.Internal.Extractor (asJsonAggExtr)
import Hasura.Backends.Postgres.Translate.Select.Internal.GenerateSelect (generateSQLSelectFromArrayNode)
import Hasura.Backends.Postgres.Translate.Select.Internal.Process (processAnnSimpleSelect)
import Hasura.Backends.Postgres.Translate.Types
  ( MultiRowSelectNode (MultiRowSelectNode),
    PermissionLimitSubQuery (PLSQNotRequired),
    SelectNode (SelectNode),
    SourcePrefixes (SourcePrefixes),
    orderByForJsonAgg,
  )
import Hasura.Backends.Postgres.Types.Column (unsafePGColumnToBackend)
import Hasura.Prelude
import Hasura.RQL.IR.BoolExp
  ( AnnBoolExpFld (AVColumn),
    GBoolExp (BoolField),
    OpExpG (AGT, ALT),
    andAnnBoolExps,
  )
import Hasura.RQL.IR.OrderBy (OrderByItemG (OrderByItemG))
import Hasura.RQL.IR.Select
import Hasura.RQL.Types.Backend (Backend)
import Hasura.RQL.Types.Column
  ( ColumnInfo (ciColumn),
    ColumnValue (cvType),
  )
import Hasura.RQL.Types.Common
  ( FieldName (FieldName),
    JsonAggSelect (JASMultipleRows),
  )
import Hasura.RQL.Types.Subscription
  ( CursorOrdering (CODescending),
  )
import Hasura.SQL.Backend (BackendType (Postgres))
import Hasura.SQL.Types
  ( CollectableType (CollectableTypeArray, CollectableTypeScalar),
    ToSQL (toSQL),
  )

selectStreamQuerySQL ::
  forall pgKind.
  (Backend ('Postgres pgKind), PostgresAnnotatedFieldJSON pgKind) =>
  AnnSimpleStreamSelect ('Postgres pgKind) ->
  Query
selectStreamQuerySQL :: AnnSimpleStreamSelect ('Postgres pgKind) -> Query
selectStreamQuerySQL AnnSimpleStreamSelect ('Postgres pgKind)
sel =
  Builder -> Query
fromBuilder (Builder -> Query) -> Builder -> Query
forall a b. (a -> b) -> a -> b
$ Select -> Builder
forall a. ToSQL a => a -> Builder
toSQL (Select -> Builder) -> Select -> Builder
forall a b. (a -> b) -> a -> b
$ AnnSimpleStreamSelect ('Postgres pgKind) -> Select
forall (pgKind :: PostgresKind).
(Backend ('Postgres pgKind), PostgresAnnotatedFieldJSON pgKind) =>
AnnSimpleStreamSelect ('Postgres pgKind) -> Select
mkStreamSQLSelect AnnSimpleStreamSelect ('Postgres pgKind)
sel

mkStreamSQLSelect ::
  forall pgKind.
  ( Backend ('Postgres pgKind),
    PostgresAnnotatedFieldJSON pgKind
  ) =>
  AnnSimpleStreamSelect ('Postgres pgKind) ->
  S.Select
mkStreamSQLSelect :: AnnSimpleStreamSelect ('Postgres pgKind) -> Select
mkStreamSQLSelect (AnnSelectStreamG () Fields
  (AnnFieldG
     ('Postgres pgKind) Void (SQLExpression ('Postgres pgKind)))
fields SelectFromG ('Postgres pgKind) (SQLExpression ('Postgres pgKind))
from TablePermG ('Postgres pgKind) (SQLExpression ('Postgres pgKind))
perm SelectStreamArgsG
  ('Postgres pgKind) (SQLExpression ('Postgres pgKind))
args StringifyNumbers
strfyNum) =
  let cursorArg :: StreamCursorItem ('Postgres pgKind)
cursorArg = SelectStreamArgsG ('Postgres pgKind) SQLExp
-> StreamCursorItem ('Postgres pgKind)
forall (b :: BackendType) v.
SelectStreamArgsG b v -> StreamCursorItem b
_ssaCursorArg SelectStreamArgsG
  ('Postgres pgKind) (SQLExpression ('Postgres pgKind))
SelectStreamArgsG ('Postgres pgKind) SQLExp
args
      cursorColInfo :: ColumnInfo ('Postgres pgKind)
cursorColInfo = StreamCursorItem ('Postgres pgKind)
-> ColumnInfo ('Postgres pgKind)
forall (b :: BackendType). StreamCursorItem b -> ColumnInfo b
_sciColInfo StreamCursorItem ('Postgres pgKind)
cursorArg
      annOrderbyCol :: AnnotatedOrderByElement ('Postgres pgKind) SQLExp
annOrderbyCol = ColumnInfo ('Postgres pgKind)
-> AnnotatedOrderByElement ('Postgres pgKind) SQLExp
forall (b :: BackendType) v.
ColumnInfo b -> AnnotatedOrderByElement b v
AOCColumn ColumnInfo ('Postgres pgKind)
cursorColInfo
      basicOrderType :: OrderType
basicOrderType =
        OrderType -> OrderType -> Bool -> OrderType
forall a. a -> a -> Bool -> a
bool OrderType
S.OTAsc OrderType
S.OTDesc (Bool -> OrderType) -> Bool -> OrderType
forall a b. (a -> b) -> a -> b
$ StreamCursorItem ('Postgres pgKind) -> CursorOrdering
forall (b :: BackendType). StreamCursorItem b -> CursorOrdering
_sciOrdering StreamCursorItem ('Postgres pgKind)
cursorArg CursorOrdering -> CursorOrdering -> Bool
forall a. Eq a => a -> a -> Bool
== CursorOrdering
CODescending
      orderByItems :: Maybe
  (NonEmpty
     (OrderByItemG
        ('Postgres pgKind)
        (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)))
orderByItems =
        [OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)]
-> Maybe
     (NonEmpty
        (OrderByItemG
           ('Postgres pgKind)
           (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)))
forall a. [a] -> Maybe (NonEmpty a)
nonEmpty ([OrderByItemG
    ('Postgres pgKind)
    (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)]
 -> Maybe
      (NonEmpty
         (OrderByItemG
            ('Postgres pgKind)
            (AnnotatedOrderByElement ('Postgres pgKind) SQLExp))))
-> [OrderByItemG
      ('Postgres pgKind)
      (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)]
-> Maybe
     (NonEmpty
        (OrderByItemG
           ('Postgres pgKind)
           (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)))
forall a b. (a -> b) -> a -> b
$ OrderByItemG
  ('Postgres pgKind)
  (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)
-> [OrderByItemG
      ('Postgres pgKind)
      (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (OrderByItemG
   ('Postgres pgKind)
   (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)
 -> [OrderByItemG
       ('Postgres pgKind)
       (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)])
-> OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)
-> [OrderByItemG
      ('Postgres pgKind)
      (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)]
forall a b. (a -> b) -> a -> b
$ Maybe (BasicOrderType ('Postgres pgKind))
-> AnnotatedOrderByElement ('Postgres pgKind) SQLExp
-> Maybe (NullsOrderType ('Postgres pgKind))
-> OrderByItemG
     ('Postgres pgKind)
     (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)
forall (b :: BackendType) a.
Maybe (BasicOrderType b)
-> a -> Maybe (NullsOrderType b) -> OrderByItemG b a
OrderByItemG (OrderType -> Maybe OrderType
forall a. a -> Maybe a
Just OrderType
basicOrderType) AnnotatedOrderByElement ('Postgres pgKind) SQLExp
annOrderbyCol Maybe (NullsOrderType ('Postgres pgKind))
forall a. Maybe a
Nothing
      cursorBoolExp :: GBoolExp
  ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
cursorBoolExp =
        let orderByOpExp :: SQLExp -> OpExpG ('Postgres pgKind) SQLExp
orderByOpExp = (SQLExp -> OpExpG ('Postgres pgKind) SQLExp)
-> (SQLExp -> OpExpG ('Postgres pgKind) SQLExp)
-> Bool
-> SQLExp
-> OpExpG ('Postgres pgKind) SQLExp
forall a. a -> a -> Bool -> a
bool SQLExp -> OpExpG ('Postgres pgKind) SQLExp
forall (backend :: BackendType) field.
field -> OpExpG backend field
ALT SQLExp -> OpExpG ('Postgres pgKind) SQLExp
forall (backend :: BackendType) field.
field -> OpExpG backend field
AGT (Bool -> SQLExp -> OpExpG ('Postgres pgKind) SQLExp)
-> Bool -> SQLExp -> OpExpG ('Postgres pgKind) SQLExp
forall a b. (a -> b) -> a -> b
$ OrderType
basicOrderType OrderType -> OrderType -> Bool
forall a. Eq a => a -> a -> Bool
== OrderType
S.OTAsc
            sqlExp :: SQLExp
sqlExp =
              CollectableType PGScalarType -> [Text] -> SQLExp
fromResVars
                (PGScalarType -> CollectableType PGScalarType
forall a. a -> CollectableType a
CollectableTypeScalar (PGScalarType -> CollectableType PGScalarType)
-> PGScalarType -> CollectableType PGScalarType
forall a b. (a -> b) -> a -> b
$ ColumnType ('Postgres pgKind) -> PGScalarType
forall (pgKind :: PostgresKind).
ColumnType ('Postgres pgKind) -> PGScalarType
unsafePGColumnToBackend (ColumnType ('Postgres pgKind) -> PGScalarType)
-> ColumnType ('Postgres pgKind) -> PGScalarType
forall a b. (a -> b) -> a -> b
$ ColumnValue ('Postgres pgKind) -> ColumnType ('Postgres pgKind)
forall (b :: BackendType). ColumnValue b -> ColumnType b
cvType (StreamCursorItem ('Postgres pgKind)
-> ColumnValue ('Postgres pgKind)
forall (b :: BackendType). StreamCursorItem b -> ColumnValue b
_sciInitialValue StreamCursorItem ('Postgres pgKind)
cursorArg))
                [Text
"cursor", PGCol -> Text
getPGColTxt (PGCol -> Text) -> PGCol -> Text
forall a b. (a -> b) -> a -> b
$ ColumnInfo ('Postgres pgKind) -> Column ('Postgres pgKind)
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo ('Postgres pgKind)
cursorColInfo]
         in AnnBoolExpFld ('Postgres pgKind) SQLExp
-> GBoolExp
     ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
forall (backend :: BackendType) field.
field -> GBoolExp backend field
BoolField (AnnBoolExpFld ('Postgres pgKind) SQLExp
 -> GBoolExp
      ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp))
-> AnnBoolExpFld ('Postgres pgKind) SQLExp
-> GBoolExp
     ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
forall a b. (a -> b) -> a -> b
$ ColumnInfo ('Postgres pgKind)
-> [OpExpG ('Postgres pgKind) SQLExp]
-> AnnBoolExpFld ('Postgres pgKind) SQLExp
forall (backend :: BackendType) leaf.
ColumnInfo backend
-> [OpExpG backend leaf] -> AnnBoolExpFld backend leaf
AVColumn ColumnInfo ('Postgres pgKind)
cursorColInfo [(SQLExp -> OpExpG ('Postgres pgKind) SQLExp
orderByOpExp SQLExp
sqlExp)]

      selectArgs :: SelectArgsG ('Postgres pgKind) SQLExp
selectArgs =
        SelectArgsG ('Postgres pgKind) Any
forall (backend :: BackendType) v. SelectArgsG backend v
noSelectArgs
          { $sel:_saWhere:SelectArgs :: Maybe
  (GBoolExp
     ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp))
_saWhere =
              GBoolExp
  ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
-> Maybe
     (GBoolExp
        ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp))
forall a. a -> Maybe a
Just (GBoolExp
   ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
 -> Maybe
      (GBoolExp
         ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)))
-> GBoolExp
     ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
-> Maybe
     (GBoolExp
        ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp))
forall a b. (a -> b) -> a -> b
$ GBoolExp
  ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
-> (GBoolExp
      ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
    -> GBoolExp
         ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp))
-> Maybe
     (GBoolExp
        ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp))
-> GBoolExp
     ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe GBoolExp
  ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
cursorBoolExp (GBoolExp
  ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
-> GBoolExp
     ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
-> GBoolExp
     ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
forall (backend :: BackendType) scalar.
AnnBoolExp backend scalar
-> AnnBoolExp backend scalar -> AnnBoolExp backend scalar
andAnnBoolExps GBoolExp
  ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
cursorBoolExp) (Maybe
   (GBoolExp
      ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp))
 -> GBoolExp
      ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp))
-> Maybe
     (GBoolExp
        ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp))
-> GBoolExp
     ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp)
forall a b. (a -> b) -> a -> b
$ SelectStreamArgsG ('Postgres pgKind) SQLExp
-> Maybe
     (GBoolExp
        ('Postgres pgKind) (AnnBoolExpFld ('Postgres pgKind) SQLExp))
forall (b :: BackendType) v.
SelectStreamArgsG b v -> Maybe (AnnBoolExp b v)
_ssaWhere SelectStreamArgsG
  ('Postgres pgKind) (SQLExpression ('Postgres pgKind))
SelectStreamArgsG ('Postgres pgKind) SQLExp
args,
            $sel:_saOrderBy:SelectArgs :: Maybe
  (NonEmpty
     (OrderByItemG
        ('Postgres pgKind)
        (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)))
_saOrderBy = Maybe
  (NonEmpty
     (OrderByItemG
        ('Postgres pgKind)
        (AnnotatedOrderByElement ('Postgres pgKind) SQLExp)))
orderByItems,
            $sel:_saLimit:SelectArgs :: Maybe Int
_saLimit = Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$ SelectStreamArgsG ('Postgres pgKind) SQLExp -> Int
forall (b :: BackendType) v. SelectStreamArgsG b v -> Int
_ssaBatchSize SelectStreamArgsG
  ('Postgres pgKind) (SQLExpression ('Postgres pgKind))
SelectStreamArgsG ('Postgres pgKind) SQLExp
args
          }
      sqlSelect :: AnnSelectG
  ('Postgres pgKind) (AnnFieldG ('Postgres pgKind) Void) SQLExp
sqlSelect = Fields (AnnFieldG ('Postgres pgKind) Void SQLExp)
-> SelectFromG ('Postgres pgKind) SQLExp
-> TablePermG ('Postgres pgKind) SQLExp
-> SelectArgsG ('Postgres pgKind) SQLExp
-> StringifyNumbers
-> Maybe NamingCase
-> AnnSelectG
     ('Postgres pgKind) (AnnFieldG ('Postgres pgKind) Void) SQLExp
forall (b :: BackendType) (f :: * -> *) v.
Fields (f v)
-> SelectFromG b v
-> TablePermG b v
-> SelectArgsG b v
-> StringifyNumbers
-> Maybe NamingCase
-> AnnSelectG b f v
AnnSelectG Fields
  (AnnFieldG
     ('Postgres pgKind) Void (SQLExpression ('Postgres pgKind)))
Fields (AnnFieldG ('Postgres pgKind) Void SQLExp)
fields SelectFromG ('Postgres pgKind) (SQLExpression ('Postgres pgKind))
SelectFromG ('Postgres pgKind) SQLExp
from TablePermG ('Postgres pgKind) (SQLExpression ('Postgres pgKind))
TablePermG ('Postgres pgKind) SQLExp
perm SelectArgsG ('Postgres pgKind) SQLExp
selectArgs StringifyNumbers
strfyNum Maybe NamingCase
forall a. Maybe a
Nothing
      permLimitSubQuery :: PermissionLimitSubQuery
permLimitSubQuery = PermissionLimitSubQuery
PLSQNotRequired
      ((SelectSource
selectSource, HashMap ColumnAlias SQLExp
nodeExtractors), JoinTree
joinTree) =
        Writer JoinTree (SelectSource, HashMap ColumnAlias SQLExp)
-> ((SelectSource, HashMap ColumnAlias SQLExp), JoinTree)
forall w a. Writer w a -> (a, w)
runWriter (Writer JoinTree (SelectSource, HashMap ColumnAlias SQLExp)
 -> ((SelectSource, HashMap ColumnAlias SQLExp), JoinTree))
-> Writer JoinTree (SelectSource, HashMap ColumnAlias SQLExp)
-> ((SelectSource, HashMap ColumnAlias SQLExp), JoinTree)
forall a b. (a -> b) -> a -> b
$
          (ReaderT
   StringifyNumbers
   (WriterT JoinTree Identity)
   (SelectSource, HashMap ColumnAlias SQLExp)
 -> StringifyNumbers
 -> Writer JoinTree (SelectSource, HashMap ColumnAlias SQLExp))
-> StringifyNumbers
-> ReaderT
     StringifyNumbers
     (WriterT JoinTree Identity)
     (SelectSource, HashMap ColumnAlias SQLExp)
-> Writer JoinTree (SelectSource, HashMap ColumnAlias SQLExp)
forall a b c. (a -> b -> c) -> b -> a -> c
flip ReaderT
  StringifyNumbers
  (WriterT JoinTree Identity)
  (SelectSource, HashMap ColumnAlias SQLExp)
-> StringifyNumbers
-> Writer JoinTree (SelectSource, HashMap ColumnAlias SQLExp)
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT StringifyNumbers
strfyNum (ReaderT
   StringifyNumbers
   (WriterT JoinTree Identity)
   (SelectSource, HashMap ColumnAlias SQLExp)
 -> Writer JoinTree (SelectSource, HashMap ColumnAlias SQLExp))
-> ReaderT
     StringifyNumbers
     (WriterT JoinTree Identity)
     (SelectSource, HashMap ColumnAlias SQLExp)
-> Writer JoinTree (SelectSource, HashMap ColumnAlias SQLExp)
forall a b. (a -> b) -> a -> b
$
            SourcePrefixes
-> FieldName
-> PermissionLimitSubQuery
-> AnnSimpleSelect ('Postgres pgKind)
-> ReaderT
     StringifyNumbers
     (WriterT JoinTree Identity)
     (SelectSource, HashMap ColumnAlias SQLExp)
forall (pgKind :: PostgresKind) (m :: * -> *).
(MonadReader StringifyNumbers m, MonadWriter JoinTree m,
 Backend ('Postgres pgKind), PostgresAnnotatedFieldJSON pgKind) =>
SourcePrefixes
-> FieldName
-> PermissionLimitSubQuery
-> AnnSimpleSelect ('Postgres pgKind)
-> m (SelectSource, HashMap ColumnAlias SQLExp)
processAnnSimpleSelect SourcePrefixes
sourcePrefixes FieldName
rootFldName PermissionLimitSubQuery
permLimitSubQuery AnnSimpleSelect ('Postgres pgKind)
AnnSelectG
  ('Postgres pgKind) (AnnFieldG ('Postgres pgKind) Void) SQLExp
sqlSelect
      selectNode :: SelectNode
selectNode = HashMap ColumnAlias SQLExp -> JoinTree -> SelectNode
SelectNode HashMap ColumnAlias SQLExp
nodeExtractors JoinTree
joinTree
      topExtractor :: Extractor
topExtractor =
        JsonAggSelect
-> ColumnAlias
-> PermissionLimitSubQuery
-> Maybe OrderByExp
-> Extractor
asJsonAggExtr JsonAggSelect
JASMultipleRows ColumnAlias
rootFldAls PermissionLimitSubQuery
permLimitSubQuery (Maybe OrderByExp -> Extractor) -> Maybe OrderByExp -> Extractor
forall a b. (a -> b) -> a -> b
$
          SelectSource -> Maybe OrderByExp
orderByForJsonAgg SelectSource
selectSource
      SQLExp
cursorLatestValueExp :: S.SQLExp =
        let pgColumn :: Column ('Postgres pgKind)
pgColumn = ColumnInfo ('Postgres pgKind) -> Column ('Postgres pgKind)
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo ('Postgres pgKind)
cursorColInfo
            mkMaxOrMinSQLExp :: Text -> Identifier -> SQLExp
mkMaxOrMinSQLExp Text
maxOrMin Identifier
col =
              Text -> [SQLExp] -> Maybe OrderByExp -> SQLExp
S.SEFnApp Text
maxOrMin [Identifier -> SQLExp
S.SEIdentifier Identifier
col] Maybe OrderByExp
forall a. Maybe a
Nothing
            maxOrMinTxt :: Text
maxOrMinTxt = Text -> Text -> Bool -> Text
forall a. a -> a -> Bool -> a
bool Text
"MIN" Text
"MAX" (Bool -> Text) -> Bool -> Text
forall a b. (a -> b) -> a -> b
$ OrderType
basicOrderType OrderType -> OrderType -> Bool
forall a. Eq a => a -> a -> Bool
== OrderType
S.OTAsc
            -- text encoding the cursor value while it's fetched from the DB, because
            -- we can then directly reuse this value, otherwise if this were json encoded
            -- then we'd have to parse the value and then convert it into a text encoded value
            colExp :: [SQLExp]
colExp =
              [ Text -> SQLExp
S.SELit (PGCol -> Text
getPGColTxt Column ('Postgres pgKind)
PGCol
pgColumn),
                SQLExp -> TypeAnn -> SQLExp
S.SETyAnn
                  (Text -> Identifier -> SQLExp
mkMaxOrMinSQLExp Text
maxOrMinTxt (Identifier -> SQLExp) -> Identifier -> SQLExp
forall a b. (a -> b) -> a -> b
$ ColumnAlias -> Identifier
forall a. IsIdentifier a => a -> Identifier
toIdentifier (ColumnAlias -> Identifier) -> ColumnAlias -> Identifier
forall a b. (a -> b) -> a -> b
$ Identifier -> PGCol -> ColumnAlias
mkBaseTableColumnAlias Identifier
rootFldIdentifier Column ('Postgres pgKind)
PGCol
pgColumn)
                  TypeAnn
S.textTypeAnn
              ]
         in -- SELECT json_build_object ('col1', MAX(col1) :: text)

            Text -> [SQLExp] -> Maybe OrderByExp -> SQLExp
S.SEFnApp Text
"json_build_object" [SQLExp]
colExp Maybe OrderByExp
forall a. Maybe a
Nothing
      cursorLatestValueExtractor :: Extractor
cursorLatestValueExtractor = SQLExp -> Maybe ColumnAlias -> Extractor
S.Extractor SQLExp
cursorLatestValueExp (ColumnAlias -> Maybe ColumnAlias
forall a. a -> Maybe a
Just (ColumnAlias -> Maybe ColumnAlias)
-> ColumnAlias -> Maybe ColumnAlias
forall a b. (a -> b) -> a -> b
$ Identifier -> ColumnAlias
forall a. IsIdentifier a => a -> ColumnAlias
S.toColumnAlias (Identifier -> ColumnAlias) -> Identifier -> ColumnAlias
forall a b. (a -> b) -> a -> b
$ Text -> Identifier
Identifier Text
"cursor")
      arrayNode :: MultiRowSelectNode
arrayNode = [Extractor] -> SelectNode -> MultiRowSelectNode
MultiRowSelectNode [Extractor
topExtractor, Extractor
cursorLatestValueExtractor] SelectNode
selectNode
   in Select -> Select
renameIdentifiers (Select -> Select) -> Select -> Select
forall a b. (a -> b) -> a -> b
$
        SelectSource -> MultiRowSelectNode -> BoolExp -> Select
generateSQLSelectFromArrayNode SelectSource
selectSource MultiRowSelectNode
arrayNode (BoolExp -> Select) -> BoolExp -> Select
forall a b. (a -> b) -> a -> b
$ Bool -> BoolExp
S.BELit Bool
True
  where
    rootFldIdentifier :: Identifier
rootFldIdentifier = FieldName -> Identifier
forall a. IsIdentifier a => a -> Identifier
toIdentifier FieldName
rootFldName
    sourcePrefixes :: SourcePrefixes
sourcePrefixes = Identifier -> Identifier -> SourcePrefixes
SourcePrefixes Identifier
rootFldIdentifier Identifier
rootFldIdentifier
    rootFldName :: FieldName
rootFldName = Text -> FieldName
FieldName Text
"root"
    rootFldAls :: ColumnAlias
rootFldAls = Identifier -> ColumnAlias
forall a. IsIdentifier a => a -> ColumnAlias
S.toColumnAlias (Identifier -> ColumnAlias) -> Identifier -> ColumnAlias
forall a b. (a -> b) -> a -> b
$ FieldName -> Identifier
forall a. IsIdentifier a => a -> Identifier
toIdentifier FieldName
rootFldName

    -- TODO: these functions also exist in `resolveMultiplexedValue`, de-duplicate these!
    fromResVars :: CollectableType PGScalarType -> [Text] -> SQLExp
fromResVars CollectableType PGScalarType
pgType [Text]
jPath =
      CollectableType PGScalarType -> SQLExp -> SQLExp
addTypeAnnotation CollectableType PGScalarType
pgType (SQLExp -> SQLExp) -> SQLExp -> SQLExp
forall a b. (a -> b) -> a -> b
$
        SQLOp -> [SQLExp] -> SQLExp
S.SEOpApp
          (Text -> SQLOp
S.SQLOp Text
"#>>")
          [ QIdentifier -> SQLExp
S.SEQIdentifier (QIdentifier -> SQLExp) -> QIdentifier -> SQLExp
forall a b. (a -> b) -> a -> b
$ Qual -> Identifier -> QIdentifier
S.QIdentifier (Identifier -> Maybe TypeAnn -> Qual
S.QualifiedIdentifier (Text -> Identifier
Identifier Text
"_subs") Maybe TypeAnn
forall a. Maybe a
Nothing) (Text -> Identifier
Identifier Text
"result_vars"),
            [SQLExp] -> SQLExp
S.SEArray ([SQLExp] -> SQLExp) -> [SQLExp] -> SQLExp
forall a b. (a -> b) -> a -> b
$ (Text -> SQLExp) -> [Text] -> [SQLExp]
forall a b. (a -> b) -> [a] -> [b]
map Text -> SQLExp
S.SELit [Text]
jPath
          ]
    addTypeAnnotation :: CollectableType PGScalarType -> SQLExp -> SQLExp
addTypeAnnotation CollectableType PGScalarType
pgType =
      (SQLExp -> TypeAnn -> SQLExp) -> TypeAnn -> SQLExp -> SQLExp
forall a b c. (a -> b -> c) -> b -> a -> c
flip SQLExp -> TypeAnn -> SQLExp
S.SETyAnn (CollectableType PGScalarType -> TypeAnn
S.mkTypeAnn CollectableType PGScalarType
pgType) (SQLExp -> SQLExp) -> (SQLExp -> SQLExp) -> SQLExp -> SQLExp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. case CollectableType PGScalarType
pgType of
        CollectableTypeScalar PGScalarType
scalarType -> PGScalarType -> SQLExp -> SQLExp
withConstructorFn PGScalarType
scalarType
        CollectableTypeArray PGScalarType
_ -> SQLExp -> SQLExp
forall a. a -> a
id