-- | 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)
import Hasura.Backends.Postgres.SQL.DML qualified as S
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 (contextualizeBaseTableColumn)
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.Helpers (selectToSelectWith, toQuery)
import Hasura.Backends.Postgres.Translate.Select.Internal.Process (processAnnSimpleSelect)
import Hasura.Backends.Postgres.Translate.Types
  ( CustomSQLCTEs,
    MultiRowSelectNode (MultiRowSelectNode),
    PermissionLimitSubQuery (PLSQNotRequired),
    SelectNode (SelectNode),
    SelectWriter (..),
    SourcePrefixes (SourcePrefixes),
    initialNativeQueryFreshIdStore,
    orderByForJsonAgg,
  )
import Hasura.Backends.Postgres.Types.Column (unsafePGColumnToBackend)
import Hasura.Prelude
import Hasura.RQL.IR.BoolExp
  ( AnnBoolExpFld (AVColumn),
    AnnRedactionExp (..),
    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.BackendType (BackendType (Postgres))
import Hasura.RQL.Types.Column
  ( ColumnInfo (ciColumn, ciName),
    ColumnValue (cvType),
  )
import Hasura.RQL.Types.Common
  ( FieldName (FieldName),
    JsonAggSelect (JASMultipleRows),
    getFieldNameTxt,
  )
import Hasura.RQL.Types.Subscription
  ( CursorOrdering (CODescending),
  )
import Hasura.SQL.Types
  ( CollectableType (CollectableTypeArray, CollectableTypeScalar),
  )
import Language.GraphQL.Draft.Syntax qualified as G

selectStreamQuerySQL ::
  forall pgKind.
  (Backend ('Postgres pgKind), PostgresAnnotatedFieldJSON pgKind) =>
  AnnSimpleStreamSelect ('Postgres pgKind) ->
  Query
selectStreamQuerySQL :: forall (pgKind :: PostgresKind).
(Backend ('Postgres pgKind), PostgresAnnotatedFieldJSON pgKind) =>
AnnSimpleStreamSelect ('Postgres pgKind) -> Query
selectStreamQuerySQL =
  SelectWithG TopLevelCTE -> Query
toQuery
    (SelectWithG TopLevelCTE -> Query)
-> (AnnSimpleStreamSelectG ('Postgres pgKind) Void SQLExp
    -> SelectWithG TopLevelCTE)
-> AnnSimpleStreamSelectG ('Postgres pgKind) Void SQLExp
-> Query
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Writer CustomSQLCTEs Select -> SelectWithG TopLevelCTE
selectToSelectWith
    (Writer CustomSQLCTEs Select -> SelectWithG TopLevelCTE)
-> (AnnSimpleStreamSelectG ('Postgres pgKind) Void SQLExp
    -> Writer CustomSQLCTEs Select)
-> AnnSimpleStreamSelectG ('Postgres pgKind) Void SQLExp
-> SelectWithG TopLevelCTE
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AnnSelectStreamG
  ('Postgres pgKind)
  (AnnFieldG ('Postgres pgKind) Void)
  (SQLExpression ('Postgres pgKind))
-> Writer CustomSQLCTEs Select
AnnSimpleStreamSelectG ('Postgres pgKind) Void SQLExp
-> Writer CustomSQLCTEs Select
forall (pgKind :: PostgresKind) (m :: * -> *).
(Backend ('Postgres pgKind), PostgresAnnotatedFieldJSON pgKind,
 MonadWriter CustomSQLCTEs m) =>
AnnSimpleStreamSelect ('Postgres pgKind) -> m Select
mkStreamSQLSelect

mkStreamSQLSelect ::
  forall pgKind m.
  ( Backend ('Postgres pgKind),
    PostgresAnnotatedFieldJSON pgKind,
    MonadWriter CustomSQLCTEs m
  ) =>
  AnnSimpleStreamSelect ('Postgres pgKind) ->
  m S.Select
mkStreamSQLSelect :: forall (pgKind :: PostgresKind) (m :: * -> *).
(Backend ('Postgres pgKind), PostgresAnnotatedFieldJSON pgKind,
 MonadWriter CustomSQLCTEs m) =>
AnnSimpleStreamSelect ('Postgres pgKind) -> m 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) = do
  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)
-> AnnRedactionExp ('Postgres pgKind) SQLExp
-> AnnotatedOrderByElement ('Postgres pgKind) SQLExp
forall (b :: BackendType) v.
ColumnInfo b -> AnnRedactionExp b v -> AnnotatedOrderByElement b v
AOCColumn ColumnInfo ('Postgres pgKind)
cursorColInfo AnnRedactionExp ('Postgres pgKind) SQLExp
forall (b :: BackendType) v. AnnRedactionExp b v
NoRedaction -- TODO(redactionExp): Does a redaction expression need to go here?
      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 a. a -> [a]
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))
Maybe NullsOrder
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", Name -> Text
G.unName (Name -> Text) -> Name -> Text
forall a b. (a -> b) -> a -> b
$ ColumnInfo ('Postgres pgKind) -> Name
forall (b :: BackendType). ColumnInfo b -> Name
ciName 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) SQLExp
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, InsOrdHashMap ColumnAlias SQLExp
nodeExtractors), SelectWriter {_swJoinTree :: SelectWriter -> JoinTree
_swJoinTree = JoinTree
joinTree, _swCustomSQLCTEs :: SelectWriter -> CustomSQLCTEs
_swCustomSQLCTEs = CustomSQLCTEs
customSQLCTEs}) =
        Writer
  SelectWriter (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
-> ((SelectSource, InsOrdHashMap ColumnAlias SQLExp), SelectWriter)
forall w a. Writer w a -> (a, w)
runWriter
          (Writer
   SelectWriter (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
 -> ((SelectSource, InsOrdHashMap ColumnAlias SQLExp),
     SelectWriter))
-> Writer
     SelectWriter (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
-> ((SelectSource, InsOrdHashMap ColumnAlias SQLExp), SelectWriter)
forall a b. (a -> b) -> a -> b
$ (ReaderT
   StringifyNumbers
   (WriterT SelectWriter Identity)
   (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
 -> StringifyNumbers
 -> Writer
      SelectWriter (SelectSource, InsOrdHashMap ColumnAlias SQLExp))
-> StringifyNumbers
-> ReaderT
     StringifyNumbers
     (WriterT SelectWriter Identity)
     (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
-> Writer
     SelectWriter (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
forall a b c. (a -> b -> c) -> b -> a -> c
flip ReaderT
  StringifyNumbers
  (WriterT SelectWriter Identity)
  (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
-> StringifyNumbers
-> Writer
     SelectWriter (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT StringifyNumbers
strfyNum
          (ReaderT
   StringifyNumbers
   (WriterT SelectWriter Identity)
   (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
 -> Writer
      SelectWriter (SelectSource, InsOrdHashMap ColumnAlias SQLExp))
-> ReaderT
     StringifyNumbers
     (WriterT SelectWriter Identity)
     (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
-> Writer
     SelectWriter (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
forall a b. (a -> b) -> a -> b
$ (StateT
   NativeQueryFreshIdStore
   (ReaderT StringifyNumbers (WriterT SelectWriter Identity))
   (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
 -> NativeQueryFreshIdStore
 -> ReaderT
      StringifyNumbers
      (WriterT SelectWriter Identity)
      (SelectSource, InsOrdHashMap ColumnAlias SQLExp))
-> NativeQueryFreshIdStore
-> StateT
     NativeQueryFreshIdStore
     (ReaderT StringifyNumbers (WriterT SelectWriter Identity))
     (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
-> ReaderT
     StringifyNumbers
     (WriterT SelectWriter Identity)
     (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
forall a b c. (a -> b -> c) -> b -> a -> c
flip StateT
  NativeQueryFreshIdStore
  (ReaderT StringifyNumbers (WriterT SelectWriter Identity))
  (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
-> NativeQueryFreshIdStore
-> ReaderT
     StringifyNumbers
     (WriterT SelectWriter Identity)
     (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m a
evalStateT NativeQueryFreshIdStore
initialNativeQueryFreshIdStore
          (StateT
   NativeQueryFreshIdStore
   (ReaderT StringifyNumbers (WriterT SelectWriter Identity))
   (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
 -> ReaderT
      StringifyNumbers
      (WriterT SelectWriter Identity)
      (SelectSource, InsOrdHashMap ColumnAlias SQLExp))
-> StateT
     NativeQueryFreshIdStore
     (ReaderT StringifyNumbers (WriterT SelectWriter Identity))
     (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
-> ReaderT
     StringifyNumbers
     (WriterT SelectWriter Identity)
     (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
forall a b. (a -> b) -> a -> b
$ SourcePrefixes
-> FieldName
-> PermissionLimitSubQuery
-> AnnSimpleSelect ('Postgres pgKind)
-> StateT
     NativeQueryFreshIdStore
     (ReaderT StringifyNumbers (WriterT SelectWriter Identity))
     (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
forall (pgKind :: PostgresKind) (m :: * -> *).
(MonadReader StringifyNumbers m,
 MonadState NativeQueryFreshIdStore m, MonadWriter SelectWriter m,
 Backend ('Postgres pgKind), PostgresAnnotatedFieldJSON pgKind) =>
SourcePrefixes
-> FieldName
-> PermissionLimitSubQuery
-> AnnSimpleSelect ('Postgres pgKind)
-> m (SelectSource, InsOrdHashMap ColumnAlias SQLExp)
processAnnSimpleSelect SourcePrefixes
sourcePrefixes FieldName
rootFldName PermissionLimitSubQuery
permLimitSubQuery AnnSimpleSelect ('Postgres pgKind)
AnnSelectG
  ('Postgres pgKind) (AnnFieldG ('Postgres pgKind) Void) SQLExp
sqlSelect
      selectNode :: SelectNode
selectNode = InsOrdHashMap ColumnAlias SQLExp -> JoinTree -> SelectNode
SelectNode InsOrdHashMap 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 columnAlias :: Name
columnAlias = ColumnInfo ('Postgres pgKind) -> Name
forall (b :: BackendType). ColumnInfo b -> Name
ciName ColumnInfo ('Postgres pgKind)
cursorColInfo
            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 (Name -> Text
G.unName Name
columnAlias),
                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
$ TableIdentifier -> PGCol -> ColumnAlias
contextualizeBaseTableColumn TableIdentifier
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
  CustomSQLCTEs -> m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell CustomSQLCTEs
customSQLCTEs

  Select -> m Select
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Select -> m Select) -> Select -> m 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 :: TableIdentifier
rootFldIdentifier = Text -> TableIdentifier
TableIdentifier (Text -> TableIdentifier) -> Text -> TableIdentifier
forall a b. (a -> b) -> a -> b
$ FieldName -> Text
getFieldNameTxt FieldName
rootFldName
    sourcePrefixes :: SourcePrefixes
sourcePrefixes = Identifier -> Identifier -> SourcePrefixes
SourcePrefixes (TableIdentifier -> Identifier
tableIdentifierToIdentifier TableIdentifier
rootFldIdentifier) (TableIdentifier -> Identifier
tableIdentifierToIdentifier TableIdentifier
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 (TableIdentifier -> Maybe TypeAnn -> Qual
S.QualifiedIdentifier (Text -> TableIdentifier
TableIdentifier 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