{-# LANGUAGE ViewPatterns #-}

-- | This module defines translation functions for queries which select data.
-- Principally this includes translating the @query@ root field, but parts are
-- also reused for serving the responses for mutations.
module Hasura.Backends.MSSQL.FromIr.Query
  ( fromQueryRootField,
    fromSelect,
    fromSourceRelationship,
  )
where

import Control.Applicative (getConst)
import Control.Monad.Validate
import Data.Aeson.Extended qualified as J
import Data.HashMap.Strict qualified as HashMap
import Data.HashMap.Strict.InsOrd qualified as InsOrdHashMap
import Data.List.NonEmpty qualified as NE
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as M
import Data.Proxy
import Data.Text.Extended qualified as T
import Data.Text.NonEmpty (mkNonEmptyTextUnsafe)
import Database.ODBC.SQLServer qualified as ODBC
import Hasura.Backends.MSSQL.FromIr
  ( Error (..),
    FromIr,
    NameTemplate (..),
    generateAlias,
    tellAfter,
    tellBefore,
    tellCTE,
  )
import Hasura.Backends.MSSQL.FromIr.Constants
import Hasura.Backends.MSSQL.FromIr.Expression
import Hasura.Backends.MSSQL.Instances.Types ()
import Hasura.Backends.MSSQL.Types.Internal as TSQL
import Hasura.LogicalModel.Common (columnsFromFields)
import Hasura.LogicalModel.IR (LogicalModel (..))
import Hasura.NativeQuery.IR qualified as IR
import Hasura.NativeQuery.InterpolatedQuery
import Hasura.NativeQuery.Types (NativeQueryName (..))
import Hasura.Prelude
import Hasura.RQL.IR qualified as IR
import Hasura.RQL.Types.BackendType
import Hasura.RQL.Types.Column qualified as IR
import Hasura.RQL.Types.Common qualified as IR
import Hasura.RQL.Types.Relationships.Local qualified as IR
import Hasura.StoredProcedure.IR qualified as IR

-- | This is the top-level entry point for translation of Query root fields.
fromQueryRootField :: IR.QueryDB 'MSSQL Void Expression -> FromIr Select
fromQueryRootField :: QueryDB 'MSSQL Void Expression -> FromIr Select
fromQueryRootField =
  \case
    (IR.QDBSingleRow AnnSimpleSelectG 'MSSQL Void Expression
s) -> JsonAggSelect
-> AnnSimpleSelectG 'MSSQL Void Expression -> FromIr Select
fromSelect JsonAggSelect
IR.JASSingleObject AnnSimpleSelectG 'MSSQL Void Expression
s
    (IR.QDBMultipleRows AnnSimpleSelectG 'MSSQL Void Expression
s) -> JsonAggSelect
-> AnnSimpleSelectG 'MSSQL Void Expression -> FromIr Select
fromSelect JsonAggSelect
IR.JASMultipleRows AnnSimpleSelectG 'MSSQL Void Expression
s
    (IR.QDBAggregation AnnAggregateSelectG 'MSSQL Void Expression
s) -> Maybe (EntityAlias, HashMap ColumnName ColumnName)
-> AnnAggregateSelectG 'MSSQL Void Expression -> FromIr Select
fromSelectAggregate Maybe (EntityAlias, HashMap ColumnName ColumnName)
forall a. Maybe a
Nothing AnnAggregateSelectG 'MSSQL Void Expression
s

fromSelect ::
  IR.JsonAggSelect ->
  IR.AnnSelectG 'MSSQL (IR.AnnFieldG 'MSSQL Void) Expression ->
  FromIr TSQL.Select
fromSelect :: JsonAggSelect
-> AnnSimpleSelectG 'MSSQL Void Expression -> FromIr Select
fromSelect JsonAggSelect
jsonAggSelect AnnSimpleSelectG 'MSSQL Void Expression
annSimpleSel =
  case JsonAggSelect
jsonAggSelect of
    JsonAggSelect
IR.JASMultipleRows ->
      Expression -> Select -> Select
guardSelectYieldingNull Expression
emptyArrayExpression (Select -> Select) -> FromIr Select -> FromIr Select
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> AnnSimpleSelectG 'MSSQL Void Expression -> FromIr Select
fromSelectRows AnnSimpleSelectG 'MSSQL Void Expression
annSimpleSel
    JsonAggSelect
IR.JASSingleObject ->
      (Select -> Select) -> FromIr Select -> FromIr Select
forall a b. (a -> b) -> FromIr a -> FromIr b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Expression -> Select -> Select
guardSelectYieldingNull Expression
nullExpression)
        (FromIr Select -> FromIr Select) -> FromIr Select -> FromIr Select
forall a b. (a -> b) -> a -> b
$ AnnSimpleSelectG 'MSSQL Void Expression -> FromIr Select
fromSelectRows AnnSimpleSelectG 'MSSQL Void Expression
annSimpleSel
        FromIr Select -> (Select -> Select) -> FromIr Select
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \Select
sel ->
          Select
sel
            { $sel:selectFor:Select :: For
selectFor =
                ForJson -> For
JsonFor
                  ForJson {$sel:jsonCardinality:ForJson :: JsonCardinality
jsonCardinality = JsonCardinality
JsonSingleton, $sel:jsonRoot:ForJson :: Root
jsonRoot = Root
NoRoot},
              $sel:selectTop:Select :: Top
selectTop = Int -> Top
Top Int
1
            }
  where
    guardSelectYieldingNull :: TSQL.Expression -> TSQL.Select -> TSQL.Select
    guardSelectYieldingNull :: Expression -> Select -> Select
guardSelectYieldingNull Expression
fallbackExpression Select
select =
      let isNullApplication :: FunctionApplicationExpression
isNullApplication = Expression -> Expression -> FunctionApplicationExpression
FunExpISNULL (Select -> Expression
SelectExpression Select
select) Expression
fallbackExpression
       in Select
emptySelect
            { $sel:selectProjections:Select :: [Projection]
selectProjections =
                [ Aliased Expression -> Projection
ExpressionProjection
                    (Aliased Expression -> Projection)
-> Aliased Expression -> Projection
forall a b. (a -> b) -> a -> b
$ Aliased
                      { $sel:aliasedThing:Aliased :: Expression
aliasedThing = FunctionApplicationExpression -> Expression
FunctionApplicationExpression FunctionApplicationExpression
isNullApplication,
                        $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
"root"
                      }
                ]
            }

-- | Used in 'Hasura.Backends.MSSQL.Plan.planSourceRelationship', which is in
-- turn used by to implement `mkDBRemoteRelationship' for 'BackendExecute'.
-- For more information, see the module/documentation of 'Hasura.GraphQL.Execute.RemoteJoin.Source'.
fromSourceRelationship ::
  -- | List of json objects, each of which becomes a row of the table
  NE.NonEmpty J.Object ->
  -- | The above objects have this schema
  HashMap.HashMap IR.FieldName (ColumnName, ScalarType) ->
  IR.FieldName ->
  (IR.FieldName, IR.SourceRelationshipSelection 'MSSQL Void (Const Expression)) ->
  FromIr TSQL.Select
fromSourceRelationship :: NonEmpty Object
-> HashMap FieldName (ColumnName, ScalarType)
-> FieldName
-> (FieldName,
    SourceRelationshipSelection 'MSSQL Void (Const Expression))
-> FromIr Select
fromSourceRelationship NonEmpty Object
lhs HashMap FieldName (ColumnName, ScalarType)
lhsSchema FieldName
argumentId (FieldName,
 SourceRelationshipSelection 'MSSQL Void (Const Expression))
relationshipField = do
  (Expression
argumentIdQualified, FieldSource
fieldSource) <-
    (ReaderT EntityAlias FromIr (Expression, FieldSource)
 -> EntityAlias -> FromIr (Expression, FieldSource))
-> EntityAlias
-> ReaderT EntityAlias FromIr (Expression, FieldSource)
-> FromIr (Expression, FieldSource)
forall a b c. (a -> b -> c) -> b -> a -> c
flip ReaderT EntityAlias FromIr (Expression, FieldSource)
-> EntityAlias -> FromIr (Expression, FieldSource)
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (From -> EntityAlias
fromAlias From
selectFrom) (ReaderT EntityAlias FromIr (Expression, FieldSource)
 -> FromIr (Expression, FieldSource))
-> ReaderT EntityAlias FromIr (Expression, FieldSource)
-> FromIr (Expression, FieldSource)
forall a b. (a -> b) -> a -> b
$ do
      FieldName
argumentIdQualified <- ColumnName -> ReaderT EntityAlias FromIr FieldName
fromColumn (FieldName -> ColumnName
coerceToColumn FieldName
argumentId)
      FieldSource
relationshipSource <-
        Map (Either NativeQueryName TableName) EntityAlias
-> HashMap ColumnName ColumnName
-> (FieldName,
    SourceRelationshipSelection 'MSSQL Void (Const Expression))
-> ReaderT EntityAlias FromIr FieldSource
fromRemoteRelationFieldsG
          Map (Either NativeQueryName TableName) EntityAlias
forall a. Monoid a => a
mempty
          ((ColumnName, ScalarType) -> ColumnName
forall a b. (a, b) -> a
fst ((ColumnName, ScalarType) -> ColumnName)
-> HashMap ColumnName (ColumnName, ScalarType)
-> HashMap ColumnName ColumnName
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HashMap ColumnName (ColumnName, ScalarType)
joinColumns)
          (FieldName,
 SourceRelationshipSelection 'MSSQL Void (Const Expression))
relationshipField
      (Expression, FieldSource)
-> ReaderT EntityAlias FromIr (Expression, FieldSource)
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FieldName -> Expression
ColumnExpression FieldName
argumentIdQualified, FieldSource
relationshipSource)
  let selectProjections :: [Projection]
selectProjections = [Expression -> Projection
projectArgumentId Expression
argumentIdQualified, FieldSource -> Projection
fieldSourceProjections FieldSource
fieldSource]
  Select -> FromIr Select
forall a. a -> FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    Select
      { $sel:selectWith:Select :: Maybe With
selectWith = Maybe With
forall a. Maybe a
Nothing,
        $sel:selectOrderBy:Select :: Maybe (NonEmpty OrderBy)
selectOrderBy = Maybe (NonEmpty OrderBy)
forall a. Maybe a
Nothing,
        $sel:selectTop:Select :: Top
selectTop = Top
NoTop,
        [Projection]
$sel:selectProjections:Select :: [Projection]
selectProjections :: [Projection]
selectProjections,
        $sel:selectFrom:Select :: Maybe From
selectFrom = From -> Maybe From
forall a. a -> Maybe a
Just From
selectFrom,
        $sel:selectJoins:Select :: [Join]
selectJoins = (FieldSource -> Maybe Join) -> [FieldSource] -> [Join]
forall a b. (a -> Maybe b) -> [a] -> [b]
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe FieldSource -> Maybe Join
fieldSourceJoin ([FieldSource] -> [Join]) -> [FieldSource] -> [Join]
forall a b. (a -> b) -> a -> b
$ FieldSource -> [FieldSource]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure FieldSource
fieldSource,
        $sel:selectWhere:Select :: Where
selectWhere = Where
forall a. Monoid a => a
mempty,
        $sel:selectFor:Select :: For
selectFor =
          ForJson -> For
JsonFor ForJson {$sel:jsonCardinality:ForJson :: JsonCardinality
jsonCardinality = JsonCardinality
JsonArray, $sel:jsonRoot:ForJson :: Root
jsonRoot = Root
NoRoot},
        $sel:selectOffset:Select :: Maybe Expression
selectOffset = Maybe Expression
forall a. Maybe a
Nothing
      }
  where
    projectArgumentId :: Expression -> Projection
projectArgumentId Expression
column =
      Aliased Expression -> Projection
ExpressionProjection
        (Aliased Expression -> Projection)
-> Aliased Expression -> Projection
forall a b. (a -> b) -> a -> b
$ Aliased
          { $sel:aliasedThing:Aliased :: Expression
aliasedThing = Expression
column,
            $sel:aliasedAlias:Aliased :: Text
aliasedAlias = FieldName -> Text
IR.getFieldNameTxt FieldName
argumentId
          }
    selectFrom :: From
selectFrom =
      Aliased OpenJson -> From
FromOpenJson
        Aliased
          { $sel:aliasedThing:Aliased :: OpenJson
aliasedThing =
              OpenJson
                { $sel:openJsonExpression:OpenJson :: Expression
openJsonExpression =
                    Value -> Expression
ValueExpression (Text -> Value
ODBC.TextValue (Text -> Value) -> Text -> Value
forall a b. (a -> b) -> a -> b
$ ByteString -> Text
lbsToTxt (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ NonEmpty Object -> ByteString
forall a. ToJSON a => a -> ByteString
J.encode NonEmpty Object
lhs),
                  $sel:openJsonWith:OpenJson :: Maybe (NonEmpty JsonFieldSpec)
openJsonWith =
                    NonEmpty JsonFieldSpec -> Maybe (NonEmpty JsonFieldSpec)
forall a. a -> Maybe a
Just
                      (NonEmpty JsonFieldSpec -> Maybe (NonEmpty JsonFieldSpec))
-> NonEmpty JsonFieldSpec -> Maybe (NonEmpty JsonFieldSpec)
forall a b. (a -> b) -> a -> b
$ FieldName -> ScalarType -> JsonFieldSpec
toJsonFieldSpec FieldName
argumentId ScalarType
IntegerType
                      JsonFieldSpec -> [JsonFieldSpec] -> NonEmpty JsonFieldSpec
forall a. a -> [a] -> NonEmpty a
NE.:| ((FieldName, (ColumnName, ScalarType)) -> JsonFieldSpec)
-> [(FieldName, (ColumnName, ScalarType))] -> [JsonFieldSpec]
forall a b. (a -> b) -> [a] -> [b]
map ((FieldName -> ScalarType -> JsonFieldSpec)
-> (FieldName, ScalarType) -> JsonFieldSpec
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry FieldName -> ScalarType -> JsonFieldSpec
toJsonFieldSpec ((FieldName, ScalarType) -> JsonFieldSpec)
-> ((FieldName, (ColumnName, ScalarType))
    -> (FieldName, ScalarType))
-> (FieldName, (ColumnName, ScalarType))
-> JsonFieldSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((ColumnName, ScalarType) -> ScalarType)
-> (FieldName, (ColumnName, ScalarType)) -> (FieldName, ScalarType)
forall b c d. (b -> c) -> (d, b) -> (d, c)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second (ColumnName, ScalarType) -> ScalarType
forall a b. (a, b) -> b
snd) (HashMap FieldName (ColumnName, ScalarType)
-> [(FieldName, (ColumnName, ScalarType))]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList HashMap FieldName (ColumnName, ScalarType)
lhsSchema)
                },
            $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
"lhs"
          }

    joinColumns :: HashMap ColumnName (ColumnName, ScalarType)
joinColumns = (FieldName -> ColumnName)
-> HashMap FieldName (ColumnName, ScalarType)
-> HashMap ColumnName (ColumnName, ScalarType)
forall k2 k1 v.
(Eq k2, Hashable k2) =>
(k1 -> k2) -> HashMap k1 v -> HashMap k2 v
mapKeys FieldName -> ColumnName
coerceToColumn HashMap FieldName (ColumnName, ScalarType)
lhsSchema

    coerceToColumn :: FieldName -> ColumnName
coerceToColumn = Text -> ColumnName
ColumnName (Text -> ColumnName)
-> (FieldName -> Text) -> FieldName -> ColumnName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FieldName -> Text
IR.getFieldNameTxt

    toJsonFieldSpec :: FieldName -> ScalarType -> JsonFieldSpec
toJsonFieldSpec (IR.FieldName Text
lhsFieldName) ScalarType
scalarType =
      ScalarType -> DataLength -> Text -> Maybe JsonPath -> JsonFieldSpec
ScalarField ScalarType
scalarType DataLength
DataLengthMax Text
lhsFieldName (JsonPath -> Maybe JsonPath
forall a. a -> Maybe a
Just (JsonPath -> Maybe JsonPath) -> JsonPath -> Maybe JsonPath
forall a b. (a -> b) -> a -> b
$ JsonPath -> Text -> JsonPath
FieldPath JsonPath
RootPath Text
lhsFieldName)

-- | Build the 'FieldSource' for the relation field, depending on whether it's
-- an object, array, or aggregate relationship.
fromRemoteRelationFieldsG ::
  Map (Either NativeQueryName TableName) EntityAlias ->
  HashMap.HashMap ColumnName ColumnName ->
  (IR.FieldName, IR.SourceRelationshipSelection 'MSSQL Void (Const Expression)) ->
  ReaderT EntityAlias FromIr FieldSource
fromRemoteRelationFieldsG :: Map (Either NativeQueryName TableName) EntityAlias
-> HashMap ColumnName ColumnName
-> (FieldName,
    SourceRelationshipSelection 'MSSQL Void (Const Expression))
-> ReaderT EntityAlias FromIr FieldSource
fromRemoteRelationFieldsG Map (Either NativeQueryName TableName) EntityAlias
existingJoins HashMap ColumnName ColumnName
joinColumns (IR.FieldName Text
name, SourceRelationshipSelection 'MSSQL Void (Const Expression)
field) =
  case SourceRelationshipSelection 'MSSQL Void (Const Expression)
field of
    IR.SourceRelationshipObject AnnObjectSelectG 'MSSQL Void (Const Expression 'MSSQL)
selectionSet ->
      (Join -> FieldSource)
-> ReaderT EntityAlias FromIr Join
-> ReaderT EntityAlias FromIr FieldSource
forall a b.
(a -> b)
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
        ( \Join
aliasedThing ->
            JsonCardinality -> Aliased Join -> FieldSource
JoinFieldSource JsonCardinality
JsonSingleton (Aliased {Join
$sel:aliasedThing:Aliased :: Join
aliasedThing :: Join
aliasedThing, $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
name})
        )
        ( Map (Either NativeQueryName TableName) EntityAlias
-> ObjectRelationSelectG 'MSSQL Void Expression
-> ReaderT EntityAlias FromIr Join
fromObjectRelationSelectG
            Map (Either NativeQueryName TableName) EntityAlias
existingJoins
            ( AnnObjectSelectG 'MSSQL Void Expression
-> ObjectRelationSelectG 'MSSQL Void Expression
forall s. s -> AnnRelationSelectG 'MSSQL s
withJoinColumns
                (AnnObjectSelectG 'MSSQL Void Expression
 -> ObjectRelationSelectG 'MSSQL Void Expression)
-> AnnObjectSelectG 'MSSQL Void Expression
-> ObjectRelationSelectG 'MSSQL Void Expression
forall a b. (a -> b) -> a -> b
$ Identity (AnnObjectSelectG 'MSSQL Void Expression)
-> AnnObjectSelectG 'MSSQL Void Expression
forall a. Identity a -> a
runIdentity
                (Identity (AnnObjectSelectG 'MSSQL Void Expression)
 -> AnnObjectSelectG 'MSSQL Void Expression)
-> Identity (AnnObjectSelectG 'MSSQL Void Expression)
-> AnnObjectSelectG 'MSSQL Void Expression
forall a b. (a -> b) -> a -> b
$ (Const Expression 'MSSQL -> Identity Expression)
-> AnnObjectSelectG 'MSSQL Void (Const Expression 'MSSQL)
-> Identity (AnnObjectSelectG 'MSSQL Void Expression)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b)
-> AnnObjectSelectG 'MSSQL Void a
-> f (AnnObjectSelectG 'MSSQL Void b)
traverse (Expression -> Identity Expression
forall a. a -> Identity a
Identity (Expression -> Identity Expression)
-> (Const Expression 'MSSQL -> Expression)
-> Const Expression 'MSSQL
-> Identity Expression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Const Expression 'MSSQL -> Expression
forall {k} a (b :: k). Const a b -> a
getConst) AnnObjectSelectG 'MSSQL Void (Const Expression 'MSSQL)
selectionSet
            )
        )
    IR.SourceRelationshipArray AnnSimpleSelectG 'MSSQL Void (Const Expression 'MSSQL)
selectionSet ->
      (Join -> FieldSource)
-> ReaderT EntityAlias FromIr Join
-> ReaderT EntityAlias FromIr FieldSource
forall a b.
(a -> b)
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
        ( \Join
aliasedThing ->
            JsonCardinality -> Aliased Join -> FieldSource
JoinFieldSource JsonCardinality
JsonArray (Aliased {Join
$sel:aliasedThing:Aliased :: Join
aliasedThing :: Join
aliasedThing, $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
name})
        )
        ( ArraySelectG 'MSSQL Void Expression
-> ReaderT EntityAlias FromIr Join
fromArraySelectG
            ( ArrayRelationSelectG 'MSSQL Void Expression
-> ArraySelectG 'MSSQL Void Expression
forall (b :: BackendType) r v.
ArrayRelationSelectG b r v -> ArraySelectG b r v
IR.ASSimple
                (ArrayRelationSelectG 'MSSQL Void Expression
 -> ArraySelectG 'MSSQL Void Expression)
-> ArrayRelationSelectG 'MSSQL Void Expression
-> ArraySelectG 'MSSQL Void Expression
forall a b. (a -> b) -> a -> b
$ AnnSimpleSelectG 'MSSQL Void Expression
-> ArrayRelationSelectG 'MSSQL Void Expression
forall s. s -> AnnRelationSelectG 'MSSQL s
withJoinColumns
                (AnnSimpleSelectG 'MSSQL Void Expression
 -> ArrayRelationSelectG 'MSSQL Void Expression)
-> AnnSimpleSelectG 'MSSQL Void Expression
-> ArrayRelationSelectG 'MSSQL Void Expression
forall a b. (a -> b) -> a -> b
$ Identity (AnnSimpleSelectG 'MSSQL Void Expression)
-> AnnSimpleSelectG 'MSSQL Void Expression
forall a. Identity a -> a
runIdentity
                (Identity (AnnSimpleSelectG 'MSSQL Void Expression)
 -> AnnSimpleSelectG 'MSSQL Void Expression)
-> Identity (AnnSimpleSelectG 'MSSQL Void Expression)
-> AnnSimpleSelectG 'MSSQL Void Expression
forall a b. (a -> b) -> a -> b
$ (Const Expression 'MSSQL -> Identity Expression)
-> AnnSimpleSelectG 'MSSQL Void (Const Expression 'MSSQL)
-> Identity (AnnSimpleSelectG 'MSSQL Void Expression)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b)
-> AnnSelectG 'MSSQL (AnnFieldG 'MSSQL Void) a
-> f (AnnSelectG 'MSSQL (AnnFieldG 'MSSQL Void) b)
traverse (Expression -> Identity Expression
forall a. a -> Identity a
Identity (Expression -> Identity Expression)
-> (Const Expression 'MSSQL -> Expression)
-> Const Expression 'MSSQL
-> Identity Expression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Const Expression 'MSSQL -> Expression
forall {k} a (b :: k). Const a b -> a
getConst) AnnSimpleSelectG 'MSSQL Void (Const Expression 'MSSQL)
selectionSet
            )
        )
    IR.SourceRelationshipArrayAggregate AnnAggregateSelectG 'MSSQL Void (Const Expression 'MSSQL)
selectionSet ->
      (Join -> FieldSource)
-> ReaderT EntityAlias FromIr Join
-> ReaderT EntityAlias FromIr FieldSource
forall a b.
(a -> b)
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
        ( \Join
aliasedThing ->
            JsonCardinality -> Aliased Join -> FieldSource
JoinFieldSource JsonCardinality
JsonArray (Aliased {Join
$sel:aliasedThing:Aliased :: Join
aliasedThing :: Join
aliasedThing, $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
name})
        )
        ( ArraySelectG 'MSSQL Void Expression
-> ReaderT EntityAlias FromIr Join
fromArraySelectG
            ( ArrayAggregateSelectG 'MSSQL Void Expression
-> ArraySelectG 'MSSQL Void Expression
forall (b :: BackendType) r v.
ArrayAggregateSelectG b r v -> ArraySelectG b r v
IR.ASAggregate
                (ArrayAggregateSelectG 'MSSQL Void Expression
 -> ArraySelectG 'MSSQL Void Expression)
-> ArrayAggregateSelectG 'MSSQL Void Expression
-> ArraySelectG 'MSSQL Void Expression
forall a b. (a -> b) -> a -> b
$ AnnAggregateSelectG 'MSSQL Void Expression
-> ArrayAggregateSelectG 'MSSQL Void Expression
forall s. s -> AnnRelationSelectG 'MSSQL s
withJoinColumns
                (AnnAggregateSelectG 'MSSQL Void Expression
 -> ArrayAggregateSelectG 'MSSQL Void Expression)
-> AnnAggregateSelectG 'MSSQL Void Expression
-> ArrayAggregateSelectG 'MSSQL Void Expression
forall a b. (a -> b) -> a -> b
$ Identity (AnnAggregateSelectG 'MSSQL Void Expression)
-> AnnAggregateSelectG 'MSSQL Void Expression
forall a. Identity a -> a
runIdentity
                (Identity (AnnAggregateSelectG 'MSSQL Void Expression)
 -> AnnAggregateSelectG 'MSSQL Void Expression)
-> Identity (AnnAggregateSelectG 'MSSQL Void Expression)
-> AnnAggregateSelectG 'MSSQL Void Expression
forall a b. (a -> b) -> a -> b
$ (Const Expression 'MSSQL -> Identity Expression)
-> AnnAggregateSelectG 'MSSQL Void (Const Expression 'MSSQL)
-> Identity (AnnAggregateSelectG 'MSSQL Void Expression)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b)
-> AnnSelectG 'MSSQL (TableAggregateFieldG 'MSSQL Void) a
-> f (AnnSelectG 'MSSQL (TableAggregateFieldG 'MSSQL Void) b)
traverse (Expression -> Identity Expression
forall a. a -> Identity a
Identity (Expression -> Identity Expression)
-> (Const Expression 'MSSQL -> Expression)
-> Const Expression 'MSSQL
-> Identity Expression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Const Expression 'MSSQL -> Expression
forall {k} a (b :: k). Const a b -> a
getConst) AnnAggregateSelectG 'MSSQL Void (Const Expression 'MSSQL)
selectionSet
            )
        )
  where
    withJoinColumns ::
      s -> IR.AnnRelationSelectG 'MSSQL s
    withJoinColumns :: forall s. s -> AnnRelationSelectG 'MSSQL s
withJoinColumns s
annotatedRelationship =
      RelName
-> HashMap (Column 'MSSQL) (Column 'MSSQL)
-> Nullable
-> s
-> AnnRelationSelectG 'MSSQL s
forall (b :: BackendType) a.
RelName
-> HashMap (Column b) (Column b)
-> Nullable
-> a
-> AnnRelationSelectG b a
IR.AnnRelationSelectG
        (NonEmptyText -> RelName
IR.RelName (NonEmptyText -> RelName) -> NonEmptyText -> RelName
forall a b. (a -> b) -> a -> b
$ Text -> NonEmptyText
mkNonEmptyTextUnsafe Text
name)
        HashMap (Column 'MSSQL) (Column 'MSSQL)
HashMap ColumnName ColumnName
joinColumns
        Nullable
IR.Nullable
        s
annotatedRelationship

-- | Top/root-level 'Select'. All descendent/sub-translations are collected to produce a root TSQL.Select.
fromSelectRows :: IR.AnnSelectG 'MSSQL (IR.AnnFieldG 'MSSQL Void) Expression -> FromIr TSQL.Select
fromSelectRows :: AnnSimpleSelectG 'MSSQL Void Expression -> FromIr Select
fromSelectRows AnnSimpleSelectG 'MSSQL Void Expression
annSelectG = do
  From
selectFrom <-
    case SelectFromG 'MSSQL Expression
from of
      IR.FromTable TableName 'MSSQL
qualifiedObject -> TableName -> FromIr From
fromQualifiedTable TableName 'MSSQL
TableName
qualifiedObject
      IR.FromIdentifier FIIdentifier
identifier -> From -> FromIr From
forall a. a -> FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (From -> FromIr From) -> From -> FromIr From
forall a b. (a -> b) -> a -> b
$ Text -> From
FromIdentifier (Text -> From) -> Text -> From
forall a b. (a -> b) -> a -> b
$ FIIdentifier -> Text
IR.unFIIdentifier FIIdentifier
identifier
      IR.FromFunction {} -> NonEmpty Error -> FromIr From
forall a. NonEmpty Error -> FromIr a
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
refute (NonEmpty Error -> FromIr From) -> NonEmpty Error -> FromIr From
forall a b. (a -> b) -> a -> b
$ Error -> NonEmpty Error
forall a. a -> NonEmpty a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Error
FunctionNotSupported
      IR.FromNativeQuery NativeQuery 'MSSQL Expression
nativeQuery -> NativeQuery 'MSSQL Expression -> FromIr From
fromNativeQuery NativeQuery 'MSSQL Expression
nativeQuery
      IR.FromStoredProcedure StoredProcedure 'MSSQL Expression
storedProcedure -> StoredProcedure 'MSSQL Expression -> FromIr From
fromStoredProcedure StoredProcedure 'MSSQL Expression
storedProcedure
  Args
    { Maybe (NonEmpty OrderBy)
argsOrderBy :: Maybe (NonEmpty OrderBy)
argsOrderBy :: Args -> Maybe (NonEmpty OrderBy)
argsOrderBy,
      Where
argsWhere :: Where
argsWhere :: Args -> Where
argsWhere,
      [Join]
argsJoins :: [Join]
argsJoins :: Args -> [Join]
argsJoins,
      Top
argsTop :: Top
argsTop :: Args -> Top
argsTop,
      argsDistinct :: Args -> Proxy (Maybe (NonEmpty FieldName))
argsDistinct = Proxy (Maybe (NonEmpty FieldName))
Proxy,
      Maybe Expression
argsOffset :: Maybe Expression
argsOffset :: Args -> Maybe Expression
argsOffset,
      Map (Either NativeQueryName TableName) EntityAlias
argsExistingJoins :: Map (Either NativeQueryName TableName) EntityAlias
argsExistingJoins :: Args -> Map (Either NativeQueryName TableName) EntityAlias
argsExistingJoins
    } <-
    ReaderT EntityAlias FromIr Args -> EntityAlias -> FromIr Args
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (SelectArgsG 'MSSQL Expression -> ReaderT EntityAlias FromIr Args
fromSelectArgsG SelectArgsG 'MSSQL Expression
args) (From -> EntityAlias
fromAlias From
selectFrom)
  [FieldSource]
fieldSources <-
    ReaderT EntityAlias FromIr [FieldSource]
-> EntityAlias -> FromIr [FieldSource]
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT
      (((FieldName, AnnFieldG 'MSSQL Void Expression)
 -> ReaderT EntityAlias FromIr FieldSource)
-> [(FieldName, AnnFieldG 'MSSQL Void Expression)]
-> ReaderT EntityAlias FromIr [FieldSource]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse (Map (Either NativeQueryName TableName) EntityAlias
-> (FieldName, AnnFieldG 'MSSQL Void Expression)
-> ReaderT EntityAlias FromIr FieldSource
fromAnnFieldsG Map (Either NativeQueryName TableName) EntityAlias
argsExistingJoins) [(FieldName, AnnFieldG 'MSSQL Void Expression)]
fields)
      (From -> EntityAlias
fromAlias From
selectFrom)
  Expression
filterExpression <-
    ReaderT EntityAlias FromIr Expression
-> EntityAlias -> FromIr Expression
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGBoolExp GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
permFilter) (From -> EntityAlias
fromAlias From
selectFrom)
  let selectProjections :: [Projection]
selectProjections = (FieldSource -> Projection) -> [FieldSource] -> [Projection]
forall a b. (a -> b) -> [a] -> [b]
map FieldSource -> Projection
fieldSourceProjections [FieldSource]
fieldSources

  Select -> FromIr Select
forall a. a -> FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    (Select -> FromIr Select) -> Select -> FromIr Select
forall a b. (a -> b) -> a -> b
$ Select
emptySelect
      { $sel:selectOrderBy:Select :: Maybe (NonEmpty OrderBy)
selectOrderBy = Maybe (NonEmpty OrderBy)
argsOrderBy,
        $sel:selectTop:Select :: Top
selectTop = Top
permissionBasedTop Top -> Top -> Top
forall a. Semigroup a => a -> a -> a
<> Top
argsTop,
        [Projection]
$sel:selectProjections:Select :: [Projection]
selectProjections :: [Projection]
selectProjections,
        $sel:selectFrom:Select :: Maybe From
selectFrom = From -> Maybe From
forall a. a -> Maybe a
Just From
selectFrom,
        $sel:selectJoins:Select :: [Join]
selectJoins = [Join]
argsJoins [Join] -> [Join] -> [Join]
forall a. Semigroup a => a -> a -> a
<> (FieldSource -> Maybe Join) -> [FieldSource] -> [Join]
forall a b. (a -> Maybe b) -> [a] -> [b]
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe FieldSource -> Maybe Join
fieldSourceJoin [FieldSource]
fieldSources,
        $sel:selectWhere:Select :: Where
selectWhere = Where
argsWhere Where -> Where -> Where
forall a. Semigroup a => a -> a -> a
<> [Expression] -> Where
Where [Expression
filterExpression],
        $sel:selectFor:Select :: For
selectFor =
          ForJson -> For
JsonFor ForJson {$sel:jsonCardinality:ForJson :: JsonCardinality
jsonCardinality = JsonCardinality
JsonArray, $sel:jsonRoot:ForJson :: Root
jsonRoot = Root
NoRoot},
        $sel:selectOffset:Select :: Maybe Expression
selectOffset = Maybe Expression
argsOffset
      }
  where
    IR.AnnSelectG
      { $sel:_asnFields:AnnSelectG :: forall (b :: BackendType) (f :: * -> *) v.
AnnSelectG b f v -> Fields (f v)
_asnFields = [(FieldName, AnnFieldG 'MSSQL Void Expression)]
fields,
        $sel:_asnFrom:AnnSelectG :: forall (b :: BackendType) (f :: * -> *) v.
AnnSelectG b f v -> SelectFromG b v
_asnFrom = SelectFromG 'MSSQL Expression
from,
        $sel:_asnPerm:AnnSelectG :: forall (b :: BackendType) (f :: * -> *) v.
AnnSelectG b f v -> TablePermG b v
_asnPerm = TablePermG 'MSSQL Expression
perm,
        $sel:_asnArgs:AnnSelectG :: forall (b :: BackendType) (f :: * -> *) v.
AnnSelectG b f v -> SelectArgsG b v
_asnArgs = SelectArgsG 'MSSQL Expression
args,
        $sel:_asnNamingConvention:AnnSelectG :: forall (b :: BackendType) (f :: * -> *) v.
AnnSelectG b f v -> Maybe NamingCase
_asnNamingConvention = Maybe NamingCase
_tCase
      } = AnnSimpleSelectG 'MSSQL Void Expression
annSelectG
    IR.TablePerm {$sel:_tpLimit:TablePerm :: forall (b :: BackendType) v. TablePermG b v -> Maybe Int
_tpLimit = Maybe Int
mPermLimit, $sel:_tpFilter:TablePerm :: forall (b :: BackendType) v. TablePermG b v -> AnnBoolExp b v
_tpFilter = GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
permFilter} = TablePermG 'MSSQL Expression
perm
    permissionBasedTop :: Top
permissionBasedTop =
      Top -> (Int -> Top) -> Maybe Int -> Top
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Top
NoTop Int -> Top
Top Maybe Int
mPermLimit

mkNodesSelect :: Args -> Where -> Expression -> Top -> From -> [(Int, (IR.FieldName, [FieldSource]))] -> [(Int, Projection)]
mkNodesSelect :: Args
-> Where
-> Expression
-> Top
-> From
-> [(Int, (FieldName, [FieldSource]))]
-> [(Int, Projection)]
mkNodesSelect Args {[Join]
Maybe (NonEmpty OrderBy)
Maybe Expression
Map (Either NativeQueryName TableName) EntityAlias
Proxy (Maybe (NonEmpty FieldName))
Top
Where
argsOrderBy :: Args -> Maybe (NonEmpty OrderBy)
argsWhere :: Args -> Where
argsJoins :: Args -> [Join]
argsTop :: Args -> Top
argsDistinct :: Args -> Proxy (Maybe (NonEmpty FieldName))
argsOffset :: Args -> Maybe Expression
argsExistingJoins :: Args -> Map (Either NativeQueryName TableName) EntityAlias
argsWhere :: Where
argsOrderBy :: Maybe (NonEmpty OrderBy)
argsJoins :: [Join]
argsTop :: Top
argsOffset :: Maybe Expression
argsDistinct :: Proxy (Maybe (NonEmpty FieldName))
argsExistingJoins :: Map (Either NativeQueryName TableName) EntityAlias
..} Where
foreignKeyConditions Expression
filterExpression Top
permissionBasedTop From
selectFrom [(Int, (FieldName, [FieldSource]))]
nodes =
  [ ( Int
index,
      Aliased Expression -> Projection
ExpressionProjection
        (Aliased Expression -> Projection)
-> Aliased Expression -> Projection
forall a b. (a -> b) -> a -> b
$ Aliased
          { $sel:aliasedThing:Aliased :: Expression
aliasedThing =
              Select -> Expression
SelectExpression
                (Select -> Expression) -> Select -> Expression
forall a b. (a -> b) -> a -> b
$ Select
emptySelect
                  { $sel:selectProjections:Select :: [Projection]
selectProjections = (FieldSource -> Projection) -> [FieldSource] -> [Projection]
forall a b. (a -> b) -> [a] -> [b]
map FieldSource -> Projection
fieldSourceProjections [FieldSource]
fieldSources,
                    $sel:selectTop:Select :: Top
selectTop = Top
permissionBasedTop Top -> Top -> Top
forall a. Semigroup a => a -> a -> a
<> Top
argsTop,
                    $sel:selectFrom:Select :: Maybe From
selectFrom = From -> Maybe From
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure From
selectFrom,
                    $sel:selectJoins:Select :: [Join]
selectJoins = [Join]
argsJoins [Join] -> [Join] -> [Join]
forall a. Semigroup a => a -> a -> a
<> (FieldSource -> Maybe Join) -> [FieldSource] -> [Join]
forall a b. (a -> Maybe b) -> [a] -> [b]
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe FieldSource -> Maybe Join
fieldSourceJoin [FieldSource]
fieldSources,
                    $sel:selectWhere:Select :: Where
selectWhere = Where
argsWhere Where -> Where -> Where
forall a. Semigroup a => a -> a -> a
<> [Expression] -> Where
Where [Expression
filterExpression] Where -> Where -> Where
forall a. Semigroup a => a -> a -> a
<> Where
foreignKeyConditions,
                    $sel:selectFor:Select :: For
selectFor =
                      ForJson -> For
JsonFor ForJson {$sel:jsonCardinality:ForJson :: JsonCardinality
jsonCardinality = JsonCardinality
JsonArray, $sel:jsonRoot:ForJson :: Root
jsonRoot = Root
NoRoot},
                    $sel:selectOrderBy:Select :: Maybe (NonEmpty OrderBy)
selectOrderBy = Maybe (NonEmpty OrderBy)
argsOrderBy,
                    $sel:selectOffset:Select :: Maybe Expression
selectOffset = Maybe Expression
argsOffset
                  },
            $sel:aliasedAlias:Aliased :: Text
aliasedAlias = FieldName -> Text
IR.getFieldNameTxt FieldName
fieldName
          }
    )
    | (Int
index, (FieldName
fieldName, [FieldSource]
fieldSources)) <- [(Int, (FieldName, [FieldSource]))]
nodes
  ]

--
-- The idea here is that LIMIT/OFFSET and aggregates don't mix
-- well. Therefore we have a nested query:
--
-- select sum(*), .. FROM (select * from x offset o limit l) p
--
-- That's why @projections@ appears on the outer, and is a
-- @StarProjection@ for the inner. But the joins, conditions, top,
-- offset are on the inner.
--
mkAggregateSelect :: Args -> Where -> Expression -> From -> [(Int, (IR.FieldName, [Projection]))] -> [(Int, Projection)]
mkAggregateSelect :: Args
-> Where
-> Expression
-> From
-> [(Int, (FieldName, [Projection]))]
-> [(Int, Projection)]
mkAggregateSelect Args {[Join]
Maybe (NonEmpty OrderBy)
Maybe Expression
Map (Either NativeQueryName TableName) EntityAlias
Proxy (Maybe (NonEmpty FieldName))
Top
Where
argsOrderBy :: Args -> Maybe (NonEmpty OrderBy)
argsWhere :: Args -> Where
argsJoins :: Args -> [Join]
argsTop :: Args -> Top
argsDistinct :: Args -> Proxy (Maybe (NonEmpty FieldName))
argsOffset :: Args -> Maybe Expression
argsExistingJoins :: Args -> Map (Either NativeQueryName TableName) EntityAlias
argsWhere :: Where
argsOrderBy :: Maybe (NonEmpty OrderBy)
argsJoins :: [Join]
argsTop :: Top
argsOffset :: Maybe Expression
argsDistinct :: Proxy (Maybe (NonEmpty FieldName))
argsExistingJoins :: Map (Either NativeQueryName TableName) EntityAlias
..} Where
foreignKeyConditions Expression
filterExpression From
selectFrom [(Int, (FieldName, [Projection]))]
aggregates =
  [ ( Int
index,
      Aliased Expression -> Projection
ExpressionProjection
        (Aliased Expression -> Projection)
-> Aliased Expression -> Projection
forall a b. (a -> b) -> a -> b
$ Aliased
          { $sel:aliasedThing:Aliased :: Expression
aliasedThing =
              JsonCardinality -> Expression -> Expression
safeJsonQueryExpression JsonCardinality
JsonSingleton
                (Expression -> Expression) -> Expression -> Expression
forall a b. (a -> b) -> a -> b
$ Select -> Expression
SelectExpression
                (Select -> Expression) -> Select -> Expression
forall a b. (a -> b) -> a -> b
$ Select
emptySelect
                  { $sel:selectProjections:Select :: [Projection]
selectProjections = [Projection]
projections,
                    $sel:selectTop:Select :: Top
selectTop = Top
NoTop,
                    $sel:selectFrom:Select :: Maybe From
selectFrom =
                      From -> Maybe From
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
                        (From -> Maybe From) -> From -> Maybe From
forall a b. (a -> b) -> a -> b
$ Aliased Select -> From
FromSelect
                          Aliased
                            { $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
aggSubselectName,
                              $sel:aliasedThing:Aliased :: Select
aliasedThing =
                                Select
emptySelect
                                  { $sel:selectProjections:Select :: [Projection]
selectProjections = Projection -> [Projection]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure Projection
StarProjection,
                                    $sel:selectTop:Select :: Top
selectTop = Top
argsTop,
                                    $sel:selectFrom:Select :: Maybe From
selectFrom = From -> Maybe From
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure From
selectFrom,
                                    $sel:selectJoins:Select :: [Join]
selectJoins = [Join]
argsJoins,
                                    $sel:selectWhere:Select :: Where
selectWhere = Where
argsWhere Where -> Where -> Where
forall a. Semigroup a => a -> a -> a
<> [Expression] -> Where
Where [Expression
filterExpression] Where -> Where -> Where
forall a. Semigroup a => a -> a -> a
<> Where
foreignKeyConditions,
                                    $sel:selectFor:Select :: For
selectFor = For
NoFor,
                                    $sel:selectOrderBy:Select :: Maybe (NonEmpty OrderBy)
selectOrderBy = Maybe (NonEmpty OrderBy)
forall a. Monoid a => a
mempty,
                                    $sel:selectOffset:Select :: Maybe Expression
selectOffset = Maybe Expression
argsOffset
                                  }
                            },
                    $sel:selectJoins:Select :: [Join]
selectJoins = [Join]
forall a. Monoid a => a
mempty,
                    $sel:selectWhere:Select :: Where
selectWhere = Where
forall a. Monoid a => a
mempty,
                    $sel:selectFor:Select :: For
selectFor =
                      ForJson -> For
JsonFor
                        ForJson
                          { $sel:jsonCardinality:ForJson :: JsonCardinality
jsonCardinality = JsonCardinality
JsonSingleton,
                            $sel:jsonRoot:ForJson :: Root
jsonRoot = Root
NoRoot
                          },
                    $sel:selectOrderBy:Select :: Maybe (NonEmpty OrderBy)
selectOrderBy = Maybe (NonEmpty OrderBy)
forall a. Monoid a => a
mempty,
                    $sel:selectOffset:Select :: Maybe Expression
selectOffset = Maybe Expression
forall a. Maybe a
Nothing
                  },
            $sel:aliasedAlias:Aliased :: Text
aliasedAlias = FieldName -> Text
IR.getFieldNameTxt FieldName
fieldName
          }
    )
    | (Int
index, (FieldName
fieldName, [Projection]
projections)) <- [(Int, (FieldName, [Projection]))]
aggregates
  ]

fromNativeQuery :: IR.NativeQuery 'MSSQL Expression -> FromIr TSQL.From
fromNativeQuery :: NativeQuery 'MSSQL Expression -> FromIr From
fromNativeQuery NativeQuery 'MSSQL Expression
nativeQuery = do
  let nativeQueryName :: NativeQueryName
nativeQueryName = NativeQuery 'MSSQL Expression -> NativeQueryName
forall (b :: BackendType) field.
NativeQuery b field -> NativeQueryName
IR.nqRootFieldName NativeQuery 'MSSQL Expression
nativeQuery
      nativeQuerySql :: InterpolatedQuery Expression
nativeQuerySql = NativeQuery 'MSSQL Expression -> InterpolatedQuery Expression
forall (b :: BackendType) field.
NativeQuery b field -> InterpolatedQuery field
IR.nqInterpolatedQuery NativeQuery 'MSSQL Expression
nativeQuery
  Text
cteName <- NativeQueryName -> InterpolatedQuery Expression -> FromIr Text
tellCTE NativeQueryName
nativeQueryName InterpolatedQuery Expression
nativeQuerySql
  From -> FromIr From
forall a. a -> FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (From -> FromIr From) -> From -> FromIr From
forall a b. (a -> b) -> a -> b
$ Text -> From
TSQL.FromIdentifier Text
cteName

fromStoredProcedure :: IR.StoredProcedure 'MSSQL Expression -> FromIr TSQL.From
fromStoredProcedure :: StoredProcedure 'MSSQL Expression -> FromIr From
fromStoredProcedure StoredProcedure 'MSSQL Expression
storedProcedure = do
  let storedProcedureName :: Text
storedProcedureName = Text
"hasura_sp_" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Name -> Text
forall a. ToTxt a => a -> Text
T.toTxt (StoredProcedure 'MSSQL Expression -> Name
forall (b :: BackendType) field. StoredProcedure b field -> Name
IR.spGraphqlName StoredProcedure 'MSSQL Expression
storedProcedure)
      declares :: [Declare]
declares =
        ((ArgumentName, (ScalarType, Expression)) -> Declare)
-> [(ArgumentName, (ScalarType, Expression))] -> [Declare]
forall a b. (a -> b) -> [a] -> [b]
map
          (\(ArgumentName
arg, (ScalarType
typ, Expression
val)) -> Text -> ScalarType -> Expression -> Declare
Declare (ArgumentName -> Text
getArgumentName ArgumentName
arg) ScalarType
typ Expression
val)
          (HashMap ArgumentName (ScalarType, Expression)
-> [(ArgumentName, (ScalarType, Expression))]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList (StoredProcedure 'MSSQL Expression
-> HashMap ArgumentName (ScalarType 'MSSQL, Expression)
forall (b :: BackendType) field.
StoredProcedure b field
-> HashMap ArgumentName (ScalarType b, field)
IR.spArgs StoredProcedure 'MSSQL Expression
storedProcedure))
      sql :: InterpolatedQuery Expression
sql =
        [InterpolatedItem Expression] -> InterpolatedQuery Expression
forall variable.
[InterpolatedItem variable] -> InterpolatedQuery variable
InterpolatedQuery
          ([InterpolatedItem Expression] -> InterpolatedQuery Expression)
-> [InterpolatedItem Expression] -> InterpolatedQuery Expression
forall a b. (a -> b) -> a -> b
$ Text -> InterpolatedItem Expression
forall variable. Text -> InterpolatedItem variable
IIText (Text
"EXECUTE " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> FunctionName -> Text
forall a. ToTxt a => a -> Text
T.toTxt (StoredProcedure 'MSSQL Expression -> FunctionName 'MSSQL
forall (b :: BackendType) field.
StoredProcedure b field -> FunctionName b
IR.spStoredProcedure StoredProcedure 'MSSQL Expression
storedProcedure) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" ")
          InterpolatedItem Expression
-> [InterpolatedItem Expression] -> [InterpolatedItem Expression]
forall a. a -> [a] -> [a]
: [InterpolatedItem Expression]
-> [[InterpolatedItem Expression]] -> [InterpolatedItem Expression]
forall a. [a] -> [[a]] -> [a]
intercalate
            [Text -> InterpolatedItem Expression
forall variable. Text -> InterpolatedItem variable
IIText Text
", "]
            ( (ArgumentName -> [InterpolatedItem Expression])
-> [ArgumentName] -> [[InterpolatedItem Expression]]
forall a b. (a -> b) -> [a] -> [b]
map
                ( \(ArgumentName Text
name) ->
                    [ Text -> InterpolatedItem Expression
forall variable. Text -> InterpolatedItem variable
IIText Text
"@",
                      Text -> InterpolatedItem Expression
forall variable. Text -> InterpolatedItem variable
IIText (Text -> Text
forall a. ToTxt a => a -> Text
T.toTxt Text
name),
                      Text -> InterpolatedItem Expression
forall variable. Text -> InterpolatedItem variable
IIText Text
" = ",
                      Text -> InterpolatedItem Expression
forall variable. Text -> InterpolatedItem variable
IIText Text
"@",
                      Text -> InterpolatedItem Expression
forall variable. Text -> InterpolatedItem variable
IIText (Text -> Text
forall a. ToTxt a => a -> Text
T.toTxt Text
name)
                    ]
                )
                (HashMap ArgumentName (ScalarType, Expression) -> [ArgumentName]
forall k v. HashMap k v -> [k]
HashMap.keys (StoredProcedure 'MSSQL Expression
-> HashMap ArgumentName (ScalarType 'MSSQL, Expression)
forall (b :: BackendType) field.
StoredProcedure b field
-> HashMap ArgumentName (ScalarType b, field)
IR.spArgs StoredProcedure 'MSSQL Expression
storedProcedure))
            )
      storedProcedureReturnType :: LogicalModel 'MSSQL
storedProcedureReturnType = StoredProcedure 'MSSQL Expression -> LogicalModel 'MSSQL
forall (b :: BackendType) field.
StoredProcedure b field -> LogicalModel b
IR.spLogicalModel StoredProcedure 'MSSQL Expression
storedProcedure
      rawTempTableName :: Text
rawTempTableName = Text -> Text
forall a. ToTxt a => a -> Text
T.toTxt Text
storedProcedureName
      aliasedTempTableName :: Aliased TempTableName
aliasedTempTableName = TempTableName -> Text -> Aliased TempTableName
forall a. a -> Text -> Aliased a
Aliased (Text -> TempTableName
TempTableName Text
rawTempTableName) Text
rawTempTableName

      columns :: [UnifiedColumn]
columns =
        ( \(ColumnName
name, NullableScalarType 'MSSQL
ty) ->
            UnifiedColumn
              { $sel:name:UnifiedColumn :: ColumnName
name = ColumnName
name,
                $sel:type':UnifiedColumn :: ScalarType
type' = NullableScalarType 'MSSQL -> ScalarType 'MSSQL
forall (b :: BackendType). NullableScalarType b -> ScalarType b
nstType NullableScalarType 'MSSQL
ty
              }
        )
          ((ColumnName, NullableScalarType 'MSSQL) -> UnifiedColumn)
-> [(ColumnName, NullableScalarType 'MSSQL)] -> [UnifiedColumn]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> InsOrdHashMap ColumnName (NullableScalarType 'MSSQL)
-> [(ColumnName, NullableScalarType 'MSSQL)]
forall k v. InsOrdHashMap k v -> [(k, v)]
InsOrdHashMap.toList (InsOrdHashMap ColumnName (LogicalModelField 'MSSQL)
-> InsOrdHashMap ColumnName (NullableScalarType 'MSSQL)
forall k (b :: BackendType).
InsOrdHashMap k (LogicalModelField b)
-> InsOrdHashMap k (NullableScalarType b)
columnsFromFields (InsOrdHashMap ColumnName (LogicalModelField 'MSSQL)
 -> InsOrdHashMap ColumnName (NullableScalarType 'MSSQL))
-> InsOrdHashMap ColumnName (LogicalModelField 'MSSQL)
-> InsOrdHashMap ColumnName (NullableScalarType 'MSSQL)
forall a b. (a -> b) -> a -> b
$ LogicalModel 'MSSQL
-> InsOrdHashMap (Column 'MSSQL) (LogicalModelField 'MSSQL)
forall (b :: BackendType).
LogicalModel b -> InsOrdHashMap (Column b) (LogicalModelField b)
lmFields LogicalModel 'MSSQL
storedProcedureReturnType)

  -- \| add create temp table to "the environment"
  TempTableDDL -> FromIr ()
tellBefore (TempTableName -> [UnifiedColumn] -> TempTableDDL
CreateTemp (Text -> TempTableName
TempTableName Text
rawTempTableName) [UnifiedColumn]
columns)

  -- \| add insert into temp table
  TempTableDDL -> FromIr ()
tellBefore ([Declare]
-> TempTableName -> InterpolatedQuery Expression -> TempTableDDL
InsertTemp [Declare]
declares (Text -> TempTableName
TempTableName Text
rawTempTableName) InterpolatedQuery Expression
sql)

  -- \| when we're done, drop the temp table
  TempTableDDL -> FromIr ()
tellAfter (TempTableName -> TempTableDDL
DropTemp (Text -> TempTableName
TempTableName Text
rawTempTableName))

  From -> FromIr From
forall a. a -> FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (From -> FromIr From) -> From -> FromIr From
forall a b. (a -> b) -> a -> b
$ Aliased TempTableName -> From
TSQL.FromTempTable Aliased TempTableName
aliasedTempTableName

fromSelectAggregate ::
  Maybe (EntityAlias, HashMap ColumnName ColumnName) ->
  IR.AnnSelectG 'MSSQL (IR.TableAggregateFieldG 'MSSQL Void) Expression ->
  FromIr TSQL.Select
fromSelectAggregate :: Maybe (EntityAlias, HashMap ColumnName ColumnName)
-> AnnAggregateSelectG 'MSSQL Void Expression -> FromIr Select
fromSelectAggregate
  Maybe (EntityAlias, HashMap ColumnName ColumnName)
mparentRelationship
  IR.AnnSelectG
    { $sel:_asnFields:AnnSelectG :: forall (b :: BackendType) (f :: * -> *) v.
AnnSelectG b f v -> Fields (f v)
_asnFields = ([Int]
-> Fields (TableAggregateFieldG 'MSSQL Void Expression)
-> [(Int,
     (FieldName, TableAggregateFieldG 'MSSQL Void Expression))]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0 ..] -> [(Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))]
fields),
      $sel:_asnFrom:AnnSelectG :: forall (b :: BackendType) (f :: * -> *) v.
AnnSelectG b f v -> SelectFromG b v
_asnFrom = SelectFromG 'MSSQL Expression
from,
      $sel:_asnPerm:AnnSelectG :: forall (b :: BackendType) (f :: * -> *) v.
AnnSelectG b f v -> TablePermG b v
_asnPerm = IR.TablePerm {$sel:_tpLimit:TablePerm :: forall (b :: BackendType) v. TablePermG b v -> Maybe Int
_tpLimit = (Top -> (Int -> Top) -> Maybe Int -> Top
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Top
NoTop Int -> Top
Top -> Top
permissionBasedTop), $sel:_tpFilter:TablePerm :: forall (b :: BackendType) v. TablePermG b v -> AnnBoolExp b v
_tpFilter = GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
permFilter},
      $sel:_asnArgs:AnnSelectG :: forall (b :: BackendType) (f :: * -> *) v.
AnnSelectG b f v -> SelectArgsG b v
_asnArgs = SelectArgsG 'MSSQL Expression
args,
      $sel:_asnNamingConvention:AnnSelectG :: forall (b :: BackendType) (f :: * -> *) v.
AnnSelectG b f v -> Maybe NamingCase
_asnNamingConvention = Maybe NamingCase
_tCase
    } =
    do
      From
selectFrom <- case SelectFromG 'MSSQL Expression
from of
        IR.FromTable TableName 'MSSQL
qualifiedObject -> TableName -> FromIr From
fromQualifiedTable TableName 'MSSQL
TableName
qualifiedObject
        IR.FromIdentifier FIIdentifier
identifier -> From -> FromIr From
forall a. a -> FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (From -> FromIr From) -> From -> FromIr From
forall a b. (a -> b) -> a -> b
$ Text -> From
FromIdentifier (Text -> From) -> Text -> From
forall a b. (a -> b) -> a -> b
$ FIIdentifier -> Text
IR.unFIIdentifier FIIdentifier
identifier
        IR.FromFunction {} -> NonEmpty Error -> FromIr From
forall a. NonEmpty Error -> FromIr a
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
refute (NonEmpty Error -> FromIr From) -> NonEmpty Error -> FromIr From
forall a b. (a -> b) -> a -> b
$ Error -> NonEmpty Error
forall a. a -> NonEmpty a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Error
FunctionNotSupported
        IR.FromNativeQuery NativeQuery 'MSSQL Expression
nativeQuery -> NativeQuery 'MSSQL Expression -> FromIr From
fromNativeQuery NativeQuery 'MSSQL Expression
nativeQuery
        IR.FromStoredProcedure {} -> [Char] -> FromIr From
forall a. HasCallStack => [Char] -> a
error [Char]
"fromSelectAggregate: FromStoredProcedure"
      -- Below: When we're actually a RHS of a query (of CROSS APPLY),
      -- then we'll have a LHS table that we're joining on. So we get the
      -- conditions expressions from the field mappings. The LHS table is
      -- the entityAlias, and the RHS table is selectFrom.
      Where
mforeignKeyConditions <- (Maybe [Expression] -> Where)
-> FromIr (Maybe [Expression]) -> FromIr Where
forall a b. (a -> b) -> FromIr a -> FromIr b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([Expression] -> Where
Where ([Expression] -> Where)
-> (Maybe [Expression] -> [Expression])
-> Maybe [Expression]
-> Where
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Expression] -> Maybe [Expression] -> [Expression]
forall a. a -> Maybe a -> a
fromMaybe [])
        (FromIr (Maybe [Expression]) -> FromIr Where)
-> FromIr (Maybe [Expression]) -> FromIr Where
forall a b. (a -> b) -> a -> b
$ Maybe (EntityAlias, HashMap ColumnName ColumnName)
-> ((EntityAlias, HashMap ColumnName ColumnName)
    -> FromIr [Expression])
-> FromIr (Maybe [Expression])
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for Maybe (EntityAlias, HashMap ColumnName ColumnName)
mparentRelationship
        (((EntityAlias, HashMap ColumnName ColumnName)
  -> FromIr [Expression])
 -> FromIr (Maybe [Expression]))
-> ((EntityAlias, HashMap ColumnName ColumnName)
    -> FromIr [Expression])
-> FromIr (Maybe [Expression])
forall a b. (a -> b) -> a -> b
$ \(EntityAlias
entityAlias, HashMap ColumnName ColumnName
mapping) ->
          ReaderT EntityAlias FromIr [Expression]
-> EntityAlias -> FromIr [Expression]
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (From
-> HashMap ColumnName ColumnName
-> ReaderT EntityAlias FromIr [Expression]
fromMapping From
selectFrom HashMap ColumnName ColumnName
mapping) EntityAlias
entityAlias
      Expression
filterExpression <- ReaderT EntityAlias FromIr Expression
-> EntityAlias -> FromIr Expression
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGBoolExp GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
permFilter) (From -> EntityAlias
fromAlias From
selectFrom)
      args' :: Args
args'@Args {Map (Either NativeQueryName TableName) EntityAlias
argsExistingJoins :: Args -> Map (Either NativeQueryName TableName) EntityAlias
argsExistingJoins :: Map (Either NativeQueryName TableName) EntityAlias
argsExistingJoins} <-
        ReaderT EntityAlias FromIr Args -> EntityAlias -> FromIr Args
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (SelectArgsG 'MSSQL Expression -> ReaderT EntityAlias FromIr Args
fromSelectArgsG SelectArgsG 'MSSQL Expression
args) (From -> EntityAlias
fromAlias From
selectFrom)
      -- Although aggregates, exps and nodes could be handled in one list,
      -- we need to separately treat the subselect expressions
      [(Int, Projection)]
expss :: [(Int, Projection)] <- (ReaderT EntityAlias FromIr [(Int, Projection)]
 -> EntityAlias -> FromIr [(Int, Projection)])
-> EntityAlias
-> ReaderT EntityAlias FromIr [(Int, Projection)]
-> FromIr [(Int, Projection)]
forall a b c. (a -> b -> c) -> b -> a -> c
flip ReaderT EntityAlias FromIr [(Int, Projection)]
-> EntityAlias -> FromIr [(Int, Projection)]
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (From -> EntityAlias
fromAlias From
selectFrom) (ReaderT EntityAlias FromIr [(Int, Projection)]
 -> FromIr [(Int, Projection)])
-> ReaderT EntityAlias FromIr [(Int, Projection)]
-> FromIr [(Int, Projection)]
forall a b. (a -> b) -> a -> b
$ [ReaderT EntityAlias FromIr (Int, Projection)]
-> ReaderT EntityAlias FromIr [(Int, Projection)]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => [m a] -> m [a]
sequence ([ReaderT EntityAlias FromIr (Int, Projection)]
 -> ReaderT EntityAlias FromIr [(Int, Projection)])
-> [ReaderT EntityAlias FromIr (Int, Projection)]
-> ReaderT EntityAlias FromIr [(Int, Projection)]
forall a b. (a -> b) -> a -> b
$ ((Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))
 -> Maybe (ReaderT EntityAlias FromIr (Int, Projection)))
-> [(Int,
     (FieldName, TableAggregateFieldG 'MSSQL Void Expression))]
-> [ReaderT EntityAlias FromIr (Int, Projection)]
forall a b. (a -> Maybe b) -> [a] -> [b]
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe (Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))
-> Maybe (ReaderT EntityAlias FromIr (Int, Projection))
fromTableExpFieldG [(Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))]
fields
      [(Int, (FieldName, [FieldSource]))]
nodes :: [(Int, (IR.FieldName, [FieldSource]))] <-
        (ReaderT EntityAlias FromIr [(Int, (FieldName, [FieldSource]))]
 -> EntityAlias -> FromIr [(Int, (FieldName, [FieldSource]))])
-> EntityAlias
-> ReaderT EntityAlias FromIr [(Int, (FieldName, [FieldSource]))]
-> FromIr [(Int, (FieldName, [FieldSource]))]
forall a b c. (a -> b -> c) -> b -> a -> c
flip ReaderT EntityAlias FromIr [(Int, (FieldName, [FieldSource]))]
-> EntityAlias -> FromIr [(Int, (FieldName, [FieldSource]))]
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (From -> EntityAlias
fromAlias From
selectFrom) (ReaderT EntityAlias FromIr [(Int, (FieldName, [FieldSource]))]
 -> FromIr [(Int, (FieldName, [FieldSource]))])
-> ReaderT EntityAlias FromIr [(Int, (FieldName, [FieldSource]))]
-> FromIr [(Int, (FieldName, [FieldSource]))]
forall a b. (a -> b) -> a -> b
$ [ReaderT EntityAlias FromIr (Int, (FieldName, [FieldSource]))]
-> ReaderT EntityAlias FromIr [(Int, (FieldName, [FieldSource]))]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => [m a] -> m [a]
sequence ([ReaderT EntityAlias FromIr (Int, (FieldName, [FieldSource]))]
 -> ReaderT EntityAlias FromIr [(Int, (FieldName, [FieldSource]))])
-> [ReaderT EntityAlias FromIr (Int, (FieldName, [FieldSource]))]
-> ReaderT EntityAlias FromIr [(Int, (FieldName, [FieldSource]))]
forall a b. (a -> b) -> a -> b
$ ((Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))
 -> Maybe
      (ReaderT EntityAlias FromIr (Int, (FieldName, [FieldSource]))))
-> [(Int,
     (FieldName, TableAggregateFieldG 'MSSQL Void Expression))]
-> [ReaderT EntityAlias FromIr (Int, (FieldName, [FieldSource]))]
forall a b. (a -> Maybe b) -> [a] -> [b]
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe (Map (Either NativeQueryName TableName) EntityAlias
-> (Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))
-> Maybe
     (ReaderT EntityAlias FromIr (Int, (FieldName, [FieldSource])))
fromTableNodesFieldG Map (Either NativeQueryName TableName) EntityAlias
argsExistingJoins) [(Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))]
fields
      let [(Int, (FieldName, [Projection]))]
aggregates :: [(Int, (IR.FieldName, [Projection]))] = ((Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))
 -> Maybe (Int, (FieldName, [Projection])))
-> [(Int,
     (FieldName, TableAggregateFieldG 'MSSQL Void Expression))]
-> [(Int, (FieldName, [Projection]))]
forall a b. (a -> Maybe b) -> [a] -> [b]
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe (Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))
-> Maybe (Int, (FieldName, [Projection]))
fromTableAggFieldG [(Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))]
fields
      Select -> FromIr Select
forall a. a -> FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        Select
emptySelect
          { $sel:selectProjections:Select :: [Projection]
selectProjections =
              ((Int, Projection) -> Projection)
-> [(Int, Projection)] -> [Projection]
forall a b. (a -> b) -> [a] -> [b]
map (Int, Projection) -> Projection
forall a b. (a, b) -> b
snd
                ([(Int, Projection)] -> [Projection])
-> [(Int, Projection)] -> [Projection]
forall a b. (a -> b) -> a -> b
$ ((Int, Projection) -> (Int, Projection) -> Ordering)
-> [(Int, Projection)] -> [(Int, Projection)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (((Int, Projection) -> Int)
-> (Int, Projection) -> (Int, Projection) -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing (Int, Projection) -> Int
forall a b. (a, b) -> a
fst)
                ([(Int, Projection)] -> [(Int, Projection)])
-> [(Int, Projection)] -> [(Int, Projection)]
forall a b. (a -> b) -> a -> b
$ [(Int, Projection)]
expss
                [(Int, Projection)] -> [(Int, Projection)] -> [(Int, Projection)]
forall a. Semigroup a => a -> a -> a
<> Args
-> Where
-> Expression
-> Top
-> From
-> [(Int, (FieldName, [FieldSource]))]
-> [(Int, Projection)]
mkNodesSelect Args
args' Where
mforeignKeyConditions Expression
filterExpression Top
permissionBasedTop From
selectFrom [(Int, (FieldName, [FieldSource]))]
nodes
                [(Int, Projection)] -> [(Int, Projection)] -> [(Int, Projection)]
forall a. Semigroup a => a -> a -> a
<> Args
-> Where
-> Expression
-> From
-> [(Int, (FieldName, [Projection]))]
-> [(Int, Projection)]
mkAggregateSelect Args
args' Where
mforeignKeyConditions Expression
filterExpression From
selectFrom [(Int, (FieldName, [Projection]))]
aggregates,
            $sel:selectTop:Select :: Top
selectTop = Top
NoTop,
            $sel:selectFrom:Select :: Maybe From
selectFrom =
              From -> Maybe From
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
                (From -> Maybe From) -> From -> Maybe From
forall a b. (a -> b) -> a -> b
$ Aliased OpenJson -> From
FromOpenJson
                (Aliased OpenJson -> From) -> Aliased OpenJson -> From
forall a b. (a -> b) -> a -> b
$ Aliased
                  { $sel:aliasedThing:Aliased :: OpenJson
aliasedThing =
                      OpenJson
                        { $sel:openJsonExpression:OpenJson :: Expression
openJsonExpression = Value -> Expression
ValueExpression (Value -> Expression) -> Value -> Expression
forall a b. (a -> b) -> a -> b
$ Text -> Value
ODBC.TextValue Text
"[0]",
                          $sel:openJsonWith:OpenJson :: Maybe (NonEmpty JsonFieldSpec)
openJsonWith = Maybe (NonEmpty JsonFieldSpec)
forall a. Maybe a
Nothing
                        },
                    $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
existsFieldName
                  },
            $sel:selectJoins:Select :: [Join]
selectJoins = [Join]
forall a. Monoid a => a
mempty, -- JOINs and WHEREs are only relevant in subselects
            $sel:selectWhere:Select :: Where
selectWhere = Where
forall a. Monoid a => a
mempty,
            $sel:selectFor:Select :: For
selectFor = ForJson -> For
JsonFor ForJson {$sel:jsonCardinality:ForJson :: JsonCardinality
jsonCardinality = JsonCardinality
JsonSingleton, $sel:jsonRoot:ForJson :: Root
jsonRoot = Root
NoRoot},
            $sel:selectOrderBy:Select :: Maybe (NonEmpty OrderBy)
selectOrderBy = Maybe (NonEmpty OrderBy)
forall a. Maybe a
Nothing,
            $sel:selectOffset:Select :: Maybe Expression
selectOffset = Maybe Expression
forall a. Maybe a
Nothing
          }

--------------------------------------------------------------------------------
-- GraphQL Args

data Args = Args
  { Args -> Where
argsWhere :: Where,
    Args -> Maybe (NonEmpty OrderBy)
argsOrderBy :: Maybe (NonEmpty OrderBy),
    Args -> [Join]
argsJoins :: [Join],
    Args -> Top
argsTop :: Top,
    Args -> Maybe Expression
argsOffset :: Maybe Expression,
    Args -> Proxy (Maybe (NonEmpty FieldName))
argsDistinct :: Proxy (Maybe (NonEmpty FieldName)),
    Args -> Map (Either NativeQueryName TableName) EntityAlias
argsExistingJoins :: Map (Either NativeQueryName TableName) EntityAlias
  }
  deriving (Int -> Args -> ShowS
[Args] -> ShowS
Args -> [Char]
(Int -> Args -> ShowS)
-> (Args -> [Char]) -> ([Args] -> ShowS) -> Show Args
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Args -> ShowS
showsPrec :: Int -> Args -> ShowS
$cshow :: Args -> [Char]
show :: Args -> [Char]
$cshowList :: [Args] -> ShowS
showList :: [Args] -> ShowS
Show)

fromSelectArgsG :: IR.SelectArgsG 'MSSQL Expression -> ReaderT EntityAlias FromIr Args
fromSelectArgsG :: SelectArgsG 'MSSQL Expression -> ReaderT EntityAlias FromIr Args
fromSelectArgsG SelectArgsG 'MSSQL Expression
selectArgsG = do
  let argsOffset :: Maybe Expression
argsOffset = Value -> Expression
ValueExpression (Value -> Expression) -> (Int64 -> Value) -> Int64 -> Expression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Value
ODBC.IntValue (Int -> Value) -> (Int64 -> Int) -> Int64 -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64 -> Expression) -> Maybe Int64 -> Maybe Expression
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Int64
moffset
  Where
argsWhere <-
    ReaderT EntityAlias FromIr Where
-> (GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
    -> ReaderT EntityAlias FromIr Where)
-> Maybe (GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression))
-> ReaderT EntityAlias FromIr Where
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Where -> ReaderT EntityAlias FromIr Where
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Where
forall a. Monoid a => a
mempty) ((Expression -> Where)
-> ReaderT EntityAlias FromIr Expression
-> ReaderT EntityAlias FromIr Where
forall a b.
(a -> b)
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([Expression] -> Where
Where ([Expression] -> Where)
-> (Expression -> [Expression]) -> Expression -> Where
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expression -> [Expression]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure) (ReaderT EntityAlias FromIr Expression
 -> ReaderT EntityAlias FromIr Where)
-> (GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
    -> ReaderT EntityAlias FromIr Expression)
-> GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Where
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGBoolExp) Maybe (GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression))
mannBoolExp
  Top
argsTop <-
    ReaderT EntityAlias FromIr Top
-> (Int -> ReaderT EntityAlias FromIr Top)
-> Maybe Int
-> ReaderT EntityAlias FromIr Top
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Top -> ReaderT EntityAlias FromIr Top
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Top
forall a. Monoid a => a
mempty) (Top -> ReaderT EntityAlias FromIr Top
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Top -> ReaderT EntityAlias FromIr Top)
-> (Int -> Top) -> Int -> ReaderT EntityAlias FromIr Top
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Top
Top) Maybe Int
mlimit
  -- Not supported presently, per Vamshi:
  --
  -- > It is hardly used and we don't have to go to great lengths to support it.
  --
  -- But placeholdering the code so that when it's ready to be used,
  -- you can just drop the Proxy wrapper.
  let argsDistinct :: Proxy t
argsDistinct = Proxy t
forall {k} (t :: k). Proxy t
Proxy
  ([OrderBy]
argsOrderBy, Seq UnfurledJoin
joins) <-
    WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) [OrderBy]
-> ReaderT EntityAlias FromIr ([OrderBy], Seq UnfurledJoin)
forall w (m :: * -> *) a. WriterT w m a -> m (a, w)
runWriterT ((AnnotatedOrderByItemG 'MSSQL Expression
 -> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) OrderBy)
-> [AnnotatedOrderByItemG 'MSSQL Expression]
-> WriterT
     (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) [OrderBy]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse AnnotatedOrderByItemG 'MSSQL Expression
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) OrderBy
fromAnnotatedOrderByItemG ([AnnotatedOrderByItemG 'MSSQL Expression]
-> (NonEmpty (AnnotatedOrderByItemG 'MSSQL Expression)
    -> [AnnotatedOrderByItemG 'MSSQL Expression])
-> Maybe (NonEmpty (AnnotatedOrderByItemG 'MSSQL Expression))
-> [AnnotatedOrderByItemG 'MSSQL Expression]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] NonEmpty (AnnotatedOrderByItemG 'MSSQL Expression)
-> [AnnotatedOrderByItemG 'MSSQL Expression]
forall a. NonEmpty a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Maybe (NonEmpty (AnnotatedOrderByItemG 'MSSQL Expression))
orders))
  -- Any object-relation joins that we generated, we record their
  -- generated names into a mapping.
  let argsExistingJoins :: Map (Either NativeQueryName TableName) EntityAlias
argsExistingJoins =
        [(Either NativeQueryName TableName, EntityAlias)]
-> Map (Either NativeQueryName TableName) EntityAlias
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ((UnfurledJoin
 -> Maybe (Either NativeQueryName TableName, EntityAlias))
-> [UnfurledJoin]
-> [(Either NativeQueryName TableName, EntityAlias)]
forall a b. (a -> Maybe b) -> [a] -> [b]
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe UnfurledJoin
-> Maybe (Either NativeQueryName TableName, EntityAlias)
unfurledObjectTableAlias (Seq UnfurledJoin -> [UnfurledJoin]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Seq UnfurledJoin
joins))
  Args -> ReaderT EntityAlias FromIr Args
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    Args
      { argsJoins :: [Join]
argsJoins = Seq Join -> [Join]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList ((UnfurledJoin -> Join) -> Seq UnfurledJoin -> Seq Join
forall a b. (a -> b) -> Seq a -> Seq b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap UnfurledJoin -> Join
unfurledJoin Seq UnfurledJoin
joins),
        argsOrderBy :: Maybe (NonEmpty OrderBy)
argsOrderBy = [OrderBy] -> Maybe (NonEmpty OrderBy)
forall a. [a] -> Maybe (NonEmpty a)
nonEmpty [OrderBy]
argsOrderBy,
        Maybe Expression
Map (Either NativeQueryName TableName) EntityAlias
Proxy (Maybe (NonEmpty FieldName))
Top
Where
forall {t}. Proxy t
argsWhere :: Where
argsTop :: Top
argsDistinct :: Proxy (Maybe (NonEmpty FieldName))
argsOffset :: Maybe Expression
argsExistingJoins :: Map (Either NativeQueryName TableName) EntityAlias
argsOffset :: Maybe Expression
argsWhere :: Where
argsTop :: Top
argsDistinct :: forall {t}. Proxy t
argsExistingJoins :: Map (Either NativeQueryName TableName) EntityAlias
..
      }
  where
    IR.SelectArgs
      { $sel:_saWhere:SelectArgs :: forall (b :: BackendType) v.
SelectArgsG b v -> Maybe (AnnBoolExp b v)
_saWhere = Maybe (GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression))
mannBoolExp,
        $sel:_saLimit:SelectArgs :: forall (b :: BackendType) v. SelectArgsG b v -> Maybe Int
_saLimit = Maybe Int
mlimit,
        $sel:_saOffset:SelectArgs :: forall (b :: BackendType) v. SelectArgsG b v -> Maybe Int64
_saOffset = Maybe Int64
moffset,
        $sel:_saOrderBy:SelectArgs :: forall (b :: BackendType) v.
SelectArgsG b v -> Maybe (NonEmpty (AnnotatedOrderByItemG b v))
_saOrderBy = Maybe (NonEmpty (AnnotatedOrderByItemG 'MSSQL Expression))
orders
      } = SelectArgsG 'MSSQL Expression
selectArgsG

--------------------------------------------------------------------------------
-- Conversion functions
fromQualifiedTable :: TableName -> FromIr From
fromQualifiedTable :: TableName -> FromIr From
fromQualifiedTable schemadTableName :: TableName
schemadTableName@(TableName {Text
tableName :: Text
$sel:tableName:TableName :: TableName -> Text
tableName}) = do
  Text
alias <- NameTemplate -> FromIr Text
generateAlias (Text -> NameTemplate
TableTemplate Text
tableName)
  From -> FromIr From
forall a. a -> FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    ( Aliased TableName -> From
FromQualifiedTable
        ( Aliased
            { $sel:aliasedThing:Aliased :: TableName
aliasedThing = TableName
schemadTableName,
              $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
alias
            }
        )
    )

--------------------------------------------------------------------------------
-- Sources of projected fields
--
-- Because in the IR, a field projected can be a foreign object, we
-- have to both generate a projection AND on the side generate a join.
--
-- So a @FieldSource@ couples the idea of the projected thing and the
-- source of it (via 'Aliased').

data FieldSource
  = ExpressionFieldSource (Aliased Expression)
  | JoinFieldSource JsonCardinality (Aliased Join)
  deriving (FieldSource -> FieldSource -> Bool
(FieldSource -> FieldSource -> Bool)
-> (FieldSource -> FieldSource -> Bool) -> Eq FieldSource
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FieldSource -> FieldSource -> Bool
== :: FieldSource -> FieldSource -> Bool
$c/= :: FieldSource -> FieldSource -> Bool
/= :: FieldSource -> FieldSource -> Bool
Eq, Int -> FieldSource -> ShowS
[FieldSource] -> ShowS
FieldSource -> [Char]
(Int -> FieldSource -> ShowS)
-> (FieldSource -> [Char])
-> ([FieldSource] -> ShowS)
-> Show FieldSource
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FieldSource -> ShowS
showsPrec :: Int -> FieldSource -> ShowS
$cshow :: FieldSource -> [Char]
show :: FieldSource -> [Char]
$cshowList :: [FieldSource] -> ShowS
showList :: [FieldSource] -> ShowS
Show)

-- | Get FieldSource from a TAFExp type table aggregate field
fromTableExpFieldG :: -- TODO: Convert function to be similar to Nodes function
  (Int, (IR.FieldName, IR.TableAggregateFieldG 'MSSQL Void Expression)) ->
  Maybe (ReaderT EntityAlias FromIr (Int, Projection))
fromTableExpFieldG :: (Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))
-> Maybe (ReaderT EntityAlias FromIr (Int, Projection))
fromTableExpFieldG = \case
  (Int
index, (IR.FieldName Text
name, IR.TAFExp Text
text)) ->
    ReaderT EntityAlias FromIr (Int, Projection)
-> Maybe (ReaderT EntityAlias FromIr (Int, Projection))
forall a. a -> Maybe a
Just
      (ReaderT EntityAlias FromIr (Int, Projection)
 -> Maybe (ReaderT EntityAlias FromIr (Int, Projection)))
-> ReaderT EntityAlias FromIr (Int, Projection)
-> Maybe (ReaderT EntityAlias FromIr (Int, Projection))
forall a b. (a -> b) -> a -> b
$ (Int, Projection) -> ReaderT EntityAlias FromIr (Int, Projection)
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
      ((Int, Projection) -> ReaderT EntityAlias FromIr (Int, Projection))
-> (Int, Projection)
-> ReaderT EntityAlias FromIr (Int, Projection)
forall a b. (a -> b) -> a -> b
$ ( Int
index,
          FieldSource -> Projection
fieldSourceProjections
            (FieldSource -> Projection) -> FieldSource -> Projection
forall a b. (a -> b) -> a -> b
$ Aliased Expression -> FieldSource
ExpressionFieldSource
              Aliased
                { $sel:aliasedThing:Aliased :: Expression
aliasedThing = Value -> Expression
TSQL.ValueExpression (Text -> Value
ODBC.TextValue Text
text),
                  $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
name
                }
        )
  (Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))
_ -> Maybe (ReaderT EntityAlias FromIr (Int, Projection))
forall a. Maybe a
Nothing

fromTableAggFieldG ::
  (Int, (IR.FieldName, IR.TableAggregateFieldG 'MSSQL Void Expression)) ->
  Maybe (Int, (IR.FieldName, [Projection]))
fromTableAggFieldG :: (Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))
-> Maybe (Int, (FieldName, [Projection]))
fromTableAggFieldG = \case
  (Int
index, (FieldName
fieldName, IR.TAFAgg ([(FieldName, AggregateField 'MSSQL Expression)]
aggregateFields :: [(IR.FieldName, IR.AggregateField 'MSSQL Expression)]))) ->
    (Int, (FieldName, [Projection]))
-> Maybe (Int, (FieldName, [Projection]))
forall a. a -> Maybe a
Just
      ((Int, (FieldName, [Projection]))
 -> Maybe (Int, (FieldName, [Projection])))
-> (Int, (FieldName, [Projection]))
-> Maybe (Int, (FieldName, [Projection]))
forall a b. (a -> b) -> a -> b
$ let aggregates :: [Projection]
aggregates =
              [(FieldName, AggregateField 'MSSQL Expression)]
aggregateFields [(FieldName, AggregateField 'MSSQL Expression)]
-> ((FieldName, AggregateField 'MSSQL Expression) -> Projection)
-> [Projection]
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \(FieldName
fieldName', AggregateField 'MSSQL Expression
aggregateField) ->
                Text -> AggregateField 'MSSQL Expression -> Projection
fromAggregateField (FieldName -> Text
IR.getFieldNameTxt FieldName
fieldName') AggregateField 'MSSQL Expression
aggregateField
         in (Int
index, (FieldName
fieldName, [Projection]
aggregates))
  (Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))
_ -> Maybe (Int, (FieldName, [Projection]))
forall a. Maybe a
Nothing

fromTableNodesFieldG ::
  Map (Either NativeQueryName TableName) EntityAlias ->
  (Int, (IR.FieldName, IR.TableAggregateFieldG 'MSSQL Void Expression)) ->
  Maybe (ReaderT EntityAlias FromIr (Int, (IR.FieldName, [FieldSource])))
fromTableNodesFieldG :: Map (Either NativeQueryName TableName) EntityAlias
-> (Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))
-> Maybe
     (ReaderT EntityAlias FromIr (Int, (FieldName, [FieldSource])))
fromTableNodesFieldG Map (Either NativeQueryName TableName) EntityAlias
argsExistingJoins = \case
  (Int
index, (FieldName
fieldName, IR.TAFNodes () ([(FieldName, AnnFieldG 'MSSQL Void Expression)]
annFieldsG :: [(IR.FieldName, IR.AnnFieldG 'MSSQL Void Expression)]))) -> ReaderT EntityAlias FromIr (Int, (FieldName, [FieldSource]))
-> Maybe
     (ReaderT EntityAlias FromIr (Int, (FieldName, [FieldSource])))
forall a. a -> Maybe a
Just do
    [FieldSource]
fieldSources' <- Map (Either NativeQueryName TableName) EntityAlias
-> (FieldName, AnnFieldG 'MSSQL Void Expression)
-> ReaderT EntityAlias FromIr FieldSource
fromAnnFieldsG Map (Either NativeQueryName TableName) EntityAlias
argsExistingJoins ((FieldName, AnnFieldG 'MSSQL Void Expression)
 -> ReaderT EntityAlias FromIr FieldSource)
-> [(FieldName, AnnFieldG 'MSSQL Void Expression)]
-> ReaderT EntityAlias FromIr [FieldSource]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
`traverse` [(FieldName, AnnFieldG 'MSSQL Void Expression)]
annFieldsG
    (Int, (FieldName, [FieldSource]))
-> ReaderT EntityAlias FromIr (Int, (FieldName, [FieldSource]))
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int
index, (FieldName
fieldName, [FieldSource]
fieldSources'))
  (Int, (FieldName, TableAggregateFieldG 'MSSQL Void Expression))
_ -> Maybe
  (ReaderT EntityAlias FromIr (Int, (FieldName, [FieldSource])))
forall a. Maybe a
Nothing

fromAggregateField :: Text -> IR.AggregateField 'MSSQL Expression -> Projection
fromAggregateField :: Text -> AggregateField 'MSSQL Expression -> Projection
fromAggregateField Text
alias AggregateField 'MSSQL Expression
aggregateField =
  case AggregateField 'MSSQL Expression
aggregateField of
    IR.AFExp Text
text -> Aliased Aggregate -> Projection
AggregateProjection (Aliased Aggregate -> Projection)
-> Aliased Aggregate -> Projection
forall a b. (a -> b) -> a -> b
$ Aggregate -> Text -> Aliased Aggregate
forall a. a -> Text -> Aliased a
Aliased (Text -> Aggregate
TextAggregate Text
text) Text
alias
    IR.AFCount CountType 'MSSQL Expression
countType -> Aliased Aggregate -> Projection
AggregateProjection (Aliased Aggregate -> Projection)
-> (Countable FieldName -> Aliased Aggregate)
-> Countable FieldName
-> Projection
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Aggregate -> Text -> Aliased Aggregate)
-> Text -> Aggregate -> Aliased Aggregate
forall a b c. (a -> b -> c) -> b -> a -> c
flip Aggregate -> Text -> Aliased Aggregate
forall a. a -> Text -> Aliased a
Aliased Text
alias (Aggregate -> Aliased Aggregate)
-> (Countable FieldName -> Aggregate)
-> Countable FieldName
-> Aliased Aggregate
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Countable FieldName -> Aggregate
CountAggregate (Countable FieldName -> Projection)
-> Countable FieldName -> Projection
forall a b. (a -> b) -> a -> b
$ case Const (Countable ColumnName) Expression -> Countable ColumnName
forall {k} a (b :: k). Const a b -> a
getConst Const (Countable ColumnName) Expression
CountType 'MSSQL Expression
countType of
      Countable ColumnName
StarCountable -> Countable FieldName
forall name. Countable name
StarCountable
      NonNullFieldCountable ColumnName
name -> FieldName -> Countable FieldName
forall name. name -> Countable name
NonNullFieldCountable (FieldName -> Countable FieldName)
-> FieldName -> Countable FieldName
forall a b. (a -> b) -> a -> b
$ ColumnName -> FieldName
columnFieldAggEntity ColumnName
name
      DistinctCountable ColumnName
name -> FieldName -> Countable FieldName
forall name. name -> Countable name
DistinctCountable (FieldName -> Countable FieldName)
-> FieldName -> Countable FieldName
forall a b. (a -> b) -> a -> b
$ ColumnName -> FieldName
columnFieldAggEntity ColumnName
name
    IR.AFOp IR.AggregateOp {$sel:_aoOp:AggregateOp :: forall (b :: BackendType) v. AggregateOp b v -> Text
_aoOp = Text
op, $sel:_aoFields:AggregateOp :: forall (b :: BackendType) v. AggregateOp b v -> SelectionFields b v
_aoFields = SelectionFields 'MSSQL Expression
fields} ->
      let [Projection]
projections :: [Projection] =
            SelectionFields 'MSSQL Expression
fields SelectionFields 'MSSQL Expression
-> ((FieldName, SelectionField 'MSSQL Expression) -> Projection)
-> [Projection]
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \(FieldName
fieldName, SelectionField 'MSSQL Expression
columnField) ->
              case SelectionField 'MSSQL Expression
columnField of
                -- TODO(redactionExp): Deal with redaction expression?
                IR.SFCol Column 'MSSQL
column ColumnType 'MSSQL
_columnType AnnRedactionExp 'MSSQL Expression
_redactionExp ->
                  let fname :: FieldName
fname = ColumnName -> FieldName
columnFieldAggEntity Column 'MSSQL
ColumnName
column
                   in Aliased Aggregate -> Projection
AggregateProjection (Aliased Aggregate -> Projection)
-> Aliased Aggregate -> Projection
forall a b. (a -> b) -> a -> b
$ Aggregate -> Text -> Aliased Aggregate
forall a. a -> Text -> Aliased a
Aliased (Text -> [Expression] -> Aggregate
OpAggregate Text
op [FieldName -> Expression
ColumnExpression FieldName
fname]) (FieldName -> Text
IR.getFieldNameTxt FieldName
fieldName)
                IR.SFExp Text
text ->
                  Aliased Expression -> Projection
ExpressionProjection (Aliased Expression -> Projection)
-> Aliased Expression -> Projection
forall a b. (a -> b) -> a -> b
$ Expression -> Text -> Aliased Expression
forall a. a -> Text -> Aliased a
Aliased (Value -> Expression
ValueExpression (Text -> Value
ODBC.TextValue Text
text)) (FieldName -> Text
IR.getFieldNameTxt FieldName
fieldName)
                -- See Hasura.RQL.Types.Backend.supportsAggregateComputedFields
                IR.SFComputedField ComputedFieldName
_ ComputedFieldScalarSelect 'MSSQL Expression
_ -> [Char] -> Projection
forall a. HasCallStack => [Char] -> a
error [Char]
"Aggregate computed fields aren't currently supported for MSSQL!"
       in Aliased Expression -> Projection
ExpressionProjection
            (Aliased Expression -> Projection)
-> Aliased Expression -> Projection
forall a b. (a -> b) -> a -> b
$ (Expression -> Text -> Aliased Expression)
-> Text -> Expression -> Aliased Expression
forall a b c. (a -> b -> c) -> b -> a -> c
flip Expression -> Text -> Aliased Expression
forall a. a -> Text -> Aliased a
Aliased Text
alias
            (Expression -> Aliased Expression)
-> Expression -> Aliased Expression
forall a b. (a -> b) -> a -> b
$ JsonCardinality -> Expression -> Expression
safeJsonQueryExpression JsonCardinality
JsonSingleton
            (Expression -> Expression) -> Expression -> Expression
forall a b. (a -> b) -> a -> b
$ Select -> Expression
SelectExpression
            (Select -> Expression) -> Select -> Expression
forall a b. (a -> b) -> a -> b
$ Select
emptySelect
              { $sel:selectProjections:Select :: [Projection]
selectProjections = [Projection]
projections,
                $sel:selectFor:Select :: For
selectFor = ForJson -> For
JsonFor (ForJson -> For) -> ForJson -> For
forall a b. (a -> b) -> a -> b
$ JsonCardinality -> Root -> ForJson
ForJson JsonCardinality
JsonSingleton Root
NoRoot
              }
  where
    columnFieldAggEntity :: ColumnName -> FieldName
columnFieldAggEntity ColumnName
col = ColumnName -> EntityAlias -> FieldName
columnNameToFieldName ColumnName
col (EntityAlias -> FieldName) -> EntityAlias -> FieldName
forall a b. (a -> b) -> a -> b
$ Text -> EntityAlias
EntityAlias Text
aggSubselectName

-- | The main sources of fields, either constants, fields or via joins.
fromAnnFieldsG ::
  Map (Either NativeQueryName TableName) EntityAlias ->
  (IR.FieldName, IR.AnnFieldG 'MSSQL Void Expression) ->
  ReaderT EntityAlias FromIr FieldSource
fromAnnFieldsG :: Map (Either NativeQueryName TableName) EntityAlias
-> (FieldName, AnnFieldG 'MSSQL Void Expression)
-> ReaderT EntityAlias FromIr FieldSource
fromAnnFieldsG Map (Either NativeQueryName TableName) EntityAlias
existingJoins (IR.FieldName Text
name, AnnFieldG 'MSSQL Void Expression
field) =
  case AnnFieldG 'MSSQL Void Expression
field of
    IR.AFColumn AnnColumnField 'MSSQL Expression
annColumnField -> do
      Expression
expression <- AnnColumnField 'MSSQL Expression
-> ReaderT EntityAlias FromIr Expression
fromAnnColumnField AnnColumnField 'MSSQL Expression
annColumnField
      FieldSource -> ReaderT EntityAlias FromIr FieldSource
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        ( Aliased Expression -> FieldSource
ExpressionFieldSource
            Aliased {$sel:aliasedThing:Aliased :: Expression
aliasedThing = Expression
expression, $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
name}
        )
    IR.AFExpression Text
text ->
      FieldSource -> ReaderT EntityAlias FromIr FieldSource
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        ( Aliased Expression -> FieldSource
ExpressionFieldSource
            Aliased
              { $sel:aliasedThing:Aliased :: Expression
aliasedThing = Value -> Expression
TSQL.ValueExpression (Text -> Value
ODBC.TextValue Text
text),
                $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
name
              }
        )
    IR.AFObjectRelation ObjectRelationSelectG 'MSSQL Void Expression
objectRelationSelectG ->
      (Join -> FieldSource)
-> ReaderT EntityAlias FromIr Join
-> ReaderT EntityAlias FromIr FieldSource
forall a b.
(a -> b)
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
        ( \Join
aliasedThing ->
            JsonCardinality -> Aliased Join -> FieldSource
JoinFieldSource JsonCardinality
JsonSingleton (Aliased {Join
$sel:aliasedThing:Aliased :: Join
aliasedThing :: Join
aliasedThing, $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
name})
        )
        (Map (Either NativeQueryName TableName) EntityAlias
-> ObjectRelationSelectG 'MSSQL Void Expression
-> ReaderT EntityAlias FromIr Join
fromObjectRelationSelectG Map (Either NativeQueryName TableName) EntityAlias
existingJoins ObjectRelationSelectG 'MSSQL Void Expression
objectRelationSelectG)
    IR.AFArrayRelation ArraySelectG 'MSSQL Void Expression
arraySelectG ->
      (Join -> FieldSource)
-> ReaderT EntityAlias FromIr Join
-> ReaderT EntityAlias FromIr FieldSource
forall a b.
(a -> b)
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
        ( \Join
aliasedThing ->
            JsonCardinality -> Aliased Join -> FieldSource
JoinFieldSource JsonCardinality
JsonArray (Aliased {Join
$sel:aliasedThing:Aliased :: Join
aliasedThing :: Join
aliasedThing, $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
name})
        )
        (ArraySelectG 'MSSQL Void Expression
-> ReaderT EntityAlias FromIr Join
fromArraySelectG ArraySelectG 'MSSQL Void Expression
arraySelectG)

-- | Here is where we project a field as a column expression. If
-- number stringification is on, then we wrap it in a
-- 'ToStringExpression' so that it's casted when being projected.
fromAnnColumnField ::
  IR.AnnColumnField 'MSSQL Expression ->
  ReaderT EntityAlias FromIr Expression
fromAnnColumnField :: AnnColumnField 'MSSQL Expression
-> ReaderT EntityAlias FromIr Expression
fromAnnColumnField AnnColumnField 'MSSQL Expression
annColumnField = do
  FieldName
fieldName <- ColumnName -> ReaderT EntityAlias FromIr FieldName
fromColumn Column 'MSSQL
ColumnName
column
  -- TODO: Handle stringifying large numbers
  {-(IR.isScalarColumnWhere isBigNum typ && stringifyNumbers == IR.StringifyNumbers)-}

  -- for geometry and geography values, the automatic json encoding on sql
  -- server would fail. So we need to convert it to a format the json encoding
  -- handles. Ideally we want this representation to be GeoJSON but sql server
  -- doesn't have any functions to convert to GeoJSON format. So we return it in
  -- WKT format
  if ColumnType 'MSSQL
typ ColumnType 'MSSQL -> ColumnType 'MSSQL -> Bool
forall a. Eq a => a -> a -> Bool
== (ScalarType 'MSSQL -> ColumnType 'MSSQL
forall (b :: BackendType). ScalarType b -> ColumnType b
IR.ColumnScalar ScalarType 'MSSQL
ScalarType
GeometryType) Bool -> Bool -> Bool
|| ColumnType 'MSSQL
typ ColumnType 'MSSQL -> ColumnType 'MSSQL -> Bool
forall a. Eq a => a -> a -> Bool
== (ScalarType 'MSSQL -> ColumnType 'MSSQL
forall (b :: BackendType). ScalarType b -> ColumnType b
IR.ColumnScalar ScalarType 'MSSQL
ScalarType
GeographyType)
    then Expression -> ReaderT EntityAlias FromIr Expression
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> ReaderT EntityAlias FromIr Expression)
-> Expression -> ReaderT EntityAlias FromIr Expression
forall a b. (a -> b) -> a -> b
$ Expression -> MethodApplicationExpression -> Expression
MethodApplicationExpression (FieldName -> Expression
ColumnExpression FieldName
fieldName) MethodApplicationExpression
MethExpSTAsText
    else case AnnRedactionExp 'MSSQL Expression
redactionExp of
      AnnRedactionExp 'MSSQL Expression
IR.NoRedaction -> Expression -> ReaderT EntityAlias FromIr Expression
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FieldName -> Expression
ColumnExpression FieldName
fieldName)
      IR.RedactIfFalse GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
ex -> do
        Expression
ex' <- GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGBoolExp (GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
forall a b. Coercible a b => a -> b
coerce GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
ex)
        let nullValue :: Expression
nullValue = Value -> Expression
ValueExpression Value
ODBC.NullValue
        Expression -> ReaderT EntityAlias FromIr Expression
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression -> Expression -> Expression -> Expression
ConditionalExpression Expression
ex' (FieldName -> Expression
ColumnExpression FieldName
fieldName) Expression
nullValue)
  where
    IR.AnnColumnField
      { $sel:_acfColumn:AnnColumnField :: forall (b :: BackendType) v. AnnColumnField b v -> Column b
_acfColumn = Column 'MSSQL
column,
        $sel:_acfType:AnnColumnField :: forall (b :: BackendType) v. AnnColumnField b v -> ColumnType b
_acfType = ColumnType 'MSSQL
typ,
        $sel:_acfAsText:AnnColumnField :: forall (b :: BackendType) v. AnnColumnField b v -> Bool
_acfAsText = Bool
_asText :: Bool,
        $sel:_acfArguments:AnnColumnField :: forall (b :: BackendType) v.
AnnColumnField b v -> Maybe (ScalarSelectionArguments b)
_acfArguments = Maybe Void
_ :: Maybe Void,
        $sel:_acfRedactionExpression:AnnColumnField :: forall (b :: BackendType) v.
AnnColumnField b v -> AnnRedactionExp b v
_acfRedactionExpression = AnnRedactionExp 'MSSQL Expression
redactionExp
      } = AnnColumnField 'MSSQL Expression
annColumnField

-- | This is where a field name "foo" is resolved to a fully qualified
-- field name [table].[foo]. The table name comes from EntityAlias in
-- the ReaderT.
fromColumn :: ColumnName -> ReaderT EntityAlias FromIr FieldName
fromColumn :: ColumnName -> ReaderT EntityAlias FromIr FieldName
fromColumn ColumnName
column = ColumnName -> EntityAlias -> FieldName
columnNameToFieldName ColumnName
column (EntityAlias -> FieldName)
-> ReaderT EntityAlias FromIr EntityAlias
-> ReaderT EntityAlias FromIr FieldName
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReaderT EntityAlias FromIr EntityAlias
forall r (m :: * -> *). MonadReader r m => m r
ask

--  entityAlias <- ask
--  pure (columnNameToFieldName column entityAlias -- FieldName {fieldName = columnName column, fieldNameEntity = entityAliasText}
--       )

fieldSourceProjections :: FieldSource -> Projection
fieldSourceProjections :: FieldSource -> Projection
fieldSourceProjections =
  \case
    ExpressionFieldSource Aliased Expression
aliasedExpression ->
      Aliased Expression -> Projection
ExpressionProjection Aliased Expression
aliasedExpression
    JoinFieldSource JsonCardinality
cardinality Aliased Join
aliasedJoin ->
      Aliased Expression -> Projection
ExpressionProjection
        ( Aliased Join
aliasedJoin
            { $sel:aliasedThing:Aliased :: Expression
aliasedThing =
                -- Basically a cast, to ensure that SQL Server won't
                -- double-encode the JSON but will "pass it through"
                -- untouched.
                JsonCardinality -> Expression -> Expression
safeJsonQueryExpression
                  JsonCardinality
cardinality
                  ( FieldName -> Expression
ColumnExpression
                      ( JoinAlias -> FieldName
joinAliasToField
                          (Join -> JoinAlias
joinJoinAlias (Aliased Join -> Join
forall a. Aliased a -> a
aliasedThing Aliased Join
aliasedJoin))
                      )
                  )
            }
        )

joinAliasToField :: JoinAlias -> FieldName
joinAliasToField :: JoinAlias -> FieldName
joinAliasToField JoinAlias {Maybe Text
Text
joinAliasEntity :: Text
joinAliasField :: Maybe Text
$sel:joinAliasEntity:JoinAlias :: JoinAlias -> Text
$sel:joinAliasField:JoinAlias :: JoinAlias -> Maybe Text
..} =
  FieldName
    { $sel:fieldNameEntity:FieldName :: Text
fieldNameEntity = Text
joinAliasEntity,
      $sel:fieldName:FieldName :: Text
fieldName = Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe ([Char] -> Text
forall a. HasCallStack => [Char] -> a
error [Char]
"TODO: Eliminate this case. joinAliasToField") Maybe Text
joinAliasField
    }

fieldSourceJoin :: FieldSource -> Maybe Join
fieldSourceJoin :: FieldSource -> Maybe Join
fieldSourceJoin =
  \case
    JoinFieldSource JsonCardinality
_ Aliased Join
aliasedJoin -> Join -> Maybe Join
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Aliased Join -> Join
forall a. Aliased a -> a
aliasedThing Aliased Join
aliasedJoin)
    ExpressionFieldSource {} -> Maybe Join
forall a. Maybe a
Nothing

--------------------------------------------------------------------------------
-- Joins

fromObjectRelationSelectG ::
  Map (Either NativeQueryName TableName) EntityAlias ->
  IR.ObjectRelationSelectG 'MSSQL Void Expression ->
  ReaderT EntityAlias FromIr Join
fromObjectRelationSelectG :: Map (Either NativeQueryName TableName) EntityAlias
-> ObjectRelationSelectG 'MSSQL Void Expression
-> ReaderT EntityAlias FromIr Join
fromObjectRelationSelectG Map (Either NativeQueryName TableName) EntityAlias
existingJoins ObjectRelationSelectG 'MSSQL Void Expression
annRelationSelectG = do
  Either EntityAlias From
eitherAliasOrFrom <-
    case SelectFromG 'MSSQL Expression
target of
      IR.FromTable TableName 'MSSQL
t -> FromIr (Either EntityAlias From)
-> ReaderT EntityAlias FromIr (Either EntityAlias From)
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Map (Either NativeQueryName TableName) EntityAlias
-> TableName -> FromIr (Either EntityAlias From)
lookupTableFrom Map (Either NativeQueryName TableName) EntityAlias
existingJoins TableName 'MSSQL
TableName
t)
      IR.FromNativeQuery NativeQuery 'MSSQL Expression
q -> FromIr (Either EntityAlias From)
-> ReaderT EntityAlias FromIr (Either EntityAlias From)
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Map (Either NativeQueryName TableName) EntityAlias
-> NativeQuery 'MSSQL Expression
-> FromIr (Either EntityAlias From)
lookupNativeQueryFrom Map (Either NativeQueryName TableName) EntityAlias
existingJoins NativeQuery 'MSSQL Expression
q)
      SelectFromG 'MSSQL Expression
other -> [Char] -> ReaderT EntityAlias FromIr (Either EntityAlias From)
forall a. HasCallStack => [Char] -> a
error ([Char] -> ReaderT EntityAlias FromIr (Either EntityAlias From))
-> [Char] -> ReaderT EntityAlias FromIr (Either EntityAlias From)
forall a b. (a -> b) -> a -> b
$ [Char]
"fromObjectRelationSelectG: " [Char] -> ShowS
forall a. Semigroup a => a -> a -> a
<> SelectFromG 'MSSQL Expression -> [Char]
forall a. Show a => a -> [Char]
show SelectFromG 'MSSQL Expression
other
  let EntityAlias
entityAlias :: EntityAlias = (EntityAlias -> EntityAlias)
-> (From -> EntityAlias) -> Either EntityAlias From -> EntityAlias
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either EntityAlias -> EntityAlias
forall a. a -> a
id From -> EntityAlias
fromAlias Either EntityAlias From
eitherAliasOrFrom
  [FieldSource]
fieldSources <-
    (EntityAlias -> EntityAlias)
-> ReaderT EntityAlias FromIr [FieldSource]
-> ReaderT EntityAlias FromIr [FieldSource]
forall a.
(EntityAlias -> EntityAlias)
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr a
forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local
      (EntityAlias -> EntityAlias -> EntityAlias
forall a b. a -> b -> a
const EntityAlias
entityAlias)
      (((FieldName, AnnFieldG 'MSSQL Void Expression)
 -> ReaderT EntityAlias FromIr FieldSource)
-> [(FieldName, AnnFieldG 'MSSQL Void Expression)]
-> ReaderT EntityAlias FromIr [FieldSource]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse (Map (Either NativeQueryName TableName) EntityAlias
-> (FieldName, AnnFieldG 'MSSQL Void Expression)
-> ReaderT EntityAlias FromIr FieldSource
fromAnnFieldsG Map (Either NativeQueryName TableName) EntityAlias
forall a. Monoid a => a
mempty) [(FieldName, AnnFieldG 'MSSQL Void Expression)]
fields)
  let selectProjections :: [Projection]
selectProjections = (FieldSource -> Projection) -> [FieldSource] -> [Projection]
forall a b. (a -> b) -> [a] -> [b]
map FieldSource -> Projection
fieldSourceProjections [FieldSource]
fieldSources

  JoinAlias
joinJoinAlias <-
    do
      Text
fieldName <- FromIr Text -> ReaderT EntityAlias FromIr Text
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (RelName -> FromIr Text
fromRelName RelName
_aarRelationshipName)
      Text
alias <- FromIr Text -> ReaderT EntityAlias FromIr Text
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (NameTemplate -> FromIr Text
generateAlias (Text -> NameTemplate
ObjectRelationTemplate Text
fieldName))
      JoinAlias -> ReaderT EntityAlias FromIr JoinAlias
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        JoinAlias
          { $sel:joinAliasEntity:JoinAlias :: Text
joinAliasEntity = Text
alias,
            $sel:joinAliasField:JoinAlias :: Maybe Text
joinAliasField = Text -> Maybe Text
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Text
jsonFieldName
          }

  let selectFor :: For
selectFor =
        ForJson -> For
JsonFor ForJson {$sel:jsonCardinality:ForJson :: JsonCardinality
jsonCardinality = JsonCardinality
JsonSingleton, $sel:jsonRoot:ForJson :: Root
jsonRoot = Root
NoRoot}

  Expression
filterExpression <- (EntityAlias -> EntityAlias)
-> ReaderT EntityAlias FromIr Expression
-> ReaderT EntityAlias FromIr Expression
forall a.
(EntityAlias -> EntityAlias)
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr a
forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local (EntityAlias -> EntityAlias -> EntityAlias
forall a b. a -> b -> a
const EntityAlias
entityAlias) (GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGBoolExp GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
tableFilter)

  -- if the object select should be non-nullable we push an extra 'where'
  -- for the outer `select` that checks the value is not `null`
  let joinWhere :: Where
joinWhere = case Nullable
nullable of
        Nullable
IR.Nullable -> Where
forall a. Monoid a => a
mempty
        Nullable
IR.NotNullable ->
          [Expression] -> Where
Where
            [ Expression -> Expression
IsNotNullExpression
                ( Expression -> Expression
JsonQueryExpression
                    ( FieldName -> Expression
ColumnExpression
                        ( FieldName
                            { $sel:fieldName:FieldName :: Text
fieldName = Text
jsonFieldName,
                              $sel:fieldNameEntity:FieldName :: Text
fieldNameEntity = JoinAlias -> Text
joinAliasEntity JoinAlias
joinJoinAlias
                            }
                        )
                    )
                )
            ]

  case Either EntityAlias From
eitherAliasOrFrom of
    Right From
selectFrom -> do
      [Expression]
foreignKeyConditions <- From
-> HashMap ColumnName ColumnName
-> ReaderT EntityAlias FromIr [Expression]
fromMapping From
selectFrom HashMap ColumnName ColumnName
mapping
      Join -> ReaderT EntityAlias FromIr Join
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        Join
          { JoinAlias
$sel:joinJoinAlias:Join :: JoinAlias
joinJoinAlias :: JoinAlias
joinJoinAlias,
            Where
joinWhere :: Where
$sel:joinWhere:Join :: Where
joinWhere,
            $sel:joinSource:Join :: JoinSource
joinSource =
              Select -> JoinSource
JoinSelect
                Select
emptySelect
                  { $sel:selectOrderBy:Select :: Maybe (NonEmpty OrderBy)
selectOrderBy = Maybe (NonEmpty OrderBy)
forall a. Maybe a
Nothing,
                    $sel:selectTop:Select :: Top
selectTop = Top
NoTop,
                    [Projection]
$sel:selectProjections:Select :: [Projection]
selectProjections :: [Projection]
selectProjections,
                    $sel:selectFrom:Select :: Maybe From
selectFrom = From -> Maybe From
forall a. a -> Maybe a
Just From
selectFrom,
                    $sel:selectJoins:Select :: [Join]
selectJoins = (FieldSource -> Maybe Join) -> [FieldSource] -> [Join]
forall a b. (a -> Maybe b) -> [a] -> [b]
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe FieldSource -> Maybe Join
fieldSourceJoin [FieldSource]
fieldSources,
                    $sel:selectWhere:Select :: Where
selectWhere =
                      [Expression] -> Where
Where ([Expression]
foreignKeyConditions [Expression] -> [Expression] -> [Expression]
forall a. Semigroup a => a -> a -> a
<> [Expression
filterExpression]),
                    For
$sel:selectFor:Select :: For
selectFor :: For
selectFor,
                    $sel:selectOffset:Select :: Maybe Expression
selectOffset = Maybe Expression
forall a. Maybe a
Nothing
                  }
          }
    Left EntityAlias
_entityAlias ->
      Join -> ReaderT EntityAlias FromIr Join
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        Join
          { JoinAlias
$sel:joinJoinAlias:Join :: JoinAlias
joinJoinAlias :: JoinAlias
joinJoinAlias,
            Where
joinWhere :: Where
$sel:joinWhere:Join :: Where
joinWhere,
            $sel:joinSource:Join :: JoinSource
joinSource =
              Reselect -> JoinSource
JoinReselect
                Reselect
                  { $sel:reselectProjections:Reselect :: [Projection]
reselectProjections = [Projection]
selectProjections,
                    $sel:reselectFor:Reselect :: For
reselectFor = For
selectFor,
                    $sel:reselectWhere:Reselect :: Where
reselectWhere = [Expression] -> Where
Where [Expression
filterExpression]
                  }
          }
  where
    IR.AnnObjectSelectG
      { $sel:_aosFields:AnnObjectSelectG :: forall (b :: BackendType) r v.
AnnObjectSelectG b r v -> AnnFieldsG b r v
_aosFields = [(FieldName, AnnFieldG 'MSSQL Void Expression)]
fields :: IR.AnnFieldsG 'MSSQL Void Expression,
        $sel:_aosTarget:AnnObjectSelectG :: forall (b :: BackendType) r v.
AnnObjectSelectG b r v -> SelectFromG b v
_aosTarget = SelectFromG 'MSSQL Expression
target :: IR.SelectFromG 'MSSQL Expression,
        $sel:_aosTargetFilter:AnnObjectSelectG :: forall (b :: BackendType) r v.
AnnObjectSelectG b r v -> AnnBoolExp b v
_aosTargetFilter = GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
tableFilter :: IR.AnnBoolExp 'MSSQL Expression
      } = AnnObjectSelectG 'MSSQL Void Expression
annObjectSelectG
    IR.AnnRelationSelectG
      { RelName
_aarRelationshipName :: RelName
$sel:_aarRelationshipName:AnnRelationSelectG :: forall (b :: BackendType) a. AnnRelationSelectG b a -> RelName
_aarRelationshipName,
        $sel:_aarColumnMapping:AnnRelationSelectG :: forall (b :: BackendType) a.
AnnRelationSelectG b a -> HashMap (Column b) (Column b)
_aarColumnMapping = HashMap ColumnName ColumnName
mapping :: HashMap ColumnName ColumnName,
        $sel:_aarAnnSelect:AnnRelationSelectG :: forall (b :: BackendType) a. AnnRelationSelectG b a -> a
_aarAnnSelect = AnnObjectSelectG 'MSSQL Void Expression
annObjectSelectG :: IR.AnnObjectSelectG 'MSSQL Void Expression,
        $sel:_aarNullable:AnnRelationSelectG :: forall (b :: BackendType) a. AnnRelationSelectG b a -> Nullable
_aarNullable = Nullable
nullable
      } = ObjectRelationSelectG 'MSSQL Void Expression
annRelationSelectG

lookupTableFrom ::
  Map (Either NativeQueryName TableName) EntityAlias ->
  TableName ->
  FromIr (Either EntityAlias From)
lookupTableFrom :: Map (Either NativeQueryName TableName) EntityAlias
-> TableName -> FromIr (Either EntityAlias From)
lookupTableFrom Map (Either NativeQueryName TableName) EntityAlias
existingJoins TableName
tableFrom = do
  case Either NativeQueryName TableName
-> Map (Either NativeQueryName TableName) EntityAlias
-> Maybe EntityAlias
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup (TableName -> Either NativeQueryName TableName
forall a b. b -> Either a b
Right TableName
tableFrom) Map (Either NativeQueryName TableName) EntityAlias
existingJoins of
    Just EntityAlias
entityAlias -> Either EntityAlias From -> FromIr (Either EntityAlias From)
forall a. a -> FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (EntityAlias -> Either EntityAlias From
forall a b. a -> Either a b
Left EntityAlias
entityAlias)
    Maybe EntityAlias
Nothing -> (From -> Either EntityAlias From)
-> FromIr From -> FromIr (Either EntityAlias From)
forall a b. (a -> b) -> FromIr a -> FromIr b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap From -> Either EntityAlias From
forall a b. b -> Either a b
Right (TableName -> FromIr From
fromQualifiedTable TableName
tableFrom)

lookupNativeQueryFrom ::
  Map (Either NativeQueryName TableName) EntityAlias ->
  IR.NativeQuery 'MSSQL Expression ->
  FromIr (Either EntityAlias From)
lookupNativeQueryFrom :: Map (Either NativeQueryName TableName) EntityAlias
-> NativeQuery 'MSSQL Expression
-> FromIr (Either EntityAlias From)
lookupNativeQueryFrom Map (Either NativeQueryName TableName) EntityAlias
existingJoins NativeQuery 'MSSQL Expression
nativeQueryFrom = do
  case Either NativeQueryName TableName
-> Map (Either NativeQueryName TableName) EntityAlias
-> Maybe EntityAlias
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup (NativeQueryName -> Either NativeQueryName TableName
forall a b. a -> Either a b
Left (NativeQuery 'MSSQL Expression -> NativeQueryName
forall (b :: BackendType) field.
NativeQuery b field -> NativeQueryName
IR.nqRootFieldName NativeQuery 'MSSQL Expression
nativeQueryFrom)) Map (Either NativeQueryName TableName) EntityAlias
existingJoins of
    Just EntityAlias
entityAlias -> Either EntityAlias From -> FromIr (Either EntityAlias From)
forall a. a -> FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (EntityAlias -> Either EntityAlias From
forall a b. a -> Either a b
Left EntityAlias
entityAlias)
    Maybe EntityAlias
Nothing -> (From -> Either EntityAlias From)
-> FromIr From -> FromIr (Either EntityAlias From)
forall a b. (a -> b) -> FromIr a -> FromIr b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap From -> Either EntityAlias From
forall a b. b -> Either a b
Right (NativeQuery 'MSSQL Expression -> FromIr From
fromNativeQuery NativeQuery 'MSSQL Expression
nativeQueryFrom)

fromArraySelectG :: IR.ArraySelectG 'MSSQL Void Expression -> ReaderT EntityAlias FromIr Join
fromArraySelectG :: ArraySelectG 'MSSQL Void Expression
-> ReaderT EntityAlias FromIr Join
fromArraySelectG =
  \case
    IR.ASSimple ArrayRelationSelectG 'MSSQL Void Expression
arrayRelationSelectG ->
      ArrayRelationSelectG 'MSSQL Void Expression
-> ReaderT EntityAlias FromIr Join
fromArrayRelationSelectG ArrayRelationSelectG 'MSSQL Void Expression
arrayRelationSelectG
    IR.ASAggregate ArrayAggregateSelectG 'MSSQL Void Expression
arrayAggregateSelectG ->
      ArrayAggregateSelectG 'MSSQL Void Expression
-> ReaderT EntityAlias FromIr Join
fromArrayAggregateSelectG ArrayAggregateSelectG 'MSSQL Void Expression
arrayAggregateSelectG

fromArrayAggregateSelectG ::
  IR.AnnRelationSelectG 'MSSQL (IR.AnnAggregateSelectG 'MSSQL Void Expression) ->
  ReaderT EntityAlias FromIr Join
fromArrayAggregateSelectG :: ArrayAggregateSelectG 'MSSQL Void Expression
-> ReaderT EntityAlias FromIr Join
fromArrayAggregateSelectG ArrayAggregateSelectG 'MSSQL Void Expression
annRelationSelectG = do
  Text
fieldName <- FromIr Text -> ReaderT EntityAlias FromIr Text
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (RelName -> FromIr Text
fromRelName RelName
_aarRelationshipName)
  Select
joinSelect <- do
    EntityAlias
lhsEntityAlias <- ReaderT EntityAlias FromIr EntityAlias
forall r (m :: * -> *). MonadReader r m => m r
ask
    -- With this, the foreign key relations are injected automatically
    -- at the right place by fromSelectAggregate.
    FromIr Select -> ReaderT EntityAlias FromIr Select
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Maybe (EntityAlias, HashMap ColumnName ColumnName)
-> AnnAggregateSelectG 'MSSQL Void Expression -> FromIr Select
fromSelectAggregate ((EntityAlias, HashMap ColumnName ColumnName)
-> Maybe (EntityAlias, HashMap ColumnName ColumnName)
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (EntityAlias
lhsEntityAlias, HashMap ColumnName ColumnName
mapping)) AnnAggregateSelectG 'MSSQL Void Expression
annSelectG)
  Text
alias <- FromIr Text -> ReaderT EntityAlias FromIr Text
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (NameTemplate -> FromIr Text
generateAlias (Text -> NameTemplate
ArrayAggregateTemplate Text
fieldName))
  Join -> ReaderT EntityAlias FromIr Join
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    Join
      { $sel:joinJoinAlias:Join :: JoinAlias
joinJoinAlias =
          JoinAlias
            { $sel:joinAliasEntity:JoinAlias :: Text
joinAliasEntity = Text
alias,
              $sel:joinAliasField:JoinAlias :: Maybe Text
joinAliasField = Text -> Maybe Text
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Text
jsonFieldName
            },
        $sel:joinWhere:Join :: Where
joinWhere = Where
forall a. Monoid a => a
mempty,
        $sel:joinSource:Join :: JoinSource
joinSource = Select -> JoinSource
JoinSelect Select
joinSelect
      }
  where
    IR.AnnRelationSelectG
      { RelName
$sel:_aarRelationshipName:AnnRelationSelectG :: forall (b :: BackendType) a. AnnRelationSelectG b a -> RelName
_aarRelationshipName :: RelName
_aarRelationshipName,
        $sel:_aarColumnMapping:AnnRelationSelectG :: forall (b :: BackendType) a.
AnnRelationSelectG b a -> HashMap (Column b) (Column b)
_aarColumnMapping = HashMap ColumnName ColumnName
mapping :: HashMap ColumnName ColumnName,
        $sel:_aarAnnSelect:AnnRelationSelectG :: forall (b :: BackendType) a. AnnRelationSelectG b a -> a
_aarAnnSelect = AnnAggregateSelectG 'MSSQL Void Expression
annSelectG
      } = ArrayAggregateSelectG 'MSSQL Void Expression
annRelationSelectG

fromArrayRelationSelectG :: IR.ArrayRelationSelectG 'MSSQL Void Expression -> ReaderT EntityAlias FromIr Join
fromArrayRelationSelectG :: ArrayRelationSelectG 'MSSQL Void Expression
-> ReaderT EntityAlias FromIr Join
fromArrayRelationSelectG ArrayRelationSelectG 'MSSQL Void Expression
annRelationSelectG = do
  Text
fieldName <- FromIr Text -> ReaderT EntityAlias FromIr Text
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (RelName -> FromIr Text
fromRelName RelName
_aarRelationshipName)
  Select
sel <- FromIr Select -> ReaderT EntityAlias FromIr Select
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (AnnSimpleSelectG 'MSSQL Void Expression -> FromIr Select
fromSelectRows AnnSimpleSelectG 'MSSQL Void Expression
annSelectG)
  Select
joinSelect <-
    do
      [Expression]
foreignKeyConditions <- Select
-> HashMap ColumnName ColumnName
-> ReaderT EntityAlias FromIr [Expression]
selectFromMapping Select
sel HashMap ColumnName ColumnName
mapping
      Select -> ReaderT EntityAlias FromIr Select
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        Select
sel {$sel:selectWhere:Select :: Where
selectWhere = [Expression] -> Where
Where [Expression]
foreignKeyConditions Where -> Where -> Where
forall a. Semigroup a => a -> a -> a
<> Select -> Where
selectWhere Select
sel}
  Text
alias <- FromIr Text -> ReaderT EntityAlias FromIr Text
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (NameTemplate -> FromIr Text
generateAlias (Text -> NameTemplate
ArrayRelationTemplate Text
fieldName))
  Join -> ReaderT EntityAlias FromIr Join
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    Join
      { $sel:joinJoinAlias:Join :: JoinAlias
joinJoinAlias =
          JoinAlias
            { $sel:joinAliasEntity:JoinAlias :: Text
joinAliasEntity = Text
alias,
              $sel:joinAliasField:JoinAlias :: Maybe Text
joinAliasField = Text -> Maybe Text
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Text
jsonFieldName
            },
        $sel:joinWhere:Join :: Where
joinWhere = Where
forall a. Monoid a => a
mempty,
        $sel:joinSource:Join :: JoinSource
joinSource = Select -> JoinSource
JoinSelect Select
joinSelect
      }
  where
    IR.AnnRelationSelectG
      { RelName
$sel:_aarRelationshipName:AnnRelationSelectG :: forall (b :: BackendType) a. AnnRelationSelectG b a -> RelName
_aarRelationshipName :: RelName
_aarRelationshipName,
        $sel:_aarColumnMapping:AnnRelationSelectG :: forall (b :: BackendType) a.
AnnRelationSelectG b a -> HashMap (Column b) (Column b)
_aarColumnMapping = HashMap ColumnName ColumnName
mapping :: HashMap ColumnName ColumnName,
        $sel:_aarAnnSelect:AnnRelationSelectG :: forall (b :: BackendType) a. AnnRelationSelectG b a -> a
_aarAnnSelect = AnnSimpleSelectG 'MSSQL Void Expression
annSelectG
      } = ArrayRelationSelectG 'MSSQL Void Expression
annRelationSelectG

fromRelName :: IR.RelName -> FromIr Text
fromRelName :: RelName -> FromIr Text
fromRelName RelName
relName =
  Text -> FromIr Text
forall a. a -> FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (RelName -> Text
IR.relNameToTxt RelName
relName)

-- | The context given by the reader is of the previous/parent
-- "remote" table. The WHERE that we're generating goes in the child,
-- "local" query. The @From@ passed in as argument is the local table.
--
-- We should hope to see e.g. "post.category = category.id" for a
-- local table of post and a remote table of category.
--
-- The left/right columns in @HashMap ColumnName ColumnName@ corresponds
-- to the left/right of @select ... join ...@. Therefore left=remote,
-- right=local in this context.
fromMapping ::
  From ->
  HashMap ColumnName ColumnName ->
  ReaderT EntityAlias FromIr [Expression]
fromMapping :: From
-> HashMap ColumnName ColumnName
-> ReaderT EntityAlias FromIr [Expression]
fromMapping From
localFrom =
  ((ColumnName, ColumnName) -> ReaderT EntityAlias FromIr Expression)
-> [(ColumnName, ColumnName)]
-> ReaderT EntityAlias FromIr [Expression]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse
    ( \(ColumnName
remoteColumn, ColumnName
localColumn) -> do
        FieldName
localFieldName <- (EntityAlias -> EntityAlias)
-> ReaderT EntityAlias FromIr FieldName
-> ReaderT EntityAlias FromIr FieldName
forall a.
(EntityAlias -> EntityAlias)
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr a
forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local (EntityAlias -> EntityAlias -> EntityAlias
forall a b. a -> b -> a
const (From -> EntityAlias
fromAlias From
localFrom)) (ColumnName -> ReaderT EntityAlias FromIr FieldName
fromColumn ColumnName
localColumn)
        FieldName
remoteFieldName <- ColumnName -> ReaderT EntityAlias FromIr FieldName
fromColumn ColumnName
remoteColumn
        Expression -> ReaderT EntityAlias FromIr Expression
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
          ( Op -> Expression -> Expression -> Expression
OpExpression
              Op
TSQL.EQ'
              (FieldName -> Expression
ColumnExpression FieldName
localFieldName)
              (FieldName -> Expression
ColumnExpression FieldName
remoteFieldName)
          )
    )
    ([(ColumnName, ColumnName)]
 -> ReaderT EntityAlias FromIr [Expression])
-> (HashMap ColumnName ColumnName -> [(ColumnName, ColumnName)])
-> HashMap ColumnName ColumnName
-> ReaderT EntityAlias FromIr [Expression]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap ColumnName ColumnName -> [(ColumnName, ColumnName)]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList

selectFromMapping ::
  Select ->
  HashMap ColumnName ColumnName ->
  ReaderT EntityAlias FromIr [Expression]
selectFromMapping :: Select
-> HashMap ColumnName ColumnName
-> ReaderT EntityAlias FromIr [Expression]
selectFromMapping Select {$sel:selectFrom:Select :: Select -> Maybe From
selectFrom = Maybe From
Nothing} = ReaderT EntityAlias FromIr [Expression]
-> HashMap ColumnName ColumnName
-> ReaderT EntityAlias FromIr [Expression]
forall a b. a -> b -> a
const ([Expression] -> ReaderT EntityAlias FromIr [Expression]
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [])
selectFromMapping Select {$sel:selectFrom:Select :: Select -> Maybe From
selectFrom = Just From
from} = From
-> HashMap ColumnName ColumnName
-> ReaderT EntityAlias FromIr [Expression]
fromMapping From
from

-- | A version of @JSON_QUERY(..)@ that returns a proper json literal, rather
-- than SQL null, which does not compose properly with @FOR JSON@ clauses.
safeJsonQueryExpression :: JsonCardinality -> Expression -> Expression
safeJsonQueryExpression :: JsonCardinality -> Expression -> Expression
safeJsonQueryExpression JsonCardinality
expectedType Expression
jsonQuery =
  FunctionApplicationExpression -> Expression
FunctionApplicationExpression (Expression -> Expression -> FunctionApplicationExpression
FunExpISNULL (Expression -> Expression
JsonQueryExpression Expression
jsonQuery) Expression
jsonTypeExpression)
  where
    jsonTypeExpression :: Expression
jsonTypeExpression = case JsonCardinality
expectedType of
      JsonCardinality
JsonSingleton -> Expression
nullExpression
      JsonCardinality
JsonArray -> Expression
emptyArrayExpression

--------------------------------------------------------------------------------
-- Constants

data UnfurledJoin = UnfurledJoin
  { UnfurledJoin -> Join
unfurledJoin :: Join,
    -- | Recorded if we joined onto an object relation.
    UnfurledJoin
-> Maybe (Either NativeQueryName TableName, EntityAlias)
unfurledObjectTableAlias :: Maybe (Either NativeQueryName TableName, EntityAlias)
  }
  deriving (Int -> UnfurledJoin -> ShowS
[UnfurledJoin] -> ShowS
UnfurledJoin -> [Char]
(Int -> UnfurledJoin -> ShowS)
-> (UnfurledJoin -> [Char])
-> ([UnfurledJoin] -> ShowS)
-> Show UnfurledJoin
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> UnfurledJoin -> ShowS
showsPrec :: Int -> UnfurledJoin -> ShowS
$cshow :: UnfurledJoin -> [Char]
show :: UnfurledJoin -> [Char]
$cshowList :: [UnfurledJoin] -> ShowS
showList :: [UnfurledJoin] -> ShowS
Show)

fromAnnotatedOrderByItemG ::
  IR.AnnotatedOrderByItemG 'MSSQL Expression ->
  WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) OrderBy
fromAnnotatedOrderByItemG :: AnnotatedOrderByItemG 'MSSQL Expression
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) OrderBy
fromAnnotatedOrderByItemG IR.OrderByItemG {Maybe (BasicOrderType 'MSSQL)
obiType :: Maybe (BasicOrderType 'MSSQL)
obiType :: forall (b :: BackendType) a.
OrderByItemG b a -> Maybe (BasicOrderType b)
obiType, obiColumn :: forall (b :: BackendType) a. OrderByItemG b a -> a
obiColumn = AnnotatedOrderByElement 'MSSQL Expression
obiColumn, Maybe (NullsOrderType 'MSSQL)
obiNulls :: Maybe (NullsOrderType 'MSSQL)
obiNulls :: forall (b :: BackendType) a.
OrderByItemG b a -> Maybe (NullsOrderType b)
obiNulls} = do
  (FieldName
orderByFieldName, Maybe ScalarType
orderByType) <- AnnotatedOrderByElement 'MSSQL Expression
-> WriterT
     (Seq UnfurledJoin)
     (ReaderT EntityAlias FromIr)
     (FieldName, Maybe ScalarType)
unfurlAnnotatedOrderByElement AnnotatedOrderByElement 'MSSQL Expression
obiColumn
  let orderByNullsOrder :: NullsOrder
orderByNullsOrder = NullsOrder -> Maybe NullsOrder -> NullsOrder
forall a. a -> Maybe a -> a
fromMaybe NullsOrder
NullsAnyOrder Maybe (NullsOrderType 'MSSQL)
Maybe NullsOrder
obiNulls
      orderByOrder :: Order
orderByOrder = Order -> Maybe Order -> Order
forall a. a -> Maybe a -> a
fromMaybe Order
AscOrder Maybe (BasicOrderType 'MSSQL)
Maybe Order
obiType
  OrderBy
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) OrderBy
forall a.
a -> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure OrderBy {Maybe ScalarType
FieldName
NullsOrder
Order
orderByFieldName :: FieldName
orderByType :: Maybe ScalarType
orderByNullsOrder :: NullsOrder
orderByOrder :: Order
$sel:orderByFieldName:OrderBy :: FieldName
$sel:orderByOrder:OrderBy :: Order
$sel:orderByNullsOrder:OrderBy :: NullsOrder
$sel:orderByType:OrderBy :: Maybe ScalarType
..}

-- | Unfurl the nested set of object relations (tell'd in the writer)
-- that are terminated by field name (IR.AOCColumn and
-- IR.AOCArrayAggregation).
unfurlAnnotatedOrderByElement ::
  IR.AnnotatedOrderByElement 'MSSQL Expression ->
  WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) (FieldName, Maybe TSQL.ScalarType)
unfurlAnnotatedOrderByElement :: AnnotatedOrderByElement 'MSSQL Expression
-> WriterT
     (Seq UnfurledJoin)
     (ReaderT EntityAlias FromIr)
     (FieldName, Maybe ScalarType)
unfurlAnnotatedOrderByElement =
  \case
    -- TODO(redactionExp): Use the redaction expression
    IR.AOCColumn ColumnInfo 'MSSQL
columnInfo AnnRedactionExp 'MSSQL Expression
_redactionExp -> do
      FieldName
fieldName <- ReaderT EntityAlias FromIr FieldName
-> WriterT
     (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) FieldName
forall (m :: * -> *) a.
Monad m =>
m a -> WriterT (Seq UnfurledJoin) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (ColumnInfo 'MSSQL -> ReaderT EntityAlias FromIr FieldName
fromColumnInfo ColumnInfo 'MSSQL
columnInfo)
      (FieldName, Maybe ScalarType)
-> WriterT
     (Seq UnfurledJoin)
     (ReaderT EntityAlias FromIr)
     (FieldName, Maybe ScalarType)
forall a.
a -> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        ( FieldName
fieldName,
          case ColumnInfo 'MSSQL -> ColumnType 'MSSQL
forall (b :: BackendType). ColumnInfo b -> ColumnType b
IR.ciType ColumnInfo 'MSSQL
columnInfo of
            IR.ColumnScalar ScalarType 'MSSQL
t -> ScalarType -> Maybe ScalarType
forall a. a -> Maybe a
Just ScalarType 'MSSQL
ScalarType
t
            -- Above: It is of interest to us whether the type is
            -- text/ntext/image. See ToQuery for more explanation.
            ColumnType 'MSSQL
_ -> Maybe ScalarType
forall a. Maybe a
Nothing
        )
    IR.AOCObjectRelation IR.RelInfo {riMapping :: forall (b :: BackendType).
RelInfo b -> HashMap (Column b) (Column b)
riMapping = HashMap (Column 'MSSQL) (Column 'MSSQL)
mapping, riTarget :: forall (b :: BackendType). RelInfo b -> RelTarget b
riTarget = IR.RelTargetNativeQuery NativeQueryName
nativeQueryName} GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
annBoolExp AnnotatedOrderByElement 'MSSQL Expression
annOrderByElementG -> do
      let name :: Text
name = Name -> Text
forall a. ToTxt a => a -> Text
T.toTxt (NativeQueryName -> Name
getNativeQueryName NativeQueryName
nativeQueryName)
          selectFrom :: From
selectFrom = Text -> From
TSQL.FromIdentifier Text
name
      Text
joinAliasEntity <-
        ReaderT EntityAlias FromIr Text
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) Text
forall (m :: * -> *) a.
Monad m =>
m a -> WriterT (Seq UnfurledJoin) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (FromIr Text -> ReaderT EntityAlias FromIr Text
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (NameTemplate -> FromIr Text
generateAlias (Text -> NameTemplate
ForOrderAlias Text
name)))
      HashMap ColumnName ColumnName
-> GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> AnnotatedOrderByElement 'MSSQL Expression
-> Text
-> From
-> Either NativeQueryName TableName
-> WriterT
     (Seq UnfurledJoin)
     (ReaderT EntityAlias FromIr)
     (FieldName, Maybe ScalarType)
genObjectRelation HashMap (Column 'MSSQL) (Column 'MSSQL)
HashMap ColumnName ColumnName
mapping GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
annBoolExp AnnotatedOrderByElement 'MSSQL Expression
annOrderByElementG Text
joinAliasEntity From
selectFrom (NativeQueryName -> Either NativeQueryName TableName
forall a b. a -> Either a b
Left NativeQueryName
nativeQueryName)
    IR.AOCObjectRelation IR.RelInfo {riMapping :: forall (b :: BackendType).
RelInfo b -> HashMap (Column b) (Column b)
riMapping = HashMap (Column 'MSSQL) (Column 'MSSQL)
mapping, riTarget :: forall (b :: BackendType). RelInfo b -> RelTarget b
riTarget = IR.RelTargetTable TableName 'MSSQL
table} GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
annBoolExp AnnotatedOrderByElement 'MSSQL Expression
annOrderByElementG -> do
      From
selectFrom <- ReaderT EntityAlias FromIr From
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) From
forall (m :: * -> *) a.
Monad m =>
m a -> WriterT (Seq UnfurledJoin) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (FromIr From -> ReaderT EntityAlias FromIr From
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TableName -> FromIr From
fromQualifiedTable TableName 'MSSQL
TableName
table))
      Text
joinAliasEntity <-
        ReaderT EntityAlias FromIr Text
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) Text
forall (m :: * -> *) a.
Monad m =>
m a -> WriterT (Seq UnfurledJoin) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (FromIr Text -> ReaderT EntityAlias FromIr Text
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (NameTemplate -> FromIr Text
generateAlias (Text -> NameTemplate
ForOrderAlias (TableName -> Text
tableNameText TableName 'MSSQL
TableName
table))))
      HashMap ColumnName ColumnName
-> GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> AnnotatedOrderByElement 'MSSQL Expression
-> Text
-> From
-> Either NativeQueryName TableName
-> WriterT
     (Seq UnfurledJoin)
     (ReaderT EntityAlias FromIr)
     (FieldName, Maybe ScalarType)
genObjectRelation HashMap (Column 'MSSQL) (Column 'MSSQL)
HashMap ColumnName ColumnName
mapping GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
annBoolExp AnnotatedOrderByElement 'MSSQL Expression
annOrderByElementG Text
joinAliasEntity From
selectFrom (TableName -> Either NativeQueryName TableName
forall a b. b -> Either a b
Right TableName 'MSSQL
TableName
table)
    IR.AOCArrayAggregation IR.RelInfo {riTarget :: forall (b :: BackendType). RelInfo b -> RelTarget b
riTarget = IR.RelTargetNativeQuery NativeQueryName
_} GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
_annBoolExp AnnotatedAggregateOrderBy 'MSSQL Expression
_annAggregateOrderBy ->
      [Char]
-> WriterT
     (Seq UnfurledJoin)
     (ReaderT EntityAlias FromIr)
     (FieldName, Maybe ScalarType)
forall a. HasCallStack => [Char] -> a
error [Char]
"unfurlAnnotatedOrderByElement RelTargetNativeQuery"
    IR.AOCArrayAggregation IR.RelInfo {riMapping :: forall (b :: BackendType).
RelInfo b -> HashMap (Column b) (Column b)
riMapping = HashMap (Column 'MSSQL) (Column 'MSSQL)
mapping, riTarget :: forall (b :: BackendType). RelInfo b -> RelTarget b
riTarget = IR.RelTargetTable TableName 'MSSQL
tableName} GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
annBoolExp AnnotatedAggregateOrderBy 'MSSQL Expression
annAggregateOrderBy -> do
      From
selectFrom <- ReaderT EntityAlias FromIr From
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) From
forall (m :: * -> *) a.
Monad m =>
m a -> WriterT (Seq UnfurledJoin) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (FromIr From -> ReaderT EntityAlias FromIr From
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TableName -> FromIr From
fromQualifiedTable TableName 'MSSQL
TableName
tableName))
      let alias :: Text
alias = Text
aggFieldName
      Text
joinAliasEntity <-
        ReaderT EntityAlias FromIr Text
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) Text
forall (m :: * -> *) a.
Monad m =>
m a -> WriterT (Seq UnfurledJoin) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (FromIr Text -> ReaderT EntityAlias FromIr Text
forall (m :: * -> *) a. Monad m => m a -> ReaderT EntityAlias m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (NameTemplate -> FromIr Text
generateAlias (Text -> NameTemplate
ForOrderAlias (TableName -> Text
tableNameText TableName 'MSSQL
TableName
tableName))))
      [Expression]
foreignKeyConditions <- ReaderT EntityAlias FromIr [Expression]
-> WriterT
     (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) [Expression]
forall (m :: * -> *) a.
Monad m =>
m a -> WriterT (Seq UnfurledJoin) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (From
-> HashMap ColumnName ColumnName
-> ReaderT EntityAlias FromIr [Expression]
fromMapping From
selectFrom HashMap (Column 'MSSQL) (Column 'MSSQL)
HashMap ColumnName ColumnName
mapping)
      Expression
whereExpression <-
        ReaderT EntityAlias FromIr Expression
-> WriterT
     (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) Expression
forall (m :: * -> *) a.
Monad m =>
m a -> WriterT (Seq UnfurledJoin) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift ((EntityAlias -> EntityAlias)
-> ReaderT EntityAlias FromIr Expression
-> ReaderT EntityAlias FromIr Expression
forall a.
(EntityAlias -> EntityAlias)
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr a
forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local (EntityAlias -> EntityAlias -> EntityAlias
forall a b. a -> b -> a
const (From -> EntityAlias
fromAlias From
selectFrom)) (GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGBoolExp GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
annBoolExp))
      Aggregate
aggregate <-
        ReaderT EntityAlias FromIr Aggregate
-> WriterT
     (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) Aggregate
forall (m :: * -> *) a.
Monad m =>
m a -> WriterT (Seq UnfurledJoin) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift
          ( (EntityAlias -> EntityAlias)
-> ReaderT EntityAlias FromIr Aggregate
-> ReaderT EntityAlias FromIr Aggregate
forall a.
(EntityAlias -> EntityAlias)
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr a
forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local
              (EntityAlias -> EntityAlias -> EntityAlias
forall a b. a -> b -> a
const (From -> EntityAlias
fromAlias From
selectFrom))
              ( case AnnotatedAggregateOrderBy 'MSSQL Expression
annAggregateOrderBy of
                  AnnotatedAggregateOrderBy 'MSSQL Expression
IR.AAOCount -> Aggregate -> ReaderT EntityAlias FromIr Aggregate
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Countable FieldName -> Aggregate
CountAggregate Countable FieldName
forall name. Countable name
StarCountable)
                  -- TODO(redactionExp): Use the redaction expression
                  IR.AAOOp (IR.AggregateOrderByColumn Text
text ColumnType 'MSSQL
_resultType ColumnInfo 'MSSQL
columnInfo AnnRedactionExp 'MSSQL Expression
_redactionExp) -> do
                    FieldName
fieldName <- ColumnInfo 'MSSQL -> ReaderT EntityAlias FromIr FieldName
fromColumnInfo ColumnInfo 'MSSQL
columnInfo
                    Aggregate -> ReaderT EntityAlias FromIr Aggregate
forall a. a -> ReaderT EntityAlias FromIr a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text -> [Expression] -> Aggregate
OpAggregate Text
text (Expression -> [Expression]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FieldName -> Expression
ColumnExpression FieldName
fieldName)))
              )
          )
      Seq UnfurledJoin
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell
        ( UnfurledJoin -> Seq UnfurledJoin
forall a. a -> Seq a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
            ( UnfurledJoin
                { unfurledJoin :: Join
unfurledJoin =
                    Join
                      { $sel:joinSource:Join :: JoinSource
joinSource =
                          Select -> JoinSource
JoinSelect
                            Select
emptySelect
                              { $sel:selectTop:Select :: Top
selectTop = Top
NoTop,
                                $sel:selectProjections:Select :: [Projection]
selectProjections =
                                  [ Aliased Aggregate -> Projection
AggregateProjection
                                      Aliased
                                        { $sel:aliasedThing:Aliased :: Aggregate
aliasedThing = Aggregate
aggregate,
                                          $sel:aliasedAlias:Aliased :: Text
aliasedAlias = Text
alias
                                        }
                                  ],
                                $sel:selectFrom:Select :: Maybe From
selectFrom = From -> Maybe From
forall a. a -> Maybe a
Just From
selectFrom,
                                $sel:selectJoins:Select :: [Join]
selectJoins = [],
                                $sel:selectWhere:Select :: Where
selectWhere =
                                  [Expression] -> Where
Where
                                    ([Expression]
foreignKeyConditions [Expression] -> [Expression] -> [Expression]
forall a. Semigroup a => a -> a -> a
<> [Expression
whereExpression]),
                                $sel:selectFor:Select :: For
selectFor = For
NoFor,
                                $sel:selectOrderBy:Select :: Maybe (NonEmpty OrderBy)
selectOrderBy = Maybe (NonEmpty OrderBy)
forall a. Maybe a
Nothing,
                                $sel:selectOffset:Select :: Maybe Expression
selectOffset = Maybe Expression
forall a. Maybe a
Nothing
                              },
                        $sel:joinWhere:Join :: Where
joinWhere = Where
forall a. Monoid a => a
mempty,
                        $sel:joinJoinAlias:Join :: JoinAlias
joinJoinAlias =
                          JoinAlias {Text
$sel:joinAliasEntity:JoinAlias :: Text
joinAliasEntity :: Text
joinAliasEntity, $sel:joinAliasField:JoinAlias :: Maybe Text
joinAliasField = Maybe Text
forall a. Maybe a
Nothing}
                      },
                  unfurledObjectTableAlias :: Maybe (Either NativeQueryName TableName, EntityAlias)
unfurledObjectTableAlias = Maybe (Either NativeQueryName TableName, EntityAlias)
forall a. Maybe a
Nothing
                }
            )
        )
      (FieldName, Maybe ScalarType)
-> WriterT
     (Seq UnfurledJoin)
     (ReaderT EntityAlias FromIr)
     (FieldName, Maybe ScalarType)
forall a.
a -> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        ( FieldName {$sel:fieldNameEntity:FieldName :: Text
fieldNameEntity = Text
joinAliasEntity, $sel:fieldName:FieldName :: Text
fieldName = Text
alias},
          Maybe ScalarType
forall a. Maybe a
Nothing
        )
  where
    genObjectRelation :: HashMap ColumnName ColumnName
-> GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> AnnotatedOrderByElement 'MSSQL Expression
-> Text
-> From
-> Either NativeQueryName TableName
-> WriterT
     (Seq UnfurledJoin)
     (ReaderT EntityAlias FromIr)
     (FieldName, Maybe ScalarType)
genObjectRelation HashMap ColumnName ColumnName
mapping GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
annBoolExp AnnotatedOrderByElement 'MSSQL Expression
annOrderByElementG Text
joinAliasEntity From
selectFrom Either NativeQueryName TableName
table = do
      [Expression]
foreignKeyConditions <- ReaderT EntityAlias FromIr [Expression]
-> WriterT
     (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) [Expression]
forall (m :: * -> *) a.
Monad m =>
m a -> WriterT (Seq UnfurledJoin) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (From
-> HashMap ColumnName ColumnName
-> ReaderT EntityAlias FromIr [Expression]
fromMapping From
selectFrom HashMap ColumnName ColumnName
mapping)
      -- TODO: Because these object relations are re-used by regular
      -- object mapping queries, this WHERE may be unnecessarily
      -- restrictive. But I actually don't know from where such an
      -- expression arises in the source GraphQL syntax.
      --
      -- Worst case scenario, we could put the WHERE in the key of the
      -- Map in 'argsExistingJoins'. That would guarantee only equal
      -- selects are re-used.
      Expression
whereExpression <-
        ReaderT EntityAlias FromIr Expression
-> WriterT
     (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) Expression
forall (m :: * -> *) a.
Monad m =>
m a -> WriterT (Seq UnfurledJoin) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift ((EntityAlias -> EntityAlias)
-> ReaderT EntityAlias FromIr Expression
-> ReaderT EntityAlias FromIr Expression
forall a.
(EntityAlias -> EntityAlias)
-> ReaderT EntityAlias FromIr a -> ReaderT EntityAlias FromIr a
forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local (EntityAlias -> EntityAlias -> EntityAlias
forall a b. a -> b -> a
const (From -> EntityAlias
fromAlias From
selectFrom)) (GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
-> ReaderT EntityAlias FromIr Expression
fromGBoolExp GBoolExp 'MSSQL (AnnBoolExpFld 'MSSQL Expression)
annBoolExp))
      Seq UnfurledJoin
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell
        ( UnfurledJoin -> Seq UnfurledJoin
forall a. a -> Seq a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
            UnfurledJoin
              { unfurledJoin :: Join
unfurledJoin =
                  Join
                    { $sel:joinSource:Join :: JoinSource
joinSource =
                        Select -> JoinSource
JoinSelect
                          Select
emptySelect
                            { $sel:selectTop:Select :: Top
selectTop = Top
NoTop,
                              $sel:selectProjections:Select :: [Projection]
selectProjections = [Projection
StarProjection],
                              $sel:selectFrom:Select :: Maybe From
selectFrom = From -> Maybe From
forall a. a -> Maybe a
Just From
selectFrom,
                              $sel:selectJoins:Select :: [Join]
selectJoins = [],
                              $sel:selectWhere:Select :: Where
selectWhere =
                                [Expression] -> Where
Where ([Expression]
foreignKeyConditions [Expression] -> [Expression] -> [Expression]
forall a. Semigroup a => a -> a -> a
<> [Expression
whereExpression]),
                              $sel:selectFor:Select :: For
selectFor = For
NoFor,
                              $sel:selectOrderBy:Select :: Maybe (NonEmpty OrderBy)
selectOrderBy = Maybe (NonEmpty OrderBy)
forall a. Maybe a
Nothing,
                              $sel:selectOffset:Select :: Maybe Expression
selectOffset = Maybe Expression
forall a. Maybe a
Nothing
                            },
                      $sel:joinWhere:Join :: Where
joinWhere = Where
forall a. Monoid a => a
mempty,
                      $sel:joinJoinAlias:Join :: JoinAlias
joinJoinAlias =
                        JoinAlias {Text
$sel:joinAliasEntity:JoinAlias :: Text
joinAliasEntity :: Text
joinAliasEntity, $sel:joinAliasField:JoinAlias :: Maybe Text
joinAliasField = Maybe Text
forall a. Maybe a
Nothing}
                    },
                unfurledObjectTableAlias :: Maybe (Either NativeQueryName TableName, EntityAlias)
unfurledObjectTableAlias = (Either NativeQueryName TableName, EntityAlias)
-> Maybe (Either NativeQueryName TableName, EntityAlias)
forall a. a -> Maybe a
Just (Either NativeQueryName TableName
table, Text -> EntityAlias
EntityAlias Text
joinAliasEntity)
              }
        )
      (EntityAlias -> EntityAlias)
-> WriterT
     (Seq UnfurledJoin)
     (ReaderT EntityAlias FromIr)
     (FieldName, Maybe ScalarType)
-> WriterT
     (Seq UnfurledJoin)
     (ReaderT EntityAlias FromIr)
     (FieldName, Maybe ScalarType)
forall a.
(EntityAlias -> EntityAlias)
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) a
-> WriterT (Seq UnfurledJoin) (ReaderT EntityAlias FromIr) a
forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local
        (EntityAlias -> EntityAlias -> EntityAlias
forall a b. a -> b -> a
const (Text -> EntityAlias
EntityAlias Text
joinAliasEntity))
        (AnnotatedOrderByElement 'MSSQL Expression
-> WriterT
     (Seq UnfurledJoin)
     (ReaderT EntityAlias FromIr)
     (FieldName, Maybe ScalarType)
unfurlAnnotatedOrderByElement AnnotatedOrderByElement 'MSSQL Expression
annOrderByElementG)

tableNameText :: TableName -> Text
tableNameText :: TableName -> Text
tableNameText (TableName {Text
$sel:tableName:TableName :: TableName -> Text
tableName :: Text
tableName}) = Text
tableName

fromColumnInfo :: IR.ColumnInfo 'MSSQL -> ReaderT EntityAlias FromIr FieldName
fromColumnInfo :: ColumnInfo 'MSSQL -> ReaderT EntityAlias FromIr FieldName
fromColumnInfo IR.ColumnInfo {ciColumn :: forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn = Column 'MSSQL
column} =
  ColumnName -> EntityAlias -> FieldName
columnNameToFieldName Column 'MSSQL
ColumnName
column (EntityAlias -> FieldName)
-> ReaderT EntityAlias FromIr EntityAlias
-> ReaderT EntityAlias FromIr FieldName
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReaderT EntityAlias FromIr EntityAlias
forall r (m :: * -> *). MonadReader r m => m r
ask