Remove circular dependency in schema building code

### Description

The main goal of this PR is, as stated, to remove the circular dependency in the schema building code. This cycle arises from the existence of remote relationships: when we build the schema for a source A, a remote relationship might force us to jump to the schema of a source B, or some remote schema. As a result, we end up having to do a dispatch from a "leaf" of the schema, similar to the one done at the root. In turn, this forces us to carry along in the schema a lot of information required for that dispatch, AND it forces us to import the instances in scope, creating an import loop.

As discussed in #4489, this PR implements the "dependency injection" solution: we pass to the schema a function to call to do the dispatch, and to get a generated field for a remote relationship. That way, this function can be chosen at the root level, and the leaves need not be aware of the overall context.

This PR grew a bit bigger than that, however; in an attempt to try and remove the `SourceCache` from the schema altogether, it changed a lot of functions across the schema building code, to thread along the `SourceInfo b` of the source being built. This avoids having to do cache lookups within a given source. A few cases remain, such as relay, that we might try to tackle in a subsequent PR.

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/4557
GitOrigin-RevId: 9388e48372877520a72a9fd1677005df9f7b2d72
This commit is contained in:
Antoine Leblanc 2022-05-27 18:21:22 +01:00 committed by hasura-bot
parent cbe0479406
commit 498442b1d3
26 changed files with 651 additions and 590 deletions

View File

@ -33,6 +33,7 @@ import Hasura.RQL.Types.Common
import Hasura.RQL.Types.ComputedField
import Hasura.RQL.Types.Function
import Hasura.RQL.Types.SchemaCache hiding (askTableInfo)
import Hasura.RQL.Types.Source (SourceInfo)
import Hasura.RQL.Types.SourceCustomization (NamingCase)
import Hasura.RQL.Types.Table
import Hasura.SQL.Backend
@ -76,7 +77,7 @@ instance BackendSchema 'BigQuery where
bqBuildTableRelayQueryFields ::
MonadBuildSchema 'BigQuery r m n =>
SourceName ->
SourceInfo 'BigQuery ->
TableName 'BigQuery ->
TableInfo 'BigQuery ->
C.GQLNameIdentifier ->
@ -88,7 +89,7 @@ bqBuildTableRelayQueryFields _sourceName _tableName _tableInfo _gqlName _pkeyCol
bqBuildTableInsertMutationFields ::
MonadBuildSchema 'BigQuery r m n =>
Scenario ->
SourceName ->
SourceInfo 'BigQuery ->
TableName 'BigQuery ->
TableInfo 'BigQuery ->
C.GQLNameIdentifier ->
@ -98,7 +99,7 @@ bqBuildTableInsertMutationFields _scenario _sourceName _tableName _tableInfo _gq
bqBuildTableUpdateMutationFields ::
MonadBuildSchema 'BigQuery r m n =>
SourceName ->
SourceInfo 'BigQuery ->
TableName 'BigQuery ->
TableInfo 'BigQuery ->
C.GQLNameIdentifier ->
@ -108,7 +109,7 @@ bqBuildTableUpdateMutationFields _sourceName _tableName _tableInfo _gqlName =
bqBuildTableDeleteMutationFields ::
MonadBuildSchema 'BigQuery r m n =>
SourceName ->
SourceInfo 'BigQuery ->
TableName 'BigQuery ->
TableInfo 'BigQuery ->
C.GQLNameIdentifier ->
@ -118,7 +119,7 @@ bqBuildTableDeleteMutationFields _sourceName _tableName _tableInfo _gqlName =
bqBuildFunctionQueryFields ::
MonadBuildSchema 'BigQuery r m n =>
SourceName ->
SourceInfo 'BigQuery ->
FunctionName 'BigQuery ->
FunctionInfo 'BigQuery ->
TableName 'BigQuery ->
@ -128,7 +129,7 @@ bqBuildFunctionQueryFields _ _ _ _ =
bqBuildFunctionRelayQueryFields ::
MonadBuildSchema 'BigQuery r m n =>
SourceName ->
SourceInfo 'BigQuery ->
FunctionName 'BigQuery ->
FunctionInfo 'BigQuery ->
TableName 'BigQuery ->
@ -139,7 +140,7 @@ bqBuildFunctionRelayQueryFields _sourceName _functionName _functionInfo _tableNa
bqBuildFunctionMutationFields ::
MonadBuildSchema 'BigQuery r m n =>
SourceName ->
SourceInfo 'BigQuery ->
FunctionName 'BigQuery ->
FunctionInfo 'BigQuery ->
TableName 'BigQuery ->
@ -248,11 +249,11 @@ bqOrderByOperators _tCase =
bqComparisonExps ::
forall m n r.
(BackendSchema 'BigQuery, MonadSchema n m, MonadError QErr m, MonadReader r m, Has QueryContext r, Has MkTypename r, Has NamingCase r) =>
(MonadBuildSchema 'BigQuery r m n) =>
ColumnType 'BigQuery ->
m (Parser 'Input n [ComparisonExp 'BigQuery])
bqComparisonExps = P.memoize 'comparisonExps $ \columnType -> do
collapseIfNull <- asks $ qcDangerousBooleanCollapse . getter
collapseIfNull <- retrieve soDangerousBooleanCollapse
dWithinGeogOpParser <- geographyWithinDistanceInput
tCase <- asks getter
-- see Note [Columns in comparison expression are never nullable]
@ -395,13 +396,13 @@ geographyWithinDistanceInput = do
bqComputedField ::
forall r m n.
MonadBuildSchema 'BigQuery r m n =>
SourceName ->
SourceInfo 'BigQuery ->
ComputedFieldInfo 'BigQuery ->
TableName 'BigQuery ->
TableInfo 'BigQuery ->
m (Maybe (FieldParser n (AnnotatedField 'BigQuery)))
bqComputedField sourceName ComputedFieldInfo {..} tableName _tableInfo = runMaybeT do
stringifyNum <- asks $ qcStringifyNum . getter
stringifyNum <- retrieve soStringifyNum
fieldName <- lift $ textToName $ computedFieldNameToText _cfiName
functionArgsParser <- lift $ computedFieldFunctionArgs _cfiFunction
case _cfiReturnType of

View File

@ -25,7 +25,7 @@ import Hasura.Prelude
import Hasura.RQL.IR.Select (SelectArgsG (..))
import Hasura.RQL.Types.Backend qualified as RQL
import Hasura.RQL.Types.Column qualified as RQL
import Hasura.RQL.Types.Common qualified as RQL
import Hasura.RQL.Types.Source qualified as RQL
import Hasura.RQL.Types.SourceCustomization (NamingCase)
import Hasura.RQL.Types.Table qualified as RQL
import Hasura.SQL.Backend (BackendType (..))
@ -74,7 +74,7 @@ instance BackendSchema 'DataConnector where
experimentalBuildTableRelayQueryFields ::
MonadBuildSchema 'DataConnector r m n =>
RQL.SourceName ->
RQL.SourceInfo 'DataConnector ->
RQL.TableName 'DataConnector ->
RQL.TableInfo 'DataConnector ->
GQLNameIdentifier ->
@ -124,14 +124,14 @@ comparisonExps' ::
MonadSchema n m,
MonadError QErr m,
MonadReader r m,
Has GS.C.QueryContext r,
Has GS.C.SchemaOptions r,
Has NamingCase r
) =>
RQL.ColumnType 'DataConnector ->
m (P.Parser 'P.Input n [ComparisonExp 'DataConnector])
comparisonExps' = P.memoize 'comparisonExps' $ \columnType -> do
tCase <- asks getter
collapseIfNull <- asks $ GS.C.qcDangerousBooleanCollapse . getter
collapseIfNull <- GS.C.retrieve GS.C.soDangerousBooleanCollapse
typedParser <- columnParser' columnType (GQL.Nullability False)
nullableTextParser <- columnParser' (RQL.ColumnScalar IR.S.T.String) (GQL.Nullability True)
textParser <- columnParser' (RQL.ColumnScalar IR.S.T.String) (GQL.Nullability False)
@ -170,7 +170,7 @@ comparisonExps' = P.memoize 'comparisonExps' $ \columnType -> do
tableArgs' ::
forall r m n.
MonadBuildSchema 'DataConnector r m n =>
RQL.SourceName ->
RQL.SourceInfo 'DataConnector ->
RQL.TableInfo 'DataConnector ->
m (P.InputFieldsParser n (SelectArgsG 'DataConnector (P.UnpreparedValue 'DataConnector)))
tableArgs' sourceName tableInfo = do

View File

@ -40,6 +40,7 @@ import Hasura.RQL.Types.ComputedField
import Hasura.RQL.Types.Function
import Hasura.RQL.Types.Relationships.Local
import Hasura.RQL.Types.SchemaCache
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization (NamingCase)
import Hasura.RQL.Types.Table
import Hasura.SQL.Backend
@ -87,7 +88,7 @@ instance BackendSchema 'MSSQL where
msBuildTableRelayQueryFields ::
MonadBuildSchema 'MSSQL r m n =>
SourceName ->
SourceInfo 'MSSQL ->
TableName 'MSSQL ->
TableInfo 'MSSQL ->
C.GQLNameIdentifier ->
@ -99,7 +100,7 @@ msBuildTableRelayQueryFields _sourceName _tableName _tableInfo _gqlName _pkeyCol
backendInsertParser ::
forall m r n.
MonadBuildSchema 'MSSQL r m n =>
SourceName ->
SourceInfo 'MSSQL ->
TableInfo 'MSSQL ->
m (InputFieldsParser n (BackendInsert (UnpreparedValue 'MSSQL)))
backendInsertParser sourceName tableInfo = do
@ -111,7 +112,7 @@ backendInsertParser sourceName tableInfo = do
msBuildTableUpdateMutationFields ::
MonadBuildSchema 'MSSQL r m n =>
SourceName ->
SourceInfo 'MSSQL ->
TableName 'MSSQL ->
TableInfo 'MSSQL ->
C.GQLNameIdentifier ->
@ -142,7 +143,7 @@ this. Should we save it?
msBuildTableDeleteMutationFields ::
MonadBuildSchema 'MSSQL r m n =>
SourceName ->
SourceInfo 'MSSQL ->
TableName 'MSSQL ->
TableInfo 'MSSQL ->
G.Name ->
@ -155,7 +156,7 @@ msBuildTableDeleteMutationFields _sourceName _tableName _tableInfo _gqlName _del
msBuildFunctionQueryFields ::
MonadBuildSchema 'MSSQL r m n =>
SourceName ->
SourceInfo 'MSSQL ->
FunctionName 'MSSQL ->
FunctionInfo 'MSSQL ->
TableName 'MSSQL ->
@ -165,7 +166,7 @@ msBuildFunctionQueryFields _ _ _ _ =
msBuildFunctionRelayQueryFields ::
MonadBuildSchema 'MSSQL r m n =>
SourceName ->
SourceInfo 'MSSQL ->
FunctionName 'MSSQL ->
FunctionInfo 'MSSQL ->
TableName 'MSSQL ->
@ -176,7 +177,7 @@ msBuildFunctionRelayQueryFields _sourceName _functionName _functionInfo _tableNa
msBuildFunctionMutationFields ::
MonadBuildSchema 'MSSQL r m n =>
SourceName ->
SourceInfo 'MSSQL ->
FunctionName 'MSSQL ->
FunctionInfo 'MSSQL ->
TableName 'MSSQL ->
@ -191,7 +192,7 @@ msBuildFunctionMutationFields _ _ _ _ =
msTableArgs ::
forall r m n.
MonadBuildSchema 'MSSQL r m n =>
SourceName ->
SourceInfo 'MSSQL ->
TableInfo 'MSSQL ->
m (InputFieldsParser n (IR.SelectArgsG 'MSSQL (UnpreparedValue 'MSSQL)))
msTableArgs sourceName tableInfo = do
@ -215,7 +216,7 @@ msTableArgs sourceName tableInfo = do
msMkRelationshipParser ::
forall r m n.
MonadBuildSchema 'MSSQL r m n =>
SourceName ->
SourceInfo 'MSSQL ->
RelInfo 'MSSQL ->
m (Maybe (InputFieldsParser n (Maybe (IR.AnnotatedInsertField 'MSSQL (UnpreparedValue 'MSSQL)))))
msMkRelationshipParser _sourceName _relationshipInfo = do
@ -335,7 +336,7 @@ msComparisonExps ::
MonadSchema n m,
MonadError QErr m,
MonadReader r m,
Has QueryContext r,
Has SchemaOptions r,
Has MkTypename r,
Has NamingCase r
) =>
@ -343,7 +344,7 @@ msComparisonExps ::
m (Parser 'Input n [ComparisonExp 'MSSQL])
msComparisonExps = P.memoize 'comparisonExps \columnType -> do
-- see Note [Columns in comparison expression are never nullable]
collapseIfNull <- asks $ qcDangerousBooleanCollapse . getter
collapseIfNull <- retrieve soDangerousBooleanCollapse
-- parsers used for individual values
typedParser <- columnParser columnType (G.Nullability False)
@ -448,7 +449,7 @@ msCountTypeInput = \case
-- Currently unsupported: returns Nothing for now.
msComputedField ::
MonadBuildSchema 'MSSQL r m n =>
SourceName ->
SourceInfo 'MSSQL ->
ComputedFieldInfo 'MSSQL ->
TableName 'MSSQL ->
TableInfo 'MSSQL ->

View File

@ -33,8 +33,8 @@ import Hasura.Prelude
import Hasura.RQL.IR.BoolExp
import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.Column
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.SchemaCache
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.Table
import Hasura.SQL.Backend
import Language.GraphQL.Draft.Syntax qualified as G
@ -55,24 +55,24 @@ import Language.GraphQL.Draft.Syntax qualified as G
ifMatchedFieldParser ::
forall r m n.
MonadBuildSchema 'MSSQL r m n =>
SourceName ->
SourceInfo 'MSSQL ->
TableInfo 'MSSQL ->
m (InputFieldsParser n (Maybe (IfMatched (UnpreparedValue 'MSSQL))))
ifMatchedFieldParser sourceName tableInfo = do
maybeObject <- ifMatchedObjectParser sourceName tableInfo
ifMatchedFieldParser sourceInfo tableInfo = do
maybeObject <- ifMatchedObjectParser sourceInfo tableInfo
return $ withJust maybeObject $ P.fieldOptional G._if_matched (Just "upsert condition")
-- | Parse a @tablename_if_matched@ object.
ifMatchedObjectParser ::
forall r m n.
MonadBuildSchema 'MSSQL r m n =>
SourceName ->
SourceInfo 'MSSQL ->
TableInfo 'MSSQL ->
m (Maybe (Parser 'Input n (IfMatched (UnpreparedValue 'MSSQL))))
ifMatchedObjectParser sourceName tableInfo = runMaybeT do
ifMatchedObjectParser sourceInfo tableInfo = runMaybeT do
-- Short-circuit if we don't have sufficient permissions.
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
matchColumnsEnum <- MaybeT $ tableInsertMatchColumnsEnum sourceName tableInfo
matchColumnsEnum <- MaybeT $ tableInsertMatchColumnsEnum sourceInfo tableInfo
lift do
updateColumnsEnum <- updateColumnsPlaceholderParser tableInfo
tableGQLName <- getTableGQLName tableInfo
@ -83,7 +83,7 @@ ifMatchedObjectParser sourceName tableInfo = runMaybeT do
matchColumnsName = G._match_columns
updateColumnsName = G._update_columns
whereName = G._where
whereExpParser <- boolExp sourceName tableInfo
whereExpParser <- boolExp sourceInfo tableInfo
pure $
P.object objectName (Just objectDesc) do
_imConditions <-
@ -109,12 +109,12 @@ ifMatchedObjectParser sourceName tableInfo = runMaybeT do
tableInsertMatchColumnsEnum ::
forall r m n.
MonadBuildSchemaBase r m n =>
SourceName ->
SourceInfo 'MSSQL ->
TableInfo 'MSSQL ->
m (Maybe (Parser 'Both n (Column 'MSSQL)))
tableInsertMatchColumnsEnum sourceName tableInfo = do
tableInsertMatchColumnsEnum sourceInfo tableInfo = do
tableGQLName <- getTableGQLName @'MSSQL tableInfo
columns <- tableSelectColumns sourceName tableInfo
columns <- tableSelectColumns sourceInfo tableInfo
enumName <- P.mkTypename $ tableGQLName <> G.__insert_match_column
let description =
Just $

View File

@ -27,9 +27,9 @@ import Hasura.RQL.IR
import Hasura.RQL.IR.Select qualified as IR
import Hasura.RQL.Types.Backend as RQL
import Hasura.RQL.Types.Column as RQL
import Hasura.RQL.Types.Common as RQL
import Hasura.RQL.Types.Function as RQL
import Hasura.RQL.Types.SchemaCache as RQL
import Hasura.RQL.Types.Source as RQL
import Hasura.RQL.Types.SourceCustomization (NamingCase)
import Hasura.SQL.Backend
import Language.GraphQL.Draft.Syntax qualified as G
@ -60,12 +60,12 @@ instance BackendSchema 'MySQL where
mysqlTableArgs ::
forall r m n.
MonadBuildSchema 'MySQL r m n =>
SourceName ->
RQL.SourceInfo 'MySQL ->
TableInfo 'MySQL ->
m (InputFieldsParser n (IR.SelectArgsG 'MySQL (UnpreparedValue 'MySQL)))
mysqlTableArgs sourceName tableInfo = do
whereParser <- tableWhereArg sourceName tableInfo
orderByParser <- tableOrderByArg sourceName tableInfo
mysqlTableArgs sourceInfo tableInfo = do
whereParser <- tableWhereArg sourceInfo tableInfo
orderByParser <- tableOrderByArg sourceInfo tableInfo
pure do
whereArg <- whereParser
orderByArg <- orderByParser
@ -82,49 +82,49 @@ mysqlTableArgs sourceName tableInfo = do
buildTableRelayQueryFields' ::
MonadBuildSchema 'MySQL r m n =>
SourceName ->
RQL.SourceInfo 'MySQL ->
RQL.TableName 'MySQL ->
TableInfo 'MySQL ->
C.GQLNameIdentifier ->
NESeq (ColumnInfo 'MySQL) ->
m [a]
buildTableRelayQueryFields' _sourceName _tableName _tableInfo _gqlName _pkeyColumns =
buildTableRelayQueryFields' _sourceInfo _tableName _tableInfo _gqlName _pkeyColumns =
pure []
buildTableInsertMutationFields' ::
MonadBuildSchema 'MySQL r m n =>
Scenario ->
SourceName ->
RQL.SourceInfo 'MySQL ->
RQL.TableName 'MySQL ->
TableInfo 'MySQL ->
C.GQLNameIdentifier ->
m [a]
buildTableInsertMutationFields' _scenario _sourceName _tableName _tableInfo _gqlName =
buildTableInsertMutationFields' _scenario _sourceInfo _tableName _tableInfo _gqlName =
pure []
buildTableUpdateMutationFields' ::
MonadBuildSchema 'MySQL r m n =>
SourceName ->
RQL.SourceInfo 'MySQL ->
RQL.TableName 'MySQL ->
TableInfo 'MySQL ->
C.GQLNameIdentifier ->
m [a]
buildTableUpdateMutationFields' _sourceName _tableName _tableInfo _gqlName =
buildTableUpdateMutationFields' _sourceInfo _tableName _tableInfo _gqlName =
pure []
buildTableDeleteMutationFields' ::
MonadBuildSchema 'MySQL r m n =>
SourceName ->
RQL.SourceInfo 'MySQL ->
RQL.TableName 'MySQL ->
TableInfo 'MySQL ->
C.GQLNameIdentifier ->
m [a]
buildTableDeleteMutationFields' _sourceName _tableName _tableInfo _gqlName =
buildTableDeleteMutationFields' _sourceInfo _tableName _tableInfo _gqlName =
pure []
buildFunctionQueryFields' ::
MonadBuildSchema 'MySQL r m n =>
SourceName ->
RQL.SourceInfo 'MySQL ->
FunctionName 'MySQL ->
FunctionInfo 'MySQL ->
RQL.TableName 'MySQL ->
@ -134,18 +134,18 @@ buildFunctionQueryFields' _ _ _ _ =
buildFunctionRelayQueryFields' ::
MonadBuildSchema 'MySQL r m n =>
SourceName ->
RQL.SourceInfo 'MySQL ->
FunctionName 'MySQL ->
FunctionInfo 'MySQL ->
RQL.TableName 'MySQL ->
NESeq (ColumnInfo 'MySQL) ->
m [a]
buildFunctionRelayQueryFields' _sourceName _functionName _functionInfo _tableName _pkeyColumns =
buildFunctionRelayQueryFields' _sourceInfo _functionName _functionInfo _tableName _pkeyColumns =
pure []
buildFunctionMutationFields' ::
MonadBuildSchema 'MySQL r m n =>
SourceName ->
RQL.SourceInfo 'MySQL ->
FunctionName 'MySQL ->
FunctionInfo 'MySQL ->
RQL.TableName 'MySQL ->

View File

@ -58,6 +58,7 @@ import Hasura.RQL.Types.Backend (Backend (..))
import Hasura.RQL.Types.Column
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.Function (FunctionInfo)
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization
import Hasura.RQL.Types.Table (RolePermInfo (..), SelPermInfo, TableInfo, UpdPermInfo)
import Hasura.SQL.Backend (BackendType (Postgres), PostgresKind (Citus, Vanilla))
@ -79,7 +80,7 @@ import Language.GraphQL.Draft.Syntax qualified as G
class PostgresSchema (pgKind :: PostgresKind) where
pgkBuildTableRelayQueryFields ::
BS.MonadBuildSchema ('Postgres pgKind) r m n =>
SourceName ->
SourceInfo ('Postgres pgKind) ->
TableName ('Postgres pgKind) ->
TableInfo ('Postgres pgKind) ->
C.GQLNameIdentifier ->
@ -87,7 +88,7 @@ class PostgresSchema (pgKind :: PostgresKind) where
m [FieldParser n (QueryDB ('Postgres pgKind) (RemoteRelationshipField UnpreparedValue) (UnpreparedValue ('Postgres pgKind)))]
pgkBuildFunctionRelayQueryFields ::
BS.MonadBuildSchema ('Postgres pgKind) r m n =>
SourceName ->
SourceInfo ('Postgres pgKind) ->
FunctionName ('Postgres pgKind) ->
FunctionInfo ('Postgres pgKind) ->
TableName ('Postgres pgKind) ->
@ -174,7 +175,7 @@ instance
backendInsertParser ::
forall pgKind m r n.
MonadBuildSchema ('Postgres pgKind) r m n =>
SourceName ->
SourceInfo ('Postgres pgKind) ->
TableInfo ('Postgres pgKind) ->
m (InputFieldsParser n (PGIR.BackendInsert pgKind (UnpreparedValue ('Postgres pgKind))))
backendInsertParser sourceName tableInfo =
@ -186,7 +187,7 @@ backendInsertParser sourceName tableInfo =
buildTableRelayQueryFields ::
forall pgKind m n r.
MonadBuildSchema ('Postgres pgKind) r m n =>
SourceName ->
SourceInfo ('Postgres pgKind) ->
TableName ('Postgres pgKind) ->
TableInfo ('Postgres pgKind) ->
C.GQLNameIdentifier ->
@ -203,7 +204,7 @@ buildTableRelayQueryFields sourceName tableName tableInfo gqlName pkeyColumns =
pgkBuildTableUpdateMutationFields ::
MonadBuildSchema ('Postgres pgKind) r m n =>
-- | The source that the table lives in
SourceName ->
SourceInfo ('Postgres pgKind) ->
-- | The name of the table being acted on
TableName ('Postgres pgKind) ->
-- | table info
@ -226,7 +227,7 @@ pgkBuildTableUpdateMutationFields sourceName tableName tableInfo gqlName =
buildFunctionRelayQueryFields ::
forall pgKind m n r.
MonadBuildSchema ('Postgres pgKind) r m n =>
SourceName ->
SourceInfo ('Postgres pgKind) ->
FunctionName ('Postgres pgKind) ->
FunctionInfo ('Postgres pgKind) ->
TableName ('Postgres pgKind) ->
@ -357,7 +358,7 @@ comparisonExps ::
MonadSchema n m,
MonadError QErr m,
MonadReader r m,
Has QueryContext r,
Has SchemaOptions r,
Has MkTypename r,
Has NamingCase r
) =>
@ -365,7 +366,7 @@ comparisonExps ::
m (Parser 'Input n [ComparisonExp ('Postgres pgKind)])
comparisonExps = P.memoize 'comparisonExps \columnType -> do
-- see Note [Columns in comparison expression are never nullable]
collapseIfNull <- asks $ qcDangerousBooleanCollapse . getter
collapseIfNull <- retrieve soDangerousBooleanCollapse
-- parsers used for comparison arguments
geogInputParser <- geographyWithinDistanceInput

View File

@ -31,8 +31,8 @@ import Hasura.Prelude
import Hasura.RQL.IR.BoolExp
import Hasura.RQL.IR.Insert qualified as IR
import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.SchemaCache
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization (applyFieldNameCaseCust)
import Hasura.RQL.Types.Table
import Hasura.SQL.Backend
@ -53,14 +53,14 @@ import Language.GraphQL.Draft.Syntax qualified as G
onConflictFieldParser ::
forall pgKind r m n.
MonadBuildSchema ('Postgres pgKind) r m n =>
SourceName ->
SourceInfo ('Postgres pgKind) ->
TableInfo ('Postgres pgKind) ->
m (InputFieldsParser n (Maybe (IR.OnConflictClause ('Postgres pgKind) (UnpreparedValue ('Postgres pgKind)))))
onConflictFieldParser sourceName tableInfo = do
onConflictFieldParser sourceInfo tableInfo = do
tCase <- asks getter
updatePerms <- _permUpd <$> tablePermissions tableInfo
let maybeConstraints = tciUniqueOrPrimaryKeyConstraints . _tiCoreInfo $ tableInfo
maybeConflictObject = conflictObjectParser sourceName tableInfo <$> maybeConstraints <*> updatePerms
maybeConflictObject = conflictObjectParser sourceInfo tableInfo <$> maybeConstraints <*> updatePerms
case maybeConflictObject of
Just conflictObject -> conflictObject <&> P.fieldOptional (applyFieldNameCaseCust tCase G._on_conflict) (Just "upsert condition")
Nothing -> return $ pure Nothing
@ -69,15 +69,15 @@ onConflictFieldParser sourceName tableInfo = do
conflictObjectParser ::
forall pgKind r m n.
MonadBuildSchema ('Postgres pgKind) r m n =>
SourceName ->
SourceInfo ('Postgres pgKind) ->
TableInfo ('Postgres pgKind) ->
NonEmpty (Constraint ('Postgres pgKind)) ->
UpdPermInfo ('Postgres pgKind) ->
m (Parser 'Input n (IR.OnConflictClause ('Postgres pgKind) (UnpreparedValue ('Postgres pgKind))))
conflictObjectParser sourceName tableInfo constraints updatePerms = do
conflictObjectParser sourceInfo tableInfo constraints updatePerms = do
updateColumnsEnum <- updateColumnsPlaceholderParser tableInfo
constraintParser <- conflictConstraint constraints sourceName tableInfo
whereExpParser <- boolExp sourceName tableInfo
constraintParser <- conflictConstraint constraints sourceInfo tableInfo
whereExpParser <- boolExp sourceInfo tableInfo
tableGQLName <- getTableGQLName tableInfo
objectName <- P.mkTypename $ tableGQLName <> G.__on_conflict
@ -116,11 +116,11 @@ conflictConstraint ::
forall pgKind r m n.
MonadBuildSchema ('Postgres pgKind) r m n =>
NonEmpty (Constraint ('Postgres pgKind)) ->
SourceName ->
SourceInfo ('Postgres pgKind) ->
TableInfo ('Postgres pgKind) ->
m (Parser 'Both n (ConstraintName ('Postgres pgKind)))
conflictConstraint constraints sourceName tableInfo =
memoizeOn 'conflictConstraint (sourceName, tableName) $ do
conflictConstraint constraints sourceInfo tableInfo =
memoizeOn 'conflictConstraint (_siName sourceInfo, tableName) $ do
tableGQLName <- getTableGQLName tableInfo
constraintEnumValues <- for constraints \constraint -> do
name <- textToName $ toTxt $ _cName constraint

View File

@ -23,7 +23,7 @@ import Hasura.Base.Error
import Hasura.GraphQL.Execute.Types
import Hasura.GraphQL.Parser.Constants qualified as G
import Hasura.GraphQL.Parser.Monad (ParseT, runSchemaT)
import Hasura.GraphQL.Schema.Common (QueryContext (..))
import Hasura.GraphQL.Schema.Common
import Hasura.GraphQL.Schema.Remote (buildRemoteParser)
import Hasura.GraphQL.Transport.HTTP.Protocol
import Hasura.HTTP
@ -33,7 +33,6 @@ import Hasura.RQL.Types.Common
import Hasura.RQL.Types.Function
import Hasura.RQL.Types.RemoteSchema
import Hasura.RQL.Types.SchemaCache
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization
import Hasura.Server.Utils
import Hasura.Session
@ -80,9 +79,12 @@ fetchRemoteSchema env manager _rscName rsDef@ValidatedRemoteSchemaDef {..} = do
-- properly for each role at schema generation time, but this allows us to
-- quickly reject an invalid schema.
void $
runSchemaT $
flip runReaderT minimumValidContext $
buildRemoteParser @_ @_ @(ParseT Identity) _rscIntroOriginal _rscRemoteRelationships _rscInfo
flip runReaderT minimumValidContext $
runSchemaT $
buildRemoteParser @_ @_ @(ParseT Identity)
_rscIntroOriginal
_rscRemoteRelationships
_rscInfo
-- The 'rawIntrospectionResult' contains the 'Bytestring' response of
-- the introspection result of the remote server. We store this in the
@ -113,28 +115,29 @@ fetchRemoteSchema env manager _rscName rsDef@ValidatedRemoteSchemaDef {..} = do
-- the remote schema.
minimumValidContext =
( adminRoleName :: RoleName,
mempty :: SourceCache,
mempty :: CustomizeRemoteFieldName,
mempty :: RemoteSchemaMap,
mempty :: MkTypename,
mempty :: MkRootFieldName,
HasuraCase :: NamingCase,
QueryContext
SchemaOptions
{ -- doesn't apply to remote schemas
qcStringifyNum = LeaveNumbersAlone,
soStringifyNum = LeaveNumbersAlone,
-- doesn't apply to remote schemas
qcDangerousBooleanCollapse = True,
soDangerousBooleanCollapse = True,
-- we don't support remote schemas in Relay, but the check is
-- performed ahead of time, meaning that the value here is
-- irrelevant
qcQueryType = QueryHasura,
soQueryType = QueryHasura,
-- doesn't apply to remote schemas
qcFunctionPermsContext = FunctionPermissionsInferred,
soFunctionPermsContext = FunctionPermissionsInferred,
-- we default to no permissions
qcRemoteSchemaPermsCtx = RemoteSchemaPermsDisabled,
soRemoteSchemaPermsCtx = RemoteSchemaPermsDisabled,
-- doesn't apply to remote schemas
qcOptimizePermissionFilters = False
}
soOptimizePermissionFilters = False
},
SchemaContext
mempty
ignoreRemoteRelationship
)
-- | Sends a GraphQL query to the given server.

View File

@ -36,6 +36,7 @@ import Hasura.GraphQL.Schema.Instances ()
import Hasura.GraphQL.Schema.Introspect
import Hasura.GraphQL.Schema.Postgres
import Hasura.GraphQL.Schema.Remote (buildRemoteParser)
import Hasura.GraphQL.Schema.RemoteRelationship
import Hasura.GraphQL.Schema.Select
import Hasura.GraphQL.Schema.Table
import Hasura.Prelude
@ -176,15 +177,19 @@ buildRoleContext options sources remotes allActionInfos customTypes role remoteS
queryType,
functionPermsCtx
) = options
roleQueryContext =
QueryContext
schemaOptions =
SchemaOptions
stringifyNum
dangerousBooleanCollapse
queryType
functionPermsCtx
remoteSchemaPermsCtx
optimizePermissionFilters
runMonadSchema role roleQueryContext sources (fst <$> remotes) $ do
schemaContext =
SchemaContext
sources
(remoteRelationshipField sources (fst <$> remotes))
runMonadSchema schemaOptions schemaContext role $ do
-- build all sources
(sourcesQueryFields, sourcesMutationFrontendFields, sourcesMutationBackendFields, subscriptionFields) <-
fmap mconcat $ traverse (buildBackendSource buildSource) $ toList sources
@ -261,15 +266,15 @@ buildRoleContext options sources remotes allActionInfos customTypes role remoteS
[FieldParser (P.ParseT Identity) (NamespacedField (MutationRootField UnpreparedValue))],
[FieldParser (P.ParseT Identity) (NamespacedField (QueryRootField UnpreparedValue))]
)
buildSource (SourceInfo sourceName tables functions sourceConfig queryTagsConfig sourceCustomization') =
buildSource sourceInfo@(SourceInfo _ tables functions _ _ sourceCustomization') =
withSourceCustomization sourceCustomization (namingConventionSupport @b) globalDefaultNC do
let validFunctions = takeValidFunctions functions
validTables = takeValidTables tables
mkTypename <- asks getter
uncustomizedQueryFields <- buildQueryFields sourceName sourceConfig validTables validFunctions queryTagsConfig
uncustomizedQueryFields <- buildQueryFields sourceInfo validTables validFunctions
uncustomizedStreamSubscriptionFields <-
case streamingSubscriptionsCtx of
StreamingSubscriptionsEnabled -> buildTableStreamSubscriptionFields sourceName sourceConfig validTables queryTagsConfig
StreamingSubscriptionsEnabled -> buildTableStreamSubscriptionFields sourceInfo validTables
StreamingSubscriptionsDisabled -> pure mempty
(,,,)
<$> customizeFields
@ -279,11 +284,11 @@ buildRoleContext options sources remotes allActionInfos customTypes role remoteS
<*> customizeFields
sourceCustomization
(mkTypename <> P.MkTypename (<> G.__mutation_frontend))
(buildMutationFields Frontend sourceName sourceConfig validTables validFunctions queryTagsConfig)
(buildMutationFields Frontend sourceInfo validTables validFunctions)
<*> customizeFields
sourceCustomization
(mkTypename <> P.MkTypename (<> G.__mutation_backend))
(buildMutationFields Backend sourceName sourceConfig validTables validFunctions queryTagsConfig)
(buildMutationFields Backend sourceInfo validTables validFunctions)
<*> customizeFields
sourceCustomization
(mkTypename <> P.MkTypename (<> G.__subscription))
@ -310,18 +315,22 @@ buildRelayRoleContext options sources allActionInfos customTypes role expFeature
queryType,
functionPermsCtx
) = options
-- TODO: At the time of writing this, remote schema queries are not supported in relay.
-- When they are supported, we should get do what `buildRoleContext` does. Since, they
-- are not supported yet, we use `mempty` below for `RemoteSchemaMap`.
roleQueryContext =
QueryContext
schemaOptions =
SchemaOptions
stringifyNum
dangerousBooleanCollapse
queryType
functionPermsCtx
RemoteSchemaPermsDisabled
optimizePermissionFilters
runMonadSchema role roleQueryContext sources mempty do
-- TODO: At the time of writing this, remote schema queries are not supported in relay.
-- When they are supported, we should get do what `buildRoleContext` does. Since, they
-- are not supported yet, we use `mempty` below for `RemoteSchemaMap`.
schemaContext =
SchemaContext
sources
(remoteRelationshipField sources mempty)
runMonadSchema schemaOptions schemaContext role do
fieldsList <- traverse (buildBackendSource buildSource) $ toList sources
-- Add node root field.
@ -381,7 +390,7 @@ buildRelayRoleContext options sources allActionInfos customTypes role expFeature
[FieldParser (P.ParseT Identity) (NamespacedField (MutationRootField UnpreparedValue))],
[FieldParser (P.ParseT Identity) (NamespacedField (MutationRootField UnpreparedValue))]
)
buildSource (SourceInfo sourceName tables functions sourceConfig queryTagsConfig sourceCustomization') =
buildSource sourceInfo@(SourceInfo _ tables functions _ _ sourceCustomization') =
withSourceCustomization sourceCustomization (namingConventionSupport @b) globalDefaultNC do
let validFunctions = takeValidFunctions functions
validTables = takeValidTables tables
@ -391,15 +400,15 @@ buildRelayRoleContext options sources allActionInfos customTypes role expFeature
<$> customizeFields
sourceCustomization
(mkTypename <> P.MkTypename (<> G.__query))
(buildRelayQueryFields sourceName sourceConfig validTables validFunctions queryTagsConfig)
(buildRelayQueryFields sourceInfo validTables validFunctions)
<*> customizeFields
sourceCustomization
(mkTypename <> P.MkTypename (<> G.__mutation_frontend))
(buildMutationFields Frontend sourceName sourceConfig validTables validFunctions queryTagsConfig)
(buildMutationFields Frontend sourceInfo validTables validFunctions)
<*> customizeFields
sourceCustomization
(mkTypename <> P.MkTypename (<> G.__mutation_backend))
(buildMutationFields Backend sourceName sourceConfig validTables validFunctions queryTagsConfig)
(buildMutationFields Backend sourceInfo validTables validFunctions)
where
sourceCustomization =
if EFNamingConventions `elem` expFeatures
@ -429,14 +438,18 @@ unauthenticatedContext allRemotes remoteSchemaPermsCtx = do
-- building a restricted schema; namely, we erase all remote relationships
-- from the remote schema contexts, meaning that all the information that is
-- needed for sources is completely irrelevant and filled with default values.
let fakeQueryContext =
QueryContext
let fakeSchemaOptions =
SchemaOptions
LeaveNumbersAlone -- stringifyNum doesn't apply to remotes
True -- booleanCollapse doesn't apply to remotes
QueryHasura
FunctionPermissionsInferred -- function permissions don't apply to remotes
remoteSchemaPermsCtx
False
fakeSchemaContext =
SchemaContext
mempty
ignoreRemoteRelationship
-- chosen arbitrarily to be as improbable as possible
fakeRole = mkRoleNameSafe [NT.nonEmptyTextQQ|MyNameIsOzymandiasKingOfKingsLookOnMyWorksYeMightyAndDespair|]
-- we delete all references to remote joins
@ -444,7 +457,7 @@ unauthenticatedContext allRemotes remoteSchemaPermsCtx = do
allRemotes <&> first \context ->
context {_rscRemoteRelationships = mempty}
runMonadSchema fakeRole fakeQueryContext mempty mempty do
runMonadSchema fakeSchemaOptions fakeSchemaContext fakeRole do
(queryFields, mutationFields, subscriptionFields, remoteErrors) <- case remoteSchemaPermsCtx of
RemoteSchemaPermsEnabled ->
-- Permissions are enabled, unauthenticated users have access to nothing.
@ -548,94 +561,95 @@ buildRemoteSchemaParser remoteSchemaPermsCtx roleName context = do
buildQueryFields ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceConfig b ->
SourceInfo b ->
TableCache b ->
FunctionCache b ->
Maybe QueryTagsConfig ->
m [P.FieldParser n (QueryRootField UnpreparedValue)]
buildQueryFields sourceName sourceConfig tables (takeExposedAs FEAQuery -> functions) queryTagsConfig = do
buildQueryFields sourceInfo tables (takeExposedAs FEAQuery -> functions) = do
roleName <- asks getter
functionPermsCtx <- asks $ qcFunctionPermsContext . getter
functionPermsCtx <- retrieve soFunctionPermsContext
tableSelectExpParsers <- for (Map.toList tables) \(tableName, tableInfo) -> do
tableIdentifierName <- getTableIdentifierName @b tableInfo
mkRF $ buildTableQueryFields sourceName tableName tableInfo tableIdentifierName
mkRF $ buildTableQueryFields sourceInfo tableName tableInfo tableIdentifierName
functionSelectExpParsers <- for (Map.toList functions) \(functionName, functionInfo) -> runMaybeT $ do
guard $
roleName == adminRoleName
|| roleName `Map.member` _fiPermissions functionInfo
|| functionPermsCtx == FunctionPermissionsInferred
let targetTableName = _fiReturnType functionInfo
lift $ mkRF $ buildFunctionQueryFields sourceName functionName functionInfo targetTableName
lift $ mkRF $ buildFunctionQueryFields sourceInfo functionName functionInfo targetTableName
pure $ concat $ tableSelectExpParsers <> catMaybes functionSelectExpParsers
where
mkRF = mkRootField sourceName sourceConfig queryTagsConfig QDBR
sourceName = _siName sourceInfo
sourceConfig = _siConfiguration sourceInfo
queryTagsConfig = _siQueryTagsConfig sourceInfo
buildTableStreamSubscriptionFields ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceConfig b ->
SourceInfo b ->
TableCache b ->
Maybe QueryTagsConfig ->
m [P.FieldParser n (QueryRootField UnpreparedValue)]
buildTableStreamSubscriptionFields sourceName sourceConfig tables queryTagsConfig = do
buildTableStreamSubscriptionFields sourceInfo tables = do
tableSelectExpParsers <- for (Map.toList tables) \(tableName, tableInfo) -> do
tableGQLName <- getTableIdentifierName @b tableInfo
mkRF $
buildTableStreamingSubscriptionFields
sourceName
sourceInfo
tableName
tableInfo
tableGQLName
pure $ concat tableSelectExpParsers
where
mkRF = mkRootField sourceName sourceConfig queryTagsConfig QDBR
sourceName = _siName sourceInfo
sourceConfig = _siConfiguration sourceInfo
queryTagsConfig = _siQueryTagsConfig sourceInfo
buildRelayQueryFields ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceConfig b ->
SourceInfo b ->
TableCache b ->
FunctionCache b ->
Maybe QueryTagsConfig ->
m [P.FieldParser n (QueryRootField UnpreparedValue)]
buildRelayQueryFields sourceName sourceConfig tables (takeExposedAs FEAQuery -> functions) queryTagsConfig = do
buildRelayQueryFields sourceInfo tables (takeExposedAs FEAQuery -> functions) = do
tableConnectionFields <- for (Map.toList tables) \(tableName, tableInfo) -> runMaybeT do
tableIdentifierName <- getTableIdentifierName @b tableInfo
pkeyColumns <- hoistMaybe $ tableInfo ^? tiCoreInfo . tciPrimaryKey . _Just . pkColumns
lift $ mkRF $ buildTableRelayQueryFields sourceName tableName tableInfo tableIdentifierName pkeyColumns
lift $ mkRF $ buildTableRelayQueryFields sourceInfo tableName tableInfo tableIdentifierName pkeyColumns
functionConnectionFields <- for (Map.toList functions) $ \(functionName, functionInfo) -> runMaybeT do
let returnTableName = _fiReturnType functionInfo
-- FIXME: only extract the TableInfo once to avoid redundant cache lookups
returnTableInfo <- lift $ askTableInfo sourceName returnTableName
returnTableInfo <- lift $ askTableInfo sourceInfo returnTableName
pkeyColumns <- MaybeT $ (^? tiCoreInfo . tciPrimaryKey . _Just . pkColumns) <$> pure returnTableInfo
lift $ mkRF $ buildFunctionRelayQueryFields sourceName functionName functionInfo returnTableName pkeyColumns
lift $ mkRF $ buildFunctionRelayQueryFields sourceInfo functionName functionInfo returnTableName pkeyColumns
pure $ concat $ catMaybes $ tableConnectionFields <> functionConnectionFields
where
mkRF = mkRootField sourceName sourceConfig queryTagsConfig QDBR
sourceName = _siName sourceInfo
sourceConfig = _siConfiguration sourceInfo
queryTagsConfig = _siQueryTagsConfig sourceInfo
buildMutationFields ::
forall b r m n.
MonadBuildSchema b r m n =>
Scenario ->
SourceName ->
SourceConfig b ->
SourceInfo b ->
TableCache b ->
FunctionCache b ->
Maybe QueryTagsConfig ->
m [P.FieldParser n (MutationRootField UnpreparedValue)]
buildMutationFields scenario sourceName sourceConfig tables (takeExposedAs FEAMutation -> functions) queryTagsConfig = do
buildMutationFields scenario sourceInfo tables (takeExposedAs FEAMutation -> functions) = do
roleName <- asks getter
tableMutations <- for (Map.toList tables) \(tableName, tableInfo) -> do
tableIdentifierName <- getTableIdentifierName @b tableInfo
inserts <-
mkRF (MDBR . MDBInsert) $ buildTableInsertMutationFields scenario sourceName tableName tableInfo tableIdentifierName
mkRF (MDBR . MDBInsert) $ buildTableInsertMutationFields scenario sourceInfo tableName tableInfo tableIdentifierName
updates <-
mkRF (MDBR . MDBUpdate) $ buildTableUpdateMutationFields @b sourceName tableName tableInfo tableIdentifierName
mkRF (MDBR . MDBUpdate) $ buildTableUpdateMutationFields sourceInfo tableName tableInfo tableIdentifierName
deletes <-
mkRF (MDBR . MDBDelete) $ buildTableDeleteMutationFields sourceName tableName tableInfo tableIdentifierName
mkRF (MDBR . MDBDelete) $ buildTableDeleteMutationFields sourceInfo tableName tableInfo tableIdentifierName
pure $ concat [inserts, updates, deletes]
functionMutations <- for (Map.toList functions) \(functionName, functionInfo) -> runMaybeT $ do
let targetTableName = _fiReturnType functionInfo
@ -645,11 +659,14 @@ buildMutationFields scenario sourceName sourceConfig tables (takeExposedAs FEAMu
-- when function permissions are inferred, we don't expose the
-- mutation functions for non-admin roles. See Note [Function Permissions]
roleName == adminRoleName || roleName `Map.member` (_fiPermissions functionInfo)
lift $ mkRF MDBR $ buildFunctionMutationFields sourceName functionName functionInfo targetTableName
lift $ mkRF MDBR $ buildFunctionMutationFields sourceInfo functionName functionInfo targetTableName
pure $ concat $ tableMutations <> catMaybes functionMutations
where
mkRF :: forall a db remote action raw. (a -> db b) -> m [FieldParser n a] -> m [FieldParser n (RootField db remote action raw)]
mkRF = mkRootField sourceName sourceConfig queryTagsConfig
sourceName = _siName sourceInfo
sourceConfig = _siConfiguration sourceInfo
queryTagsConfig = _siQueryTagsConfig sourceInfo
----------------------------------------------------------------
-- Building root parser from fields
@ -821,13 +838,12 @@ type ConcreteSchemaT m a =
P.SchemaT
(P.ParseT Identity)
( ReaderT
( RoleName,
SourceCache,
QueryContext,
P.MkTypename,
( SchemaOptions,
SchemaContext,
RoleName,
MkTypename,
MkRootFieldName,
CustomizeRemoteFieldName,
RemoteSchemaMap,
NamingCase
)
m
@ -837,14 +853,14 @@ type ConcreteSchemaT m a =
runMonadSchema ::
forall m a.
Monad m =>
SchemaOptions ->
SchemaContext ->
RoleName ->
QueryContext ->
SourceCache ->
RemoteSchemaMap ->
ConcreteSchemaT m a ->
m a
runMonadSchema roleName queryContext sources remotes m =
P.runSchemaT m `runReaderT` (roleName, sources, queryContext, mempty, mempty, mempty, remotes, HasuraCase)
runMonadSchema options context roleName m =
flip runReaderT (options, context, roleName, mempty, mempty, mempty, HasuraCase) $
P.runSchemaT m
buildBackendSource ::
(forall b. BackendSchema b => SourceInfo b -> r) ->

View File

@ -29,7 +29,6 @@ import Hasura.GraphQL.Parser.Constants qualified as G
import Hasura.GraphQL.Parser.Internal.Parser qualified as P
import Hasura.GraphQL.Schema.Backend
import Hasura.GraphQL.Schema.Common
import Hasura.GraphQL.Schema.Select
import Hasura.Prelude
import Hasura.RQL.IR.Action qualified as IR
import Hasura.RQL.IR.Root qualified as IR
@ -185,7 +184,7 @@ actionAsyncQuery objectTypes actionInfo = runMaybeT do
let selectionSet = customScalarParser ast
pure $ P.selection fieldName description actionIdInputField selectionSet <&> (,[])
stringifyNum <- asks $ qcStringifyNum . getter
stringifyNum <- retrieve soStringifyNum
pure $
parserOutput
<&> \(idArg, fields) ->
@ -261,7 +260,8 @@ actionOutputFields outputType annotatedObject objectTypes = do
TypeRelationship (TableInfo ('Postgres 'Vanilla)) (ColumnInfo ('Postgres 'Vanilla)) ->
m (Maybe [FieldParser n (AnnotatedActionField)])
relationshipFieldParser (TypeRelationship relationshipName relType sourceName tableInfo fieldMapping) = runMaybeT do
sourceInfo <- MaybeT $ asks $ (unsafeSourceInfo @('Postgres 'Vanilla) <=< Map.lookup sourceName) . getter
sourceCache <- lift $ retrieve scSourceCache
sourceInfo <- hoistMaybe $ unsafeSourceInfo @('Postgres 'Vanilla) =<< Map.lookup sourceName sourceCache
relName <- hoistMaybe $ RelName <$> mkNonEmptyText (toTxt relationshipName)
-- `lhsJoinFields` is a map of `x: y`
@ -295,6 +295,7 @@ actionOutputFields outputType annotatedObject objectTypes = do
_rsfiMapping = joinMapping
}
}
RemoteRelationshipParserBuilder remoteRelationshipField <- retrieve scRemoteRelationshipParserBuilder
remoteRelationshipFieldParsers <- MaybeT $ remoteRelationshipField remoteFieldInfo
pure $ remoteRelationshipFieldParsers <&> fmap (IR.ACFRemote . IR.ActionRemoteRelationshipSelect lhsJoinFields)

View File

@ -51,6 +51,7 @@ import Hasura.RQL.Types.ComputedField
import Hasura.RQL.Types.Function
import Hasura.RQL.Types.Relationships.Local
import Hasura.RQL.Types.SchemaCache
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization (NamingCase)
import Hasura.RQL.Types.Table
import Hasura.SQL.Backend
@ -98,21 +99,21 @@ class
-- top level parsers
buildTableQueryFields ::
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableName b ->
TableInfo b ->
GQLNameIdentifier ->
m [FieldParser n (QueryDB b (RemoteRelationshipField UnpreparedValue) (UnpreparedValue b))]
buildTableStreamingSubscriptionFields ::
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableName b ->
TableInfo b ->
GQLNameIdentifier ->
m [FieldParser n (QueryDB b (RemoteRelationshipField UnpreparedValue) (UnpreparedValue b))]
buildTableRelayQueryFields ::
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableName b ->
TableInfo b ->
GQLNameIdentifier ->
@ -121,7 +122,7 @@ class
buildTableInsertMutationFields ::
MonadBuildSchema b r m n =>
Scenario ->
SourceName ->
SourceInfo b ->
TableName b ->
TableInfo b ->
GQLNameIdentifier ->
@ -136,7 +137,7 @@ class
buildTableUpdateMutationFields ::
MonadBuildSchema b r m n =>
-- | The source that the table lives in
SourceName ->
SourceInfo b ->
-- | The name of the table being acted on
TableName b ->
-- | table info
@ -147,7 +148,7 @@ class
buildTableDeleteMutationFields ::
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableName b ->
TableInfo b ->
GQLNameIdentifier ->
@ -155,7 +156,7 @@ class
buildFunctionQueryFields ::
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
FunctionName b ->
FunctionInfo b ->
TableName b ->
@ -163,7 +164,7 @@ class
buildFunctionRelayQueryFields ::
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
FunctionName b ->
FunctionInfo b ->
TableName b ->
@ -172,7 +173,7 @@ class
buildFunctionMutationFields ::
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
FunctionName b ->
FunctionInfo b ->
TableName b ->
@ -181,7 +182,7 @@ class
-- table components
tableArguments ::
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (InputFieldsParser n (IR.SelectArgsG b (UnpreparedValue b)))
@ -189,7 +190,7 @@ class
-- relationships altogether.
mkRelationshipParser ::
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
RelInfo b ->
m (Maybe (InputFieldsParser n (Maybe (IR.AnnotatedInsertField b (UnpreparedValue b)))))
mkRelationshipParser _ _ = pure Nothing
@ -232,7 +233,7 @@ class
-- | Computed field parser
computedField ::
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
ComputedFieldInfo b ->
TableName b ->
TableInfo b ->

View File

@ -28,11 +28,11 @@ import Hasura.Prelude
import Hasura.RQL.IR.BoolExp
import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.Column
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.ComputedField
import Hasura.RQL.Types.Function
import Hasura.RQL.Types.Relationships.Local
import Hasura.RQL.Types.SchemaCache hiding (askTableInfo)
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization (NamingCase, applyFieldNameCaseIdentifier)
import Hasura.RQL.Types.Table
import Language.GraphQL.Draft.Syntax qualified as G
@ -48,10 +48,10 @@ import Language.GraphQL.Draft.Syntax qualified as G
boolExp ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (Parser 'Input n (AnnBoolExp b (UnpreparedValue b)))
boolExp sourceName tableInfo = memoizeOn 'boolExp (sourceName, tableName) $ do
boolExp sourceInfo tableInfo = memoizeOn 'boolExp (_siName sourceInfo, tableName) $ do
tableGQLName <- getTableGQLName tableInfo
name <- P.mkTypename $ tableGQLName <> G.__bool_exp
let description =
@ -59,9 +59,9 @@ boolExp sourceName tableInfo = memoizeOn 'boolExp (sourceName, tableName) $ do
"Boolean expression to filter rows from the table " <> tableName
<<> ". All fields are combined with a logical 'AND'."
fieldInfos <- tableSelectFields sourceName tableInfo
fieldInfos <- tableSelectFields sourceInfo tableInfo
tableFieldParsers <- catMaybes <$> traverse mkField fieldInfos
recur <- boolExp sourceName tableInfo
recur <- boolExp sourceInfo tableInfo
-- Bafflingly, ApplicativeDo doesnt work if we inline this definition (I
-- think the TH splices throw it off), so we have to define it separately.
let specialFieldParsers =
@ -89,12 +89,12 @@ boolExp sourceName tableInfo = memoizeOn 'boolExp (sourceName, tableName) $ do
lift $ fmap (AVColumn columnInfo) <$> comparisonExps @b (ciType columnInfo)
-- field_name: field_type_bool_exp
FIRelationship relationshipInfo -> do
remoteTableInfo <- askTableInfo sourceName $ riRTable relationshipInfo
remoteTableInfo <- askTableInfo sourceInfo $ riRTable relationshipInfo
remotePermissions <- lift $ tableSelectPermissions remoteTableInfo
let remoteTableFilter =
fmap partialSQLExpToUnpreparedValue
<$> maybe annBoolExpTrue spiFilter remotePermissions
remoteBoolExp <- lift $ boolExp sourceName remoteTableInfo
remoteBoolExp <- lift $ boolExp sourceInfo remoteTableInfo
pure $ fmap (AVRelationship relationshipInfo . andAnnBoolExps remoteTableFilter) remoteBoolExp
FIComputedField ComputedFieldInfo {..} -> do
let ComputedFieldFunction {..} = _cfiFunction
@ -109,8 +109,8 @@ boolExp sourceName tableInfo = memoizeOn 'boolExp (sourceName, tableName) $ do
<$> case computedFieldReturnType @b _cfiReturnType of
ReturnsScalar scalarType -> lift $ fmap CFBEScalar <$> comparisonExps @b (ColumnScalar scalarType)
ReturnsTable table -> do
info <- askTableInfo @b sourceName table
lift $ fmap (CFBETable table) <$> boolExp sourceName info
info <- askTableInfo sourceInfo table
lift $ fmap (CFBETable table) <$> boolExp sourceInfo info
ReturnsOthers -> hoistMaybe Nothing
_ -> hoistMaybe Nothing

View File

@ -70,6 +70,7 @@ import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.Function
import Hasura.RQL.Types.SchemaCache
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization
import Hasura.RQL.Types.Table
import Hasura.SQL.Backend
@ -95,12 +96,12 @@ setFieldNameCase tCase tInfo crf getFieldName tableName =
buildTableQueryFields ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableName b ->
TableInfo b ->
C.GQLNameIdentifier ->
(m [FieldParser n (QueryDB b (RemoteRelationshipField UnpreparedValue) (UnpreparedValue b))])
buildTableQueryFields sourceName tableName tableInfo gqlName = do
buildTableQueryFields sourceInfo tableName tableInfo gqlName = do
tCase <- asks getter
-- select table
selectName <- mkRootFieldName $ setFieldNameCase tCase tableInfo _tcrfSelect mkSelectField gqlName
@ -110,9 +111,9 @@ buildTableQueryFields sourceName tableName tableInfo gqlName = do
selectAggName <- mkRootFieldName $ setFieldNameCase tCase tableInfo _tcrfSelectAggregate mkSelectAggregateField gqlName
catMaybes
<$> sequenceA
[ optionalFieldParser QDBMultipleRows $ selectTable sourceName tableInfo selectName selectDesc,
optionalFieldParser QDBSingleRow $ selectTableByPk sourceName tableInfo selectPKName selectPKDesc,
optionalFieldParser QDBAggregation $ selectTableAggregate sourceName tableInfo selectAggName selectAggDesc
[ optionalFieldParser QDBMultipleRows $ selectTable sourceInfo tableInfo selectName selectDesc,
optionalFieldParser QDBSingleRow $ selectTableByPk sourceInfo tableInfo selectPKName selectPKDesc,
optionalFieldParser QDBAggregation $ selectTableAggregate sourceInfo tableInfo selectAggName selectAggDesc
]
where
selectDesc = buildFieldDescription defaultSelectDesc $ _crfComment _tcrfSelect
@ -126,42 +127,42 @@ buildTableQueryFields sourceName tableName tableInfo gqlName = do
buildTableStreamingSubscriptionFields ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableName b ->
TableInfo b ->
C.GQLNameIdentifier ->
m [FieldParser n (QueryDB b (RemoteRelationshipField UnpreparedValue) (UnpreparedValue b))]
buildTableStreamingSubscriptionFields sourceName tableName tableInfo gqlName = do
buildTableStreamingSubscriptionFields sourceInfo tableName tableInfo gqlName = do
tCase <- asks getter
let customRootFields = _tcCustomRootFields $ _tciCustomConfig $ _tiCoreInfo tableInfo
selectDesc = Just $ G.Description $ "fetch data from the table in a streaming manner : " <>> tableName
selectStreamName <- mkRootFieldName $ setFieldNameCase tCase tableInfo (_tcrfSelect customRootFields) mkSelectStreamField gqlName
catMaybes
<$> sequenceA
[ optionalFieldParser QDBStreamMultipleRows $ selectStreamTable sourceName tableInfo selectStreamName selectDesc
[ optionalFieldParser QDBStreamMultipleRows $ selectStreamTable sourceInfo tableInfo selectStreamName selectDesc
]
buildTableInsertMutationFields ::
forall b r m n.
MonadBuildSchema b r m n =>
(SourceName -> TableInfo b -> m (InputFieldsParser n (BackendInsert b (UnpreparedValue b)))) ->
(SourceInfo b -> TableInfo b -> m (InputFieldsParser n (BackendInsert b (UnpreparedValue b)))) ->
Scenario ->
SourceName ->
SourceInfo b ->
TableName b ->
TableInfo b ->
C.GQLNameIdentifier ->
m [FieldParser n (AnnotatedInsert b (RemoteRelationshipField UnpreparedValue) (UnpreparedValue b))]
buildTableInsertMutationFields backendInsertAction scenario sourceName tableName tableInfo gqlName = do
buildTableInsertMutationFields backendInsertAction scenario sourceInfo tableName tableInfo gqlName = do
tCase <- asks getter
-- insert in table
insertName <- mkRootFieldName $ setFieldNameCase tCase tableInfo _tcrfInsert mkInsertField gqlName
-- insert one in table
insertOneName <- mkRootFieldName $ setFieldNameCase tCase tableInfo _tcrfInsertOne mkInsertOneField gqlName
insert <- insertIntoTable backendInsertAction scenario sourceName tableInfo insertName insertDesc
insert <- insertIntoTable backendInsertAction scenario sourceInfo tableInfo insertName insertDesc
-- Select permissions are required for insertOne: the selection set is the
-- same as a select on that table, and it therefore can't be populated if the
-- user doesn't have select permissions.
insertOne <- insertOneIntoTable backendInsertAction scenario sourceName tableInfo insertOneName insertOneDesc
insertOne <- insertOneIntoTable backendInsertAction scenario sourceInfo tableInfo insertOneName insertOneDesc
pure $ catMaybes [insert, insertOne]
where
insertDesc = buildFieldDescription defaultInsertDesc $ _crfComment _tcrfInsert
@ -200,7 +201,7 @@ buildTableUpdateMutationFields ::
(InputFieldsParser n (BackendUpdate b (UnpreparedValue b)))
) ->
-- | The source that the table lives in
SourceName ->
SourceInfo b ->
-- | The name of the table being acted on
TableName b ->
-- | table info
@ -208,18 +209,18 @@ buildTableUpdateMutationFields ::
-- | field display name
C.GQLNameIdentifier ->
m [FieldParser n (AnnotatedUpdateG b (RemoteRelationshipField UnpreparedValue) (UnpreparedValue b))]
buildTableUpdateMutationFields mkBackendUpdate sourceName tableName tableInfo gqlName = do
buildTableUpdateMutationFields mkBackendUpdate sourceInfo tableName tableInfo gqlName = do
tCase <- asks getter
backendUpdate <- mkBackendUpdate tableInfo
-- update table
updateName <- mkRootFieldName $ setFieldNameCase tCase tableInfo _tcrfUpdate mkUpdateField gqlName
-- update table by pk
updatePKName <- mkRootFieldName $ setFieldNameCase tCase tableInfo _tcrfUpdateByPk mkUpdateByPkField gqlName
update <- updateTable backendUpdate sourceName tableInfo updateName updateDesc
update <- updateTable backendUpdate sourceInfo tableInfo updateName updateDesc
-- Primary keys can only be tested in the `where` clause if a primary key
-- exists on the table and if the user has select permissions on all columns
-- that make up the key.
updateByPk <- updateTableByPk backendUpdate sourceName tableInfo updatePKName updatePKDesc
updateByPk <- updateTableByPk backendUpdate sourceInfo tableInfo updatePKName updatePKDesc
pure $ catMaybes [update, updateByPk]
where
updateDesc = buildFieldDescription defaultUpdateDesc $ _crfComment _tcrfUpdate
@ -231,22 +232,22 @@ buildTableUpdateMutationFields mkBackendUpdate sourceName tableName tableInfo gq
buildTableDeleteMutationFields ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableName b ->
TableInfo b ->
C.GQLNameIdentifier ->
m [FieldParser n (AnnDelG b (RemoteRelationshipField UnpreparedValue) (UnpreparedValue b))]
buildTableDeleteMutationFields sourceName tableName tableInfo gqlName = do
buildTableDeleteMutationFields sourceInfo tableName tableInfo gqlName = do
tCase <- asks getter
-- delete from table
deleteName <- mkRootFieldName $ setFieldNameCase tCase tableInfo _tcrfDelete mkDeleteField gqlName
-- delete from table by pk
deletePKName <- mkRootFieldName $ setFieldNameCase tCase tableInfo _tcrfDeleteByPk mkDeleteByPkField gqlName
delete <- deleteFromTable sourceName tableInfo deleteName deleteDesc
delete <- deleteFromTable sourceInfo tableInfo deleteName deleteDesc
-- Primary keys can only be tested in the `where` clause if the user has
-- select permissions for them, which at the very least requires select
-- permissions.
deleteByPk <- deleteFromTableByPk sourceName tableInfo deletePKName deletePKDesc
deleteByPk <- deleteFromTableByPk sourceInfo tableInfo deletePKName deletePKDesc
pure $ catMaybes [delete, deleteByPk]
where
deleteDesc = buildFieldDescription defaultDeleteDesc $ _crfComment _tcrfDelete
@ -258,12 +259,12 @@ buildTableDeleteMutationFields sourceName tableName tableInfo gqlName = do
buildFunctionQueryFieldsPG ::
forall r m n pgKind.
MonadBuildSchema ('Postgres pgKind) r m n =>
SourceName ->
SourceInfo ('Postgres pgKind) ->
FunctionName ('Postgres pgKind) ->
FunctionInfo ('Postgres pgKind) ->
TableName ('Postgres pgKind) ->
m [FieldParser n (QueryDB ('Postgres pgKind) (RemoteRelationshipField UnpreparedValue) (UnpreparedValue ('Postgres pgKind)))]
buildFunctionQueryFieldsPG sourceName functionName functionInfo tableName = do
buildFunctionQueryFieldsPG sourceInfo functionName functionInfo tableName = do
let -- select function
funcDesc =
Just . G.Description $
@ -279,24 +280,24 @@ buildFunctionQueryFieldsPG sourceName functionName functionInfo tableName = do
catMaybes
<$> sequenceA
[ optionalFieldParser (queryResultType) $ selectFunction sourceName functionInfo funcDesc,
optionalFieldParser (QDBAggregation) $ selectFunctionAggregate sourceName functionInfo funcAggDesc
[ optionalFieldParser (queryResultType) $ selectFunction sourceInfo functionInfo funcDesc,
optionalFieldParser (QDBAggregation) $ selectFunctionAggregate sourceInfo functionInfo funcAggDesc
]
buildFunctionMutationFieldsPG ::
forall r m n pgKind.
MonadBuildSchema ('Postgres pgKind) r m n =>
SourceName ->
SourceInfo ('Postgres pgKind) ->
FunctionName ('Postgres pgKind) ->
FunctionInfo ('Postgres pgKind) ->
TableName ('Postgres pgKind) ->
m [FieldParser n (MutationDB ('Postgres pgKind) (RemoteRelationshipField UnpreparedValue) (UnpreparedValue ('Postgres pgKind)))]
buildFunctionMutationFieldsPG sourceName functionName functionInfo tableName = do
buildFunctionMutationFieldsPG sourceInfo functionName functionInfo tableName = do
let funcDesc = Just $ G.Description $ "execute VOLATILE function " <> functionName <<> " which returns " <>> tableName
jsonAggSelect = _fiJsonAggSelect functionInfo
catMaybes
<$> sequenceA
[ optionalFieldParser (MDBFunction jsonAggSelect) $ selectFunction sourceName functionInfo funcDesc
[ optionalFieldParser (MDBFunction jsonAggSelect) $ selectFunction sourceInfo functionInfo funcDesc
-- TODO: do we want aggregate mutation functions?
]

View File

@ -1,7 +1,12 @@
{-# LANGUAGE TemplateHaskell #-}
module Hasura.GraphQL.Schema.Common
( MonadBuildSchemaBase,
( SchemaOptions (..),
SchemaContext (..),
RemoteRelationshipParserBuilder (..),
MonadBuildSchemaBase,
retrieve,
ignoreRemoteRelationship,
AggSelectExp,
AnnotatedField,
AnnotatedFields,
@ -10,7 +15,6 @@ module Hasura.GraphQL.Schema.Common
AnnotatedActionField,
AnnotatedActionFields,
EdgeFields,
QueryContext (..),
Scenario (..),
SelectArgs,
SelectStreamArgs,
@ -52,38 +56,94 @@ import Hasura.GraphQL.Namespace (NamespacedField)
import Hasura.GraphQL.Parser qualified as P
import Hasura.GraphQL.Parser.Constants qualified as G
import Hasura.Prelude
import Hasura.RQL.IR.Action qualified as IR
import Hasura.RQL.IR qualified as IR
import Hasura.RQL.IR.BoolExp
import Hasura.RQL.IR.RemoteSchema qualified as IR
import Hasura.RQL.IR.Root qualified as IR
import Hasura.RQL.IR.Select qualified as IR
import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.Column
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.Function
import Hasura.RQL.Types.Relationships.Remote
import Hasura.RQL.Types.RemoteSchema
import Hasura.RQL.Types.SchemaCache hiding (askTableInfo)
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization
import Hasura.SQL.AnyBackend qualified as AB
import Hasura.Session (RoleName)
import Language.GraphQL.Draft.Syntax as G
import Language.GraphQL.Draft.Syntax qualified as G
-- | the set of common constraints required to build the schema
-------------------------------------------------------------------------------
-- | Aggregation of options required to build the schema.
data SchemaOptions = SchemaOptions
{ -- | how numbers should be represented in the ouput; this option does not
-- influence the schema, but is bundled in the resulting IR
soStringifyNum :: StringifyNumbers,
-- | should boolean fields be collapsed to True when null is given?
soDangerousBooleanCollapse :: Bool,
-- | what kind of schema is being built (Hasura or Relay)
soQueryType :: ET.GraphQLQueryType,
-- | whether function permissions should be inferred
soFunctionPermsContext :: FunctionPermissionsCtx,
-- | whether remote schema permissions are enabled
soRemoteSchemaPermsCtx :: RemoteSchemaPermsCtx,
-- | 'True' when we should attempt to use experimental SQL optimization passes
soOptimizePermissionFilters :: Bool
}
-- | Aggregation of contextual information required to build the schema.
data SchemaContext = SchemaContext
{ -- | the set of all sources (TODO: remove this?)
scSourceCache :: SourceCache,
-- | how to process remote relationships
scRemoteRelationshipParserBuilder :: RemoteRelationshipParserBuilder
}
-- | The set of common constraints required to build the schema.
type MonadBuildSchemaBase r m n =
( MonadError QErr m,
MonadReader r m,
P.MonadSchema n m,
Has SchemaOptions r,
Has SchemaContext r,
-- TODO: make all `Has x r` explicit fields of 'SchemaContext'
Has RoleName r,
Has SourceCache r,
Has QueryContext r,
Has MkTypename r,
Has MkRootFieldName r,
Has CustomizeRemoteFieldName r,
Has RemoteSchemaMap r,
Has NamingCase r
)
-- | How a remote relationship field should be processed when building a
-- schema. Injecting this function from the top level avoids having to know how
-- to do top-level dispatch from deep within the schema code.
--
-- Note: the inner function type uses an existential qualifier: it is expected
-- that the given function will work for _any_ monad @m@ that has the relevant
-- constraints. This prevents us from passing a function that is specfic to the
-- monad in which the schema construction will run, but avoids having to
-- propagate type annotations to each call site.
newtype RemoteRelationshipParserBuilder
= RemoteRelationshipParserBuilder
( forall lhsJoinField r n m.
MonadBuildSchemaBase r m n =>
RemoteFieldInfo lhsJoinField ->
m (Maybe [P.FieldParser n (IR.RemoteRelationshipField P.UnpreparedValue)])
)
-- | A 'RemoteRelationshipParserBuilder' that ignores the field altogether, that can
-- be used in tests or to build a source or remote schema in isolation.
ignoreRemoteRelationship :: RemoteRelationshipParserBuilder
ignoreRemoteRelationship = RemoteRelationshipParserBuilder $ const $ pure Nothing
-- TODO: move this to Prelude?
retrieve ::
(MonadReader r m, Has a r) =>
(a -> b) ->
m b
retrieve f = asks $ f . getter
-------------------------------------------------------------------------------
type SelectExp b = IR.AnnSimpleSelectG b (IR.RemoteRelationshipField P.UnpreparedValue) (P.UnpreparedValue b)
type StreamSelectExp b = IR.AnnSimpleStreamSelectG b (IR.RemoteRelationshipField P.UnpreparedValue) (P.UnpreparedValue b)
@ -110,23 +170,14 @@ type AnnotatedActionFields = IR.ActionFieldsG (IR.RemoteRelationshipField P.Unpr
type AnnotatedActionField = IR.ActionFieldG (IR.RemoteRelationshipField P.UnpreparedValue)
-------------------------------------------------------------------------------
data RemoteSchemaParser n = RemoteSchemaParser
{ piQuery :: [P.FieldParser n (NamespacedField (IR.RemoteSchemaRootField (IR.RemoteRelationshipField P.UnpreparedValue) RemoteSchemaVariable))],
piMutation :: Maybe [P.FieldParser n (NamespacedField (IR.RemoteSchemaRootField (IR.RemoteRelationshipField P.UnpreparedValue) RemoteSchemaVariable))],
piSubscription :: Maybe [P.FieldParser n (NamespacedField (IR.RemoteSchemaRootField (IR.RemoteRelationshipField P.UnpreparedValue) RemoteSchemaVariable))]
}
data QueryContext = QueryContext
{ qcStringifyNum :: StringifyNumbers,
-- | should boolean fields be collapsed to True when null is given?
qcDangerousBooleanCollapse :: Bool,
qcQueryType :: ET.GraphQLQueryType,
qcFunctionPermsContext :: FunctionPermissionsCtx,
qcRemoteSchemaPermsCtx :: RemoteSchemaPermsCtx,
-- | 'True' when we should attempt to use experimental SQL optimization passes
qcOptimizePermissionFilters :: Bool
}
getTableRoles :: BackendSourceInfo -> [RoleName]
getTableRoles bsi = AB.dispatchAnyBackend @Backend bsi go
where
@ -137,19 +188,14 @@ getTableRoles bsi = AB.dispatchAnyBackend @Backend bsi go
-- supposed to ensure all dependencies are resolved.
-- TODO: deduplicate this with `CacheRM`.
askTableInfo ::
forall b r m.
(Backend b, MonadError QErr m, MonadReader r m, Has SourceCache r) =>
SourceName ->
forall b m.
(Backend b, MonadError QErr m) =>
SourceInfo b ->
TableName b ->
m (TableInfo b)
askTableInfo sourceName tableName = do
tableInfo <- asks $ getTableInfo . getter
-- This should never fail, since the schema cache construction process is
-- supposed to ensure that all dependencies are resolved.
tableInfo `onNothing` throw500 ("askTableInfo: no info for table " <> dquote tableName <> " in source " <> dquote sourceName)
where
getTableInfo :: SourceCache -> Maybe (TableInfo b)
getTableInfo = Map.lookup tableName <=< unsafeSourceTables <=< Map.lookup sourceName
askTableInfo SourceInfo {..} tableName =
Map.lookup tableName _siTables
`onNothing` throw500 ("askTableInfo: no info for table " <> dquote tableName <> " in source " <> dquote _siName)
-- | Whether the request is sent with `x-hasura-use-backend-only-permissions` set to `true`.
data Scenario = Backend | Frontend deriving (Enum, Show, Eq)
@ -197,7 +243,7 @@ numericAggOperators =
]
comparisonAggOperators :: [G.Name]
comparisonAggOperators = [$$(litName "max"), $$(litName "min")]
comparisonAggOperators = [$$(G.litName "max"), $$(G.litName "min")]
data NodeIdVersion
= NIVersion1

View File

@ -42,6 +42,7 @@ import Hasura.RQL.Types.Column
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.Relationships.Local
import Hasura.RQL.Types.SchemaCache hiding (askTableInfo)
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.Table
import Language.GraphQL.Draft.Syntax qualified as G
@ -56,9 +57,9 @@ import Language.GraphQL.Draft.Syntax qualified as G
insertIntoTable ::
forall b r m n.
MonadBuildSchema b r m n =>
(SourceName -> TableInfo b -> m (InputFieldsParser n (BackendInsert b (UnpreparedValue b)))) ->
(SourceInfo b -> TableInfo b -> m (InputFieldsParser n (BackendInsert b (UnpreparedValue b)))) ->
Scenario ->
SourceName ->
SourceInfo b ->
-- | qualified name of the table
TableInfo b ->
-- | field display name
@ -66,7 +67,7 @@ insertIntoTable ::
-- | field description, if any
Maybe G.Description ->
m (Maybe (FieldParser n (IR.AnnotatedInsert b (IR.RemoteRelationshipField UnpreparedValue) (UnpreparedValue b))))
insertIntoTable backendInsertAction scenario sourceName tableInfo fieldName description = runMaybeT $ do
insertIntoTable backendInsertAction scenario sourceInfo tableInfo fieldName description = runMaybeT $ do
let viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
guard $ isMutable viIsInsertable viewInfo
insertPerms <- MaybeT $ _permIns <$> tablePermissions tableInfo
@ -75,10 +76,10 @@ insertIntoTable backendInsertAction scenario sourceName tableInfo fieldName desc
lift do
updatePerms <- _permUpd <$> tablePermissions tableInfo
-- objects [{ ... }]
objectParser <- tableFieldsInput sourceName tableInfo
backendInsertParser <- backendInsertAction sourceName tableInfo
objectParser <- tableFieldsInput sourceInfo tableInfo
backendInsertParser <- backendInsertAction sourceInfo tableInfo
-- returning clause, affected rows, etc.
selectionParser <- mutationSelectionSet sourceName tableInfo
selectionParser <- mutationSelectionSet sourceInfo tableInfo
let argsParser = do
backendInsert <- backendInsertParser
objects <- mkObjectsArg objectParser
@ -101,10 +102,10 @@ insertIntoTable backendInsertAction scenario sourceName tableInfo fieldName desc
insertOneIntoTable ::
forall b r m n.
(MonadBuildSchema b r m n) =>
(SourceName -> TableInfo b -> m (InputFieldsParser n (BackendInsert b (UnpreparedValue b)))) ->
(SourceInfo b -> TableInfo b -> m (InputFieldsParser n (BackendInsert b (UnpreparedValue b)))) ->
Scenario ->
-- | source of the table
SourceName ->
SourceInfo b ->
-- | table info
TableInfo b ->
-- | field display name
@ -112,17 +113,17 @@ insertOneIntoTable ::
-- | field description, if any
Maybe G.Description ->
m (Maybe (FieldParser n (IR.AnnotatedInsert b (IR.RemoteRelationshipField UnpreparedValue) (UnpreparedValue b))))
insertOneIntoTable backendInsertAction scenario sourceName tableInfo fieldName description = runMaybeT do
insertOneIntoTable backendInsertAction scenario sourceInfo tableInfo fieldName description = runMaybeT do
let viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
guard $ isMutable viIsInsertable viewInfo
insertPerms <- MaybeT $ _permIns <$> tablePermissions tableInfo
-- If we're in a frontend scenario, we should not include backend_only inserts
guard $ not $ scenario == Frontend && ipiBackendOnly insertPerms
selectionParser <- MaybeT $ tableSelectionSet sourceName tableInfo
selectionParser <- MaybeT $ tableSelectionSet sourceInfo tableInfo
lift do
updatePerms <- _permUpd <$> tablePermissions tableInfo
objectParser <- tableFieldsInput sourceName tableInfo
backendInsertParser <- backendInsertAction sourceName tableInfo
objectParser <- tableFieldsInput sourceInfo tableInfo
backendInsertParser <- backendInsertAction sourceInfo tableInfo
let argsParser = do
backendInsert <- backendInsertParser
object <- mkObjectArg objectParser
@ -156,12 +157,12 @@ insertOneIntoTable backendInsertAction scenario sourceName tableInfo fieldName d
tableFieldsInput ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
-- | qualified name of the table
TableInfo b ->
m (Parser 'Input n (IR.AnnotatedInsertRow b (UnpreparedValue b)))
tableFieldsInput sourceName tableInfo =
memoizeOn 'tableFieldsInput (sourceName, tableName) do
tableFieldsInput sourceInfo tableInfo =
memoizeOn 'tableFieldsInput (_siName sourceInfo, tableName) do
tableGQLName <- getTableGQLName tableInfo
objectFields <- traverse mkFieldParser (Map.elems allFields)
objectName <- P.mkTypename $ tableGQLName <> G.__insert_input
@ -191,7 +192,7 @@ tableFieldsInput sourceName tableInfo =
if (_cmIsInsertable $ ciMutability columnInfo)
then mkColumnParser columnInfo
else pure Nothing
FIRelationship relInfo -> mkRelationshipParser sourceName relInfo
FIRelationship relInfo -> mkRelationshipParser sourceInfo relInfo
mkColumnParser ::
ColumnInfo b ->
@ -210,25 +211,25 @@ tableFieldsInput sourceName tableInfo =
mkDefaultRelationshipParser ::
forall b r m n.
MonadBuildSchema b r m n =>
(SourceName -> TableInfo b -> m (InputFieldsParser n (BackendInsert b (UnpreparedValue b)))) ->
(SourceInfo b -> TableInfo b -> m (InputFieldsParser n (BackendInsert b (UnpreparedValue b)))) ->
XNestedInserts b ->
SourceName ->
SourceInfo b ->
RelInfo b ->
m (Maybe (InputFieldsParser n (Maybe (IR.AnnotatedInsertField b (UnpreparedValue b)))))
mkDefaultRelationshipParser backendInsertAction xNestedInserts sourceName relationshipInfo = runMaybeT do
mkDefaultRelationshipParser backendInsertAction xNestedInserts sourceInfo relationshipInfo = runMaybeT do
let otherTableName = riRTable relationshipInfo
relName = riName relationshipInfo
otherTableInfo <- askTableInfo sourceName otherTableName
otherTableInfo <- askTableInfo sourceInfo otherTableName
relFieldName <- lift $ textToName $ relNameToTxt relName
case riType relationshipInfo of
ObjRel -> do
parser <- MaybeT $ objectRelationshipInput backendInsertAction sourceName otherTableInfo
parser <- MaybeT $ objectRelationshipInput backendInsertAction sourceInfo otherTableInfo
pure $
P.fieldOptional relFieldName Nothing (P.nullable parser) <&> \objRelIns -> do
rel <- join objRelIns
Just $ IR.AIObjectRelationship xNestedInserts $ IR.RelationInsert rel relationshipInfo
ArrRel -> do
parser <- MaybeT $ arrayRelationshipInput backendInsertAction sourceName otherTableInfo
parser <- MaybeT $ arrayRelationshipInput backendInsertAction sourceInfo otherTableInfo
pure $
P.fieldOptional relFieldName Nothing (P.nullable parser) <&> \arrRelIns -> do
rel <- join arrRelIns
@ -245,18 +246,18 @@ mkDefaultRelationshipParser backendInsertAction xNestedInserts sourceName relati
objectRelationshipInput ::
forall b r m n.
MonadBuildSchema b r m n =>
(SourceName -> TableInfo b -> m (InputFieldsParser n (BackendInsert b (UnpreparedValue b)))) ->
SourceName ->
(SourceInfo b -> TableInfo b -> m (InputFieldsParser n (BackendInsert b (UnpreparedValue b)))) ->
SourceInfo b ->
TableInfo b ->
m (Maybe (Parser 'Input n (IR.SingleObjectInsert b (UnpreparedValue b))))
objectRelationshipInput backendInsertAction sourceName tableInfo = runMaybeT $ do
objectRelationshipInput backendInsertAction sourceInfo tableInfo = runMaybeT $ do
insertPerms <- MaybeT $ _permIns <$> tablePermissions tableInfo
lift $ memoizeOn 'objectRelationshipInput (sourceName, tableName) do
lift $ memoizeOn 'objectRelationshipInput (_siName sourceInfo, tableName) do
updatePerms <- _permUpd <$> tablePermissions tableInfo
_selectPerms <- _permSel <$> tablePermissions tableInfo
tableGQLName <- getTableGQLName tableInfo
objectParser <- tableFieldsInput sourceName tableInfo
backendInsertParser <- backendInsertAction sourceName tableInfo
objectParser <- tableFieldsInput sourceInfo tableInfo
backendInsertParser <- backendInsertAction sourceInfo tableInfo
inputName <- P.mkTypename $ tableGQLName <> G.__obj_rel_insert_input
let objectName = G._data
inputDesc = G.Description $ "input type for inserting object relation for remote table " <>> tableName
@ -278,18 +279,18 @@ objectRelationshipInput backendInsertAction sourceName tableInfo = runMaybeT $ d
arrayRelationshipInput ::
forall b r m n.
MonadBuildSchema b r m n =>
(SourceName -> TableInfo b -> m (InputFieldsParser n (BackendInsert b (UnpreparedValue b)))) ->
SourceName ->
(SourceInfo b -> TableInfo b -> m (InputFieldsParser n (BackendInsert b (UnpreparedValue b)))) ->
SourceInfo b ->
TableInfo b ->
m (Maybe (Parser 'Input n (IR.MultiObjectInsert b (UnpreparedValue b))))
arrayRelationshipInput backendInsertAction sourceName tableInfo = runMaybeT $ do
arrayRelationshipInput backendInsertAction sourceInfo tableInfo = runMaybeT $ do
insertPerms <- MaybeT $ _permIns <$> tablePermissions tableInfo
lift $ memoizeOn 'arrayRelationshipInput (sourceName, tableName) do
lift $ memoizeOn 'arrayRelationshipInput (_siName sourceInfo, tableName) do
updatePerms <- _permUpd <$> tablePermissions tableInfo
_selectPerms <- _permSel <$> tablePermissions tableInfo
tableGQLName <- getTableGQLName tableInfo
objectParser <- tableFieldsInput sourceName tableInfo
backendInsertParser <- backendInsertAction sourceName tableInfo
objectParser <- tableFieldsInput sourceInfo tableInfo
backendInsertParser <- backendInsertAction sourceInfo tableInfo
inputName <- P.mkTypename $ tableGQLName <> G.__arr_rel_insert_input
let objectsName = G._data
inputDesc = G.Description $ "input type for inserting array relation for remote table " <>> tableName
@ -335,7 +336,7 @@ deleteFromTable ::
forall b r m n.
MonadBuildSchema b r m n =>
-- | table source
SourceName ->
SourceInfo b ->
-- | table info
TableInfo b ->
-- | field display name
@ -343,15 +344,15 @@ deleteFromTable ::
-- | field description, if any
Maybe G.Description ->
m (Maybe (FieldParser n (IR.AnnDelG b (IR.RemoteRelationshipField UnpreparedValue) (UnpreparedValue b))))
deleteFromTable sourceName tableInfo fieldName description = runMaybeT $ do
deleteFromTable sourceInfo tableInfo fieldName description = runMaybeT $ do
let viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
guard $ isMutable viIsInsertable viewInfo
deletePerms <- MaybeT $ _permDel <$> tablePermissions tableInfo
lift do
let whereName = G._where
whereDesc = "filter the rows which have to be deleted"
whereArg <- P.field whereName (Just whereDesc) <$> boolExp sourceName tableInfo
selection <- mutationSelectionSet sourceName tableInfo
whereArg <- P.field whereName (Just whereDesc) <$> boolExp sourceInfo tableInfo
selection <- mutationSelectionSet sourceInfo tableInfo
let columns = tableColumns tableInfo
pure $
P.subselection fieldName description whereArg selection
@ -364,7 +365,7 @@ deleteFromTableByPk ::
forall b r m n.
MonadBuildSchema b r m n =>
-- | table source
SourceName ->
SourceInfo b ->
-- | table info
TableInfo b ->
-- | field display name
@ -372,12 +373,12 @@ deleteFromTableByPk ::
-- | field description, if any
Maybe G.Description ->
m (Maybe (FieldParser n (IR.AnnDelG b (IR.RemoteRelationshipField UnpreparedValue) (UnpreparedValue b))))
deleteFromTableByPk sourceName tableInfo fieldName description = runMaybeT $ do
deleteFromTableByPk sourceInfo tableInfo fieldName description = runMaybeT $ do
let viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
guard $ isMutable viIsInsertable viewInfo
pkArgs <- MaybeT $ primaryKeysArguments tableInfo
deletePerms <- MaybeT $ _permDel <$> tablePermissions tableInfo
selection <- MaybeT $ tableSelectionSet sourceName tableInfo
selection <- MaybeT $ tableSelectionSet sourceInfo tableInfo
let columns = tableColumns tableInfo
pure $
P.subselection fieldName description pkArgs selection
@ -407,15 +408,15 @@ mkDeleteObject table columns deletePerms (whereExp, mutationOutput) =
mutationSelectionSet ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (Parser 'Output n (IR.MutFldsG b (IR.RemoteRelationshipField UnpreparedValue) (UnpreparedValue b)))
mutationSelectionSet sourceName tableInfo =
memoizeOn 'mutationSelectionSet (sourceName, tableName) do
mutationSelectionSet sourceInfo tableInfo =
memoizeOn 'mutationSelectionSet (_siName sourceInfo, tableName) do
tableGQLName <- getTableGQLName tableInfo
returning <- runMaybeT do
_permissions <- MaybeT $ tableSelectPermissions tableInfo
tableSet <- MaybeT $ tableSelectionList sourceName tableInfo
tableSet <- MaybeT $ tableSelectionList sourceInfo tableInfo
let returningName = G._returning
returningDesc = "data from the rows affected by the mutation"
pure $ IR.MRet <$> P.subselection_ returningName (Just returningDesc) tableSet

View File

@ -30,6 +30,7 @@ import Hasura.RQL.Types.ComputedField
import Hasura.RQL.Types.Function
import Hasura.RQL.Types.Relationships.Local
import Hasura.RQL.Types.SchemaCache hiding (askTableInfo)
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization
import Hasura.RQL.Types.Table
import Language.GraphQL.Draft.Syntax qualified as G
@ -57,17 +58,17 @@ orderByOperator tCase = case tCase of
orderByExp ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (Parser 'Input n [IR.AnnotatedOrderByItemG b (UnpreparedValue b)])
orderByExp sourceName tableInfo = memoizeOn 'orderByExp (sourceName, tableInfoName tableInfo) $ do
orderByExp sourceInfo tableInfo = memoizeOn 'orderByExp (_siName sourceInfo, tableInfoName tableInfo) $ do
tableGQLName <- getTableGQLName tableInfo
tCase <- asks getter
name <- P.mkTypename $ tableGQLName <> G.__order_by
let description =
G.Description $
"Ordering options when selecting data from " <> tableInfoName tableInfo <<> "."
tableFields <- tableSelectFields sourceName tableInfo
tableFields <- tableSelectFields sourceInfo tableInfo
fieldParsers <- sequenceA . catMaybes <$> traverse (mkField tCase) tableFields
pure $ concat . catMaybes <$> P.object name (Just description) fieldParsers
where
@ -86,19 +87,19 @@ orderByExp sourceName tableInfo = memoizeOn 'orderByExp (sourceName, tableInfoNa
(orderByOperator @b tCase)
<&> fmap (pure . mkOrderByItemG @b (IR.AOCColumn columnInfo)) . join
FIRelationship relationshipInfo -> do
remoteTableInfo <- askTableInfo @b sourceName $ riRTable relationshipInfo
remoteTableInfo <- askTableInfo sourceInfo $ riRTable relationshipInfo
fieldName <- hoistMaybe $ G.mkName $ relNameToTxt $ riName relationshipInfo
perms <- MaybeT $ tableSelectPermissions remoteTableInfo
let newPerms = fmap partialSQLExpToUnpreparedValue <$> spiFilter perms
case riType relationshipInfo of
ObjRel -> do
otherTableParser <- lift $ orderByExp sourceName remoteTableInfo
otherTableParser <- lift $ orderByExp sourceInfo remoteTableInfo
pure $ do
otherTableOrderBy <- join <$> P.fieldOptional fieldName Nothing (P.nullable otherTableParser)
pure $ fmap (map $ fmap $ IR.AOCObjectRelation relationshipInfo newPerms) otherTableOrderBy
ArrRel -> do
let aggregateFieldName = fieldName <> G.__aggregate
aggregationParser <- lift $ orderByAggregation sourceName remoteTableInfo
aggregationParser <- lift $ orderByAggregation sourceInfo remoteTableInfo
pure $ do
aggregationOrderBy <- join <$> P.fieldOptional aggregateFieldName Nothing (P.nullable aggregationParser)
pure $ fmap (map $ fmap $ IR.AOCArrayAggregation relationshipInfo newPerms) aggregationOrderBy
@ -122,10 +123,10 @@ orderByExp sourceName tableInfo = memoizeOn 'orderByExp (sourceName, tableInfoNa
<&> fmap (pure . mkOrderByItemG @b (IR.AOCComputedField computedFieldOrderBy)) . join
ReturnsTable table -> do
let aggregateFieldName = fieldName <> G.__aggregate
tableInfo' <- askTableInfo @b sourceName table
tableInfo' <- askTableInfo sourceInfo table
perms <- MaybeT $ tableSelectPermissions tableInfo'
let newPerms = fmap partialSQLExpToUnpreparedValue <$> spiFilter perms
aggregationParser <- lift $ orderByAggregation sourceName tableInfo'
aggregationParser <- lift $ orderByAggregation sourceInfo tableInfo'
pure $ do
aggregationOrderBy <- join <$> P.fieldOptional aggregateFieldName Nothing (P.nullable aggregationParser)
pure $
@ -147,17 +148,17 @@ orderByExp sourceName tableInfo = memoizeOn 'orderByExp (sourceName, tableInfoNa
orderByAggregation ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (Parser 'Input n [IR.OrderByItemG b (IR.AnnotatedAggregateOrderBy b)])
orderByAggregation sourceName tableInfo = memoizeOn 'orderByAggregation (sourceName, tableName) do
orderByAggregation sourceInfo tableInfo = memoizeOn 'orderByAggregation (_siName sourceInfo, tableName) do
-- WIP NOTE
-- there is heavy duplication between this and Select.tableAggregationFields
-- it might be worth putting some of it in common, just to avoid issues when
-- we change one but not the other?
tableGQLName <- getTableGQLName @b tableInfo
tCase <- asks getter
allColumns <- tableSelectColumns sourceName tableInfo
allColumns <- tableSelectColumns sourceInfo tableInfo
mkTypename <- asks getter
let numColumns = onlyNumCols allColumns
compColumns = onlyComparableCols allColumns

View File

@ -1,5 +1,5 @@
{-# LANGUAGE RecursiveDo #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TemplateHaskellQuotes #-}
{-# LANGUAGE ViewPatterns #-}
module Hasura.GraphQL.Schema.Remote
@ -25,7 +25,6 @@ import Hasura.GraphQL.Parser.Constants qualified as G
import Hasura.GraphQL.Parser.Internal.Parser qualified as P
import Hasura.GraphQL.Parser.Internal.TypeChecking qualified as P
import Hasura.GraphQL.Schema.Common
import {-# SOURCE #-} Hasura.GraphQL.Schema.RemoteRelationship
import Hasura.Prelude
import Hasura.RQL.IR.RemoteSchema qualified as IR
import Hasura.RQL.IR.Root qualified as IR
@ -565,6 +564,7 @@ remoteSchemaRelationships relationships typeName =
Nothing -> pure []
Just rels ->
concat <$> for (toList rels) \remoteFieldInfo -> do
RemoteRelationshipParserBuilder remoteRelationshipField <- retrieve scRemoteRelationshipParserBuilder
relationshipFields <- fromMaybe [] <$> remoteRelationshipField remoteFieldInfo
let lhsFields = _rfiLHS remoteFieldInfo
pure $ map (fmap (IR.SchemaRemoteRelationshipSelect lhsFields)) relationshipFields

View File

@ -30,6 +30,7 @@ import Hasura.RQL.Types.Relationships.ToSchema qualified as Remote
import Hasura.RQL.Types.RemoteSchema
import Hasura.RQL.Types.ResultCustomization
import Hasura.RQL.Types.SchemaCache hiding (askTableInfo)
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization (NamingCase (..), mkCustomizedTypename)
import Hasura.SQL.AnyBackend
import Hasura.Session
@ -37,34 +38,34 @@ import Language.GraphQL.Draft.Syntax qualified as G
-- | Remote relationship field parsers
remoteRelationshipField ::
forall r m n lhsJoinField.
(MonadBuildSchemaBase r m n) =>
RemoteFieldInfo lhsJoinField ->
m (Maybe [FieldParser n (IR.RemoteRelationshipField UnpreparedValue)])
remoteRelationshipField RemoteFieldInfo {..} = runMaybeT do
queryType <- asks $ qcQueryType . getter
-- https://github.com/hasura/graphql-engine/issues/5144
-- The above issue is easily fixable by removing the following guard
guard $ queryType == ET.QueryHasura
case _rfiRHS of
RFISource anyRemoteSourceFieldInfo ->
dispatchAnyBackend @BackendSchema anyRemoteSourceFieldInfo \remoteSourceFieldInfo -> do
fields <- lift $ remoteRelationshipToSourceField remoteSourceFieldInfo
pure $ fmap (IR.RemoteSourceField . mkAnyBackend) <$> fields
RFISchema remoteSchema -> do
fields <- MaybeT $ remoteRelationshipToSchemaField _rfiLHS remoteSchema
pure $ pure $ IR.RemoteSchemaField <$> fields
SourceCache ->
RemoteSchemaMap ->
RemoteRelationshipParserBuilder
remoteRelationshipField sourceCache remoteSchemaCache = RemoteRelationshipParserBuilder
\RemoteFieldInfo {..} -> runMaybeT do
queryType <- retrieve soQueryType
-- https://github.com/hasura/graphql-engine/issues/5144
-- The above issue is easily fixable by removing the following guard
guard $ queryType == ET.QueryHasura
case _rfiRHS of
RFISource anyRemoteSourceFieldInfo ->
dispatchAnyBackend @BackendSchema anyRemoteSourceFieldInfo \remoteSourceFieldInfo -> do
fields <- lift $ remoteRelationshipToSourceField sourceCache remoteSourceFieldInfo
pure $ fmap (IR.RemoteSourceField . mkAnyBackend) <$> fields
RFISchema remoteSchema -> do
fields <- MaybeT $ remoteRelationshipToSchemaField remoteSchemaCache _rfiLHS remoteSchema
pure $ pure $ IR.RemoteSchemaField <$> fields
-- | Parser(s) for remote relationship fields to a remote schema
remoteRelationshipToSchemaField ::
forall r m n lhsJoinField.
(MonadBuildSchemaBase r m n) =>
RemoteSchemaMap ->
Map.HashMap FieldName lhsJoinField ->
RemoteSchemaFieldInfo ->
m (Maybe (FieldParser n (IR.RemoteSchemaSelect (IR.RemoteRelationshipField UnpreparedValue))))
remoteRelationshipToSchemaField lhsFields RemoteSchemaFieldInfo {..} = runMaybeT do
remoteSchemaCache <- asks getter
remoteSchemaPermsCtx <- asks $ qcRemoteSchemaPermsCtx . getter
remoteRelationshipToSchemaField remoteSchemaCache lhsFields RemoteSchemaFieldInfo {..} = runMaybeT do
remoteSchemaPermsCtx <- retrieve soRemoteSchemaPermsCtx
roleName <- asks getter
remoteSchemaContext <-
Map.lookup _rrfiRemoteSchemaName remoteSchemaCache
@ -173,11 +174,15 @@ lookupNestedFieldType parentTypeName remoteSchemaIntrospection (fieldCall :| res
remoteRelationshipToSourceField ::
forall r m n tgt.
(MonadBuildSchemaBase r m n, BackendSchema tgt) =>
SourceCache ->
RemoteSourceFieldInfo tgt ->
m [FieldParser n (IR.RemoteSourceSelect (IR.RemoteRelationshipField UnpreparedValue) UnpreparedValue tgt)]
remoteRelationshipToSourceField RemoteSourceFieldInfo {..} =
remoteRelationshipToSourceField sourceCache RemoteSourceFieldInfo {..} =
withTypenameCustomization (mkCustomizedTypename (Just _rsfiSourceCustomization) HasuraCase) do
tableInfo <- askTableInfo @tgt _rsfiSource _rsfiTable
sourceInfo <-
onNothing (unsafeSourceInfo @tgt =<< Map.lookup _rsfiSource sourceCache) $
throw500 $ "source not found " <> dquote _rsfiSource
tableInfo <- askTableInfo sourceInfo _rsfiTable
fieldName <- textToName $ relNameToTxt _rsfiName
maybePerms <- tableSelectPermissions @tgt tableInfo
case maybePerms of
@ -185,7 +190,7 @@ remoteRelationshipToSourceField RemoteSourceFieldInfo {..} =
Just tablePerms -> do
parsers <- case _rsfiType of
ObjRel -> do
selectionSetParserM <- tableSelectionSet _rsfiSource tableInfo
selectionSetParserM <- tableSelectionSet sourceInfo tableInfo
pure $ case selectionSetParserM of
Nothing -> []
Just selectionSetParser ->
@ -195,8 +200,8 @@ remoteRelationshipToSourceField RemoteSourceFieldInfo {..} =
IR.AnnObjectSelectG fields _rsfiTable $ IR._tpFilter $ tablePermissionsInfo tablePerms
ArrRel -> do
let aggFieldName = fieldName <> G.__aggregate
selectionSetParser <- selectTable _rsfiSource tableInfo fieldName Nothing
aggSelectionSetParser <- selectTableAggregate _rsfiSource tableInfo aggFieldName Nothing
selectionSetParser <- selectTable sourceInfo tableInfo fieldName Nothing
aggSelectionSetParser <- selectTableAggregate sourceInfo tableInfo aggFieldName Nothing
pure $
catMaybes
[ selectionSetParser <&> fmap IR.SourceRelationshipArray,

View File

@ -1,16 +0,0 @@
module Hasura.GraphQL.Schema.RemoteRelationship
( remoteRelationshipField,
)
where
import Hasura.GraphQL.Parser
import Hasura.GraphQL.Schema.Common
import Hasura.Prelude
import Hasura.RQL.IR.Root qualified as IR
import Hasura.RQL.Types.Relationships.Remote
remoteRelationshipField ::
forall r m n lhsJoinField.
(MonadBuildSchemaBase r m n) =>
RemoteFieldInfo lhsJoinField ->
m (Maybe [FieldParser n (IR.RemoteRelationshipField UnpreparedValue)])

View File

@ -15,7 +15,6 @@ module Hasura.GraphQL.Schema.Select
selectFunctionAggregate,
selectFunctionConnection,
computedFieldPG,
remoteRelationshipField,
defaultTableArgs,
tableWhereArg,
tableOrderByArg,
@ -68,7 +67,6 @@ import Hasura.GraphQL.Schema.Backend
import Hasura.GraphQL.Schema.BoolExp
import Hasura.GraphQL.Schema.Common
import Hasura.GraphQL.Schema.OrderBy
import {-# SOURCE #-} Hasura.GraphQL.Schema.RemoteRelationship
import Hasura.GraphQL.Schema.Table
import Hasura.Prelude
import Hasura.RQL.IR qualified as IR
@ -108,7 +106,7 @@ import Language.GraphQL.Draft.Syntax qualified as G
selectTable ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
-- | table info
TableInfo b ->
-- | field display name
@ -116,12 +114,12 @@ selectTable ::
-- | field description, if any
Maybe G.Description ->
m (Maybe (FieldParser n (SelectExp b)))
selectTable sourceName tableInfo fieldName description = runMaybeT do
selectTable sourceInfo tableInfo fieldName description = runMaybeT do
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
selectionSetParser <- MaybeT $ tableSelectionList sourceName tableInfo
lift $ memoizeOn 'selectTable (sourceName, tableName, fieldName) do
stringifyNum <- asks $ qcStringifyNum . getter
tableArgsParser <- tableArguments sourceName tableInfo
selectionSetParser <- MaybeT $ tableSelectionList sourceInfo tableInfo
lift $ memoizeOn 'selectTable (_siName sourceInfo, tableName, fieldName) do
stringifyNum <- retrieve soStringifyNum
tableArgsParser <- tableArguments sourceInfo tableInfo
pure $
P.subselection fieldName description tableArgsParser selectionSetParser
<&> \(args, fields) ->
@ -157,7 +155,7 @@ selectTable sourceName tableInfo fieldName description = runMaybeT do
selectTableConnection ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
-- | table info
TableInfo b ->
-- | field display name
@ -167,13 +165,13 @@ selectTableConnection ::
-- | primary key columns
PrimaryKeyColumns b ->
m (Maybe (FieldParser n (ConnectionSelectExp b)))
selectTableConnection sourceName tableInfo fieldName description pkeyColumns = runMaybeT do
selectTableConnection sourceInfo tableInfo fieldName description pkeyColumns = runMaybeT do
xRelayInfo <- hoistMaybe $ relayExtension @b
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
selectionSetParser <- fmap P.nonNullableParser <$> MaybeT $ tableConnectionSelectionSet sourceName tableInfo
lift $ memoizeOn 'selectTableConnection (sourceName, tableName, fieldName) do
stringifyNum <- asks $ qcStringifyNum . getter
selectArgsParser <- tableConnectionArgs pkeyColumns sourceName tableInfo
selectionSetParser <- fmap P.nonNullableParser <$> MaybeT $ tableConnectionSelectionSet sourceInfo tableInfo
lift $ memoizeOn 'selectTableConnection (_siName sourceInfo, tableName, fieldName) do
stringifyNum <- retrieve soStringifyNum
selectArgsParser <- tableConnectionArgs pkeyColumns sourceInfo tableInfo
pure $
P.subselection fieldName description selectArgsParser selectionSetParser
<&> \((args, split, slice), fields) ->
@ -207,7 +205,7 @@ selectTableConnection sourceName tableInfo fieldName description pkeyColumns = r
selectTableByPk ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
-- | table info
TableInfo b ->
-- | field display name
@ -215,13 +213,13 @@ selectTableByPk ::
-- | field description, if any
Maybe G.Description ->
m (Maybe (FieldParser n (SelectExp b)))
selectTableByPk sourceName tableInfo fieldName description = runMaybeT do
selectTableByPk sourceInfo tableInfo fieldName description = runMaybeT do
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
primaryKeys <- hoistMaybe $ fmap _pkColumns . _tciPrimaryKey . _tiCoreInfo $ tableInfo
selectionSetParser <- MaybeT $ tableSelectionSet sourceName tableInfo
selectionSetParser <- MaybeT $ tableSelectionSet sourceInfo tableInfo
guard $ all (\c -> ciColumn c `Map.member` spiCols selectPermissions) primaryKeys
lift $ memoizeOn 'selectTableByPk (sourceName, tableName, fieldName) do
stringifyNum <- asks $ qcStringifyNum . getter
lift $ memoizeOn 'selectTableByPk (_siName sourceInfo, tableName, fieldName) do
stringifyNum <- retrieve soStringifyNum
argsParser <-
sequenceA <$> for primaryKeys \columnInfo -> do
field <- columnParser (ciType columnInfo) (G.Nullability $ ciIsNullable columnInfo)
@ -258,7 +256,7 @@ selectTableByPk sourceName tableInfo fieldName description = runMaybeT do
selectTableAggregate ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
-- | table info
TableInfo b ->
-- | field display name
@ -266,16 +264,16 @@ selectTableAggregate ::
-- | field description, if any
Maybe G.Description ->
m (Maybe (FieldParser n (AggSelectExp b)))
selectTableAggregate sourceName tableInfo fieldName description = runMaybeT $ do
selectTableAggregate sourceInfo tableInfo fieldName description = runMaybeT $ do
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
guard $ spiAllowAgg selectPermissions
xNodesAgg <- hoistMaybe $ nodesAggExtension @b
nodesParser <- MaybeT $ tableSelectionList sourceName tableInfo
lift $ memoizeOn 'selectTableAggregate (sourceName, tableName, fieldName) do
stringifyNum <- asks $ qcStringifyNum . getter
nodesParser <- MaybeT $ tableSelectionList sourceInfo tableInfo
lift $ memoizeOn 'selectTableAggregate (_siName sourceInfo, tableName, fieldName) do
stringifyNum <- retrieve soStringifyNum
tableGQLName <- getTableGQLName tableInfo
tableArgsParser <- tableArguments sourceName tableInfo
aggregateParser <- tableAggregationFields sourceName tableInfo
tableArgsParser <- tableArguments sourceInfo tableInfo
aggregateParser <- tableAggregationFields sourceInfo tableInfo
selectionName <- P.mkTypename $ tableGQLName <> G.__aggregate
let aggregationParser =
P.nonNullableParser $
@ -364,12 +362,12 @@ cause errors on the client side, for the following reasons:
tableSelectionSet ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (Maybe (Parser 'Output n (AnnotatedFields b)))
tableSelectionSet sourceName tableInfo = runMaybeT do
tableSelectionSet sourceInfo tableInfo = runMaybeT do
_selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
lift $ memoizeOn 'tableSelectionSet (sourceName, tableName) do
lift $ memoizeOn 'tableSelectionSet (_siName sourceInfo, tableName) do
tableGQLName <- getTableGQLName tableInfo
objectTypename <- P.mkTypename tableGQLName
let xRelay = relayExtension @b
@ -380,7 +378,7 @@ tableSelectionSet sourceName tableInfo = runMaybeT do
concat
<$> for
tableFields
(fieldSelection sourceName tableName tableInfo tablePkeyColumns)
(fieldSelection sourceInfo tableName tableInfo tablePkeyColumns)
-- We don't check *here* that the subselection set is non-empty,
-- even though the GraphQL specification requires that it is (see
@ -390,7 +388,7 @@ tableSelectionSet sourceName tableInfo = runMaybeT do
-- required, meaning that not having this check here does not allow
-- for the construction of invalid queries.
queryType <- asks $ qcQueryType . getter
queryType <- retrieve soQueryType
case (queryType, tablePkeyColumns, xRelay) of
-- A relay table
(ET.QueryRelay, Just pkeyColumns, Just xRelayInfo) -> do
@ -414,11 +412,11 @@ tableSelectionSet sourceName tableInfo = runMaybeT do
-- > table_name: [table!]!
tableSelectionList ::
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (Maybe (Parser 'Output n (AnnotatedFields b)))
tableSelectionList sourceName tableInfo =
fmap nonNullableObjectList <$> tableSelectionSet sourceName tableInfo
tableSelectionList sourceInfo tableInfo =
fmap nonNullableObjectList <$> tableSelectionSet sourceInfo tableInfo
-- | Converts an output type parser from object_type to [object_type!]!
nonNullableObjectList :: Parser 'Output m a -> Parser 'Output m a
@ -446,14 +444,14 @@ nonNullableObjectList =
tableConnectionSelectionSet ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (Maybe (Parser 'Output n (ConnectionFields b)))
tableConnectionSelectionSet sourceName tableInfo = runMaybeT do
tableConnectionSelectionSet sourceInfo tableInfo = runMaybeT do
tableGQLName <- lift $ getTableGQLName tableInfo
_selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
edgesParser <- MaybeT $ tableEdgesSelectionSet tableGQLName
lift $ memoizeOn 'tableConnectionSelectionSet (sourceName, tableName) do
lift $ memoizeOn 'tableConnectionSelectionSet (_siName sourceInfo, tableName) do
connectionTypeName <- P.mkTypename $ tableGQLName <> G._Connection
let pageInfo =
P.subselection_
@ -514,7 +512,7 @@ tableConnectionSelectionSet sourceName tableInfo = runMaybeT do
tableEdgesSelectionSet ::
G.Name -> m (Maybe (Parser 'Output n (EdgeFields b)))
tableEdgesSelectionSet tableGQLName = runMaybeT do
edgeNodeParser <- MaybeT $ fmap P.nonNullableParser <$> tableSelectionSet sourceName tableInfo
edgeNodeParser <- MaybeT $ fmap P.nonNullableParser <$> tableSelectionSet sourceInfo tableInfo
edgesType <- lift $ P.mkTypename $ tableGQLName <> G._Edge
let cursor =
P.selection_
@ -538,20 +536,20 @@ selectFunction ::
forall r m n pgKind.
MonadBuildSchema ('Postgres pgKind) r m n =>
-- | source name
SourceName ->
SourceInfo ('Postgres pgKind) ->
-- | SQL function info
FunctionInfo ('Postgres pgKind) ->
-- | field description, if any
Maybe G.Description ->
m (Maybe (FieldParser n (SelectExp ('Postgres pgKind))))
selectFunction sourceName fi@FunctionInfo {..} description = runMaybeT do
tableInfo <- lift $ askTableInfo sourceName _fiReturnType
selectFunction sourceInfo fi@FunctionInfo {..} description = runMaybeT do
tableInfo <- lift $ askTableInfo sourceInfo _fiReturnType
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
selectionSetParser <- MaybeT $ returnFunctionParser sourceName tableInfo
selectionSetParser <- MaybeT $ returnFunctionParser sourceInfo tableInfo
lift do
stringifyNum <- asks $ qcStringifyNum . getter
tableArgsParser <- tableArguments sourceName tableInfo
functionArgsParser <- customSQLFunctionArgs fi _fiGQLName _fiGQLArgsName
stringifyNum <- retrieve soStringifyNum
tableArgsParser <- tableArguments sourceInfo tableInfo
functionArgsParser <- customSQLFunctionArgs sourceInfo fi _fiGQLName _fiGQLArgsName
let argsParser = liftA2 (,) functionArgsParser tableArgsParser
functionFieldName <- mkRootFieldName _fiGQLName
pure $
@ -574,25 +572,25 @@ selectFunctionAggregate ::
forall r m n pgKind.
MonadBuildSchema ('Postgres pgKind) r m n =>
-- | source name
SourceName ->
SourceInfo ('Postgres pgKind) ->
-- | SQL function info
FunctionInfo ('Postgres pgKind) ->
-- | field description, if any
Maybe G.Description ->
m (Maybe (FieldParser n (AggSelectExp ('Postgres pgKind))))
selectFunctionAggregate sourceName fi@FunctionInfo {..} description = runMaybeT do
targetTableInfo <- askTableInfo sourceName _fiReturnType
selectFunctionAggregate sourceInfo fi@FunctionInfo {..} description = runMaybeT do
targetTableInfo <- askTableInfo sourceInfo _fiReturnType
selectPermissions <- MaybeT $ tableSelectPermissions targetTableInfo
guard $ spiAllowAgg selectPermissions
xNodesAgg <- hoistMaybe $ nodesAggExtension @('Postgres pgKind)
tableInfo <- askTableInfo sourceName _fiReturnType
nodesParser <- MaybeT $ tableSelectionList sourceName tableInfo
tableInfo <- askTableInfo sourceInfo _fiReturnType
nodesParser <- MaybeT $ tableSelectionList sourceInfo tableInfo
lift do
stringifyNum <- asks $ qcStringifyNum . getter
stringifyNum <- retrieve soStringifyNum
tableGQLName <- getTableGQLName tableInfo
tableArgsParser <- tableArguments sourceName tableInfo
functionArgsParser <- customSQLFunctionArgs fi _fiGQLAggregateName _fiGQLArgsName
aggregateParser <- tableAggregationFields sourceName tableInfo
tableArgsParser <- tableArguments sourceInfo tableInfo
functionArgsParser <- customSQLFunctionArgs sourceInfo fi _fiGQLAggregateName _fiGQLArgsName
aggregateParser <- tableAggregationFields sourceInfo tableInfo
selectionName <- P.mkTypename =<< pure (tableGQLName <> G.__aggregate)
aggregateFieldName <- mkRootFieldName _fiGQLAggregateName
let argsParser = liftA2 (,) functionArgsParser tableArgsParser
@ -620,7 +618,7 @@ selectFunctionConnection ::
forall pgKind r m n.
MonadBuildSchema ('Postgres pgKind) r m n =>
-- | source name
SourceName ->
SourceInfo ('Postgres pgKind) ->
-- | SQL function info
FunctionInfo ('Postgres pgKind) ->
-- | field description, if any
@ -628,17 +626,17 @@ selectFunctionConnection ::
-- | primary key columns of the target table
PrimaryKeyColumns ('Postgres pgKind) ->
m (Maybe (FieldParser n (ConnectionSelectExp ('Postgres pgKind))))
selectFunctionConnection sourceName fi@FunctionInfo {..} description pkeyColumns = runMaybeT do
returnTableInfo <- lift $ askTableInfo sourceName _fiReturnType
selectFunctionConnection sourceInfo fi@FunctionInfo {..} description pkeyColumns = runMaybeT do
returnTableInfo <- lift $ askTableInfo sourceInfo _fiReturnType
selectPermissions <- MaybeT $ tableSelectPermissions returnTableInfo
xRelayInfo <- hoistMaybe $ relayExtension @('Postgres pgKind)
tableInfo <- lift $ askTableInfo sourceName _fiReturnType
selectionSetParser <- MaybeT $ tableConnectionSelectionSet sourceName tableInfo
tableInfo <- lift $ askTableInfo sourceInfo _fiReturnType
selectionSetParser <- MaybeT $ tableConnectionSelectionSet sourceInfo tableInfo
lift do
fieldName <- mkRootFieldName $ _fiGQLName <> G.__connection
stringifyNum <- asks $ qcStringifyNum . getter
tableConnectionArgsParser <- tableConnectionArgs pkeyColumns sourceName tableInfo
functionArgsParser <- customSQLFunctionArgs fi _fiGQLName _fiGQLArgsName
stringifyNum <- retrieve soStringifyNum
tableConnectionArgsParser <- tableConnectionArgs pkeyColumns sourceInfo tableInfo
functionArgsParser <- customSQLFunctionArgs sourceInfo fi _fiGQLName _fiGQLArgsName
let argsParser = liftA2 (,) functionArgsParser tableConnectionArgsParser
pure $
P.subselection fieldName description argsParser selectionSetParser
@ -673,13 +671,13 @@ selectFunctionConnection sourceName fi@FunctionInfo {..} description pkeyColumns
defaultTableArgs ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (InputFieldsParser n (SelectArgs b))
defaultTableArgs sourceName tableInfo = do
whereParser <- tableWhereArg sourceName tableInfo
orderByParser <- tableOrderByArg sourceName tableInfo
distinctParser <- tableDistinctArg sourceName tableInfo
defaultTableArgs sourceInfo tableInfo = do
whereParser <- tableWhereArg sourceInfo tableInfo
orderByParser <- tableOrderByArg sourceInfo tableInfo
distinctParser <- tableDistinctArg sourceInfo tableInfo
let result = do
whereArg <- whereParser
orderByArg <- orderByParser
@ -721,11 +719,11 @@ defaultTableArgs sourceName tableInfo = do
tableWhereArg ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (InputFieldsParser n (Maybe (IR.AnnBoolExp b (UnpreparedValue b))))
tableWhereArg sourceName tableInfo = do
boolExpParser <- boolExp sourceName tableInfo
tableWhereArg sourceInfo tableInfo = do
boolExpParser <- boolExp sourceInfo tableInfo
pure $
fmap join $
P.fieldOptional whereName whereDesc $
@ -739,12 +737,12 @@ tableWhereArg sourceName tableInfo = do
tableOrderByArg ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (InputFieldsParser n (Maybe (NonEmpty (IR.AnnotatedOrderByItemG b (UnpreparedValue b)))))
tableOrderByArg sourceName tableInfo = do
tableOrderByArg sourceInfo tableInfo = do
tCase <- asks getter
orderByParser <- orderByExp sourceName tableInfo
orderByParser <- orderByExp sourceInfo tableInfo
let orderByName = applyFieldNameCaseCust tCase G._order_by
orderByDesc = Just $ G.Description "sort the rows by one or more columns"
pure $ do
@ -758,12 +756,12 @@ tableOrderByArg sourceName tableInfo = do
tableDistinctArg ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (InputFieldsParser n (Maybe (NonEmpty (Column b))))
tableDistinctArg sourceName tableInfo = do
tableDistinctArg sourceInfo tableInfo = do
tCase <- asks getter
columnsEnum <- tableSelectColumnsEnum sourceName tableInfo
columnsEnum <- tableSelectColumnsEnum sourceInfo tableInfo
let distinctOnName = applyFieldNameCaseCust tCase G._distinct_on
distinctOnDesc = Just $ G.Description "distinct select on columns"
pure do
@ -815,7 +813,7 @@ tableConnectionArgs ::
forall b r m n.
MonadBuildSchema b r m n =>
PrimaryKeyColumns b ->
SourceName ->
SourceInfo b ->
TableInfo b ->
m
( InputFieldsParser
@ -825,10 +823,10 @@ tableConnectionArgs ::
Maybe IR.ConnectionSlice
)
)
tableConnectionArgs pkeyColumns sourceName tableInfo = do
whereParser <- tableWhereArg sourceName tableInfo
orderByParser <- fmap (fmap appendPrimaryKeyOrderBy) <$> tableOrderByArg sourceName tableInfo
distinctParser <- tableDistinctArg sourceName tableInfo
tableConnectionArgs pkeyColumns sourceInfo tableInfo = do
whereParser <- tableWhereArg sourceInfo tableInfo
orderByParser <- fmap (fmap appendPrimaryKeyOrderBy) <$> tableOrderByArg sourceInfo tableInfo
distinctParser <- tableDistinctArg sourceInfo tableInfo
let maybeFirst = fmap join $ P.fieldOptional G._first Nothing $ P.nullable P.nonNegativeInt
maybeLast = fmap join $ P.fieldOptional G._last Nothing $ P.nullable P.nonNegativeInt
maybeAfter = fmap join $ P.fieldOptional G._after Nothing $ P.nullable base64Text
@ -960,45 +958,46 @@ tableConnectionArgs pkeyColumns sourceName tableInfo = do
tableAggregationFields ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (Parser 'Output n (IR.AggregateFields b))
tableAggregationFields sourceName tableInfo = memoizeOn 'tableAggregationFields (sourceName, tableInfoName tableInfo) do
tableGQLName <- getTableGQLName tableInfo
allColumns <- tableSelectColumns sourceName tableInfo
tCase <- asks getter
let numericColumns = onlyNumCols allColumns
comparableColumns = onlyComparableCols allColumns
description = G.Description $ "aggregate fields of " <>> tableInfoName tableInfo
selectName <- P.mkTypename $ tableGQLName <> G.__aggregate_fields
count <- countField
mkTypename <- asks getter
numericAndComparable <-
fmap concat $
sequenceA $
catMaybes
[ -- operators on numeric columns
if null numericColumns
then Nothing
else Just $
for numericAggOperators $ \operator -> do
let fieldNameCase = applyFieldNameCaseCust tCase operator
numFields <- mkNumericAggFields operator numericColumns
pure $ parseAggOperator mkTypename operator fieldNameCase tableGQLName numFields,
-- operators on comparable columns
if null comparableColumns
then Nothing
else Just $ do
comparableFields <- traverse mkColumnAggField comparableColumns
pure $
comparisonAggOperators & map \operator ->
tableAggregationFields sourceInfo tableInfo =
memoizeOn 'tableAggregationFields (_siName sourceInfo, tableInfoName tableInfo) do
tableGQLName <- getTableGQLName tableInfo
tCase <- asks getter
allColumns <- tableSelectColumns sourceInfo tableInfo
let numericColumns = onlyNumCols allColumns
comparableColumns = onlyComparableCols allColumns
description = G.Description $ "aggregate fields of " <>> tableInfoName tableInfo
selectName <- P.mkTypename $ tableGQLName <> G.__aggregate_fields
count <- countField
mkTypename <- asks getter
numericAndComparable <-
fmap concat $
sequenceA $
catMaybes
[ -- operators on numeric columns
if null numericColumns
then Nothing
else Just $
for numericAggOperators $ \operator -> do
let fieldNameCase = applyFieldNameCaseCust tCase operator
in parseAggOperator mkTypename operator fieldNameCase tableGQLName comparableFields
]
let aggregateFields = count : numericAndComparable
pure $
P.selectionSet selectName (Just description) aggregateFields
<&> parsedSelectionsToFields IR.AFExp
numFields <- mkNumericAggFields operator numericColumns
pure $ parseAggOperator mkTypename operator fieldNameCase tableGQLName numFields,
-- operators on comparable columns
if null comparableColumns
then Nothing
else Just $ do
comparableFields <- traverse mkColumnAggField comparableColumns
pure $
comparisonAggOperators & map \operator ->
let fieldNameCase = applyFieldNameCaseCust tCase operator
in parseAggOperator mkTypename operator fieldNameCase tableGQLName comparableFields
]
let aggregateFields = count : numericAndComparable
pure $
P.selectionSet selectName (Just description) aggregateFields
<&> parsedSelectionsToFields IR.AFExp
where
mkNumericAggFields :: G.Name -> [ColumnInfo b] -> m [FieldParser n (IR.ColFld b)]
mkNumericAggFields name
@ -1023,7 +1022,7 @@ tableAggregationFields sourceName tableInfo = memoizeOn 'tableAggregationFields
countField :: m (FieldParser n (IR.AggregateField b))
countField = do
columnsEnum <- tableSelectColumnsEnum sourceName tableInfo
columnsEnum <- tableSelectColumnsEnum sourceInfo tableInfo
let distinctName = G._distinct
args = do
distinct <- P.fieldOptional distinctName Nothing P.boolean
@ -1060,16 +1059,16 @@ tableAggregationFields sourceName tableInfo = memoizeOn 'tableAggregationFields
fieldSelection ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableName b ->
TableInfo b ->
Maybe (PrimaryKeyColumns b) ->
FieldInfo b ->
m [FieldParser n (AnnotatedField b)]
fieldSelection sourceName table tableInfo maybePkeyColumns = \case
fieldSelection sourceInfo table tableInfo maybePkeyColumns = \case
FIColumn columnInfo ->
maybeToList <$> runMaybeT do
queryType <- asks $ qcQueryType . getter
queryType <- retrieve soQueryType
let fieldName = ciName columnInfo
if fieldName == G._id && queryType == ET.QueryRelay
then do
@ -1111,20 +1110,21 @@ fieldSelection sourceName table tableInfo maybePkeyColumns = \case
P.selection fieldName (ciDescription columnInfo) pathArg field
<&> IR.mkAnnColumnField (ciColumn columnInfo) (ciType columnInfo) caseBoolExpUnpreparedValue
FIRelationship relationshipInfo ->
concat . maybeToList <$> relationshipField sourceName table relationshipInfo
concat . maybeToList <$> relationshipField sourceInfo table relationshipInfo
FIComputedField computedFieldInfo ->
maybeToList <$> computedField sourceName computedFieldInfo table tableInfo
maybeToList <$> computedField sourceInfo computedFieldInfo table tableInfo
FIRemoteRelationship remoteFieldInfo -> do
queryType <- asks $ qcQueryType . getter
queryType <- retrieve soQueryType
case (queryType, _rfiRHS remoteFieldInfo) of
(ET.QueryRelay, RFISchema _) ->
-- Remote schemas aren't currently supported in Relay, and we therefore
-- cannot include remote relationships to them while building a
-- Relay-specific schema: attempting to do so would raise an error, as
-- 'remoteRelationshipField' would attempt to look into the
-- 'QueryContext' for information about the targeted schema.
-- 'SchemaOptions' for information about the targeted schema.
pure []
_ -> do
RemoteRelationshipParserBuilder remoteRelationshipField <- retrieve scRemoteRelationshipParserBuilder
relationshipFields <- fromMaybe [] <$> remoteRelationshipField remoteFieldInfo
let lhsFields = _rfiLHS remoteFieldInfo
pure $ map (fmap (IR.AFRemote . IR.RemoteRelationshipSelect lhsFields)) relationshipFields
@ -1213,20 +1213,20 @@ join) satisfies `p(T)`.
relationshipField ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableName b ->
RelInfo b ->
m (Maybe [FieldParser n (AnnotatedField b)])
relationshipField sourceName table ri = runMaybeT do
relationshipField sourceInfo table ri = runMaybeT do
tCase <- asks getter
optimizePermissionFilters <- asks $ qcOptimizePermissionFilters . getter
otherTableInfo <- lift $ askTableInfo sourceName $ riRTable ri
optimizePermissionFilters <- retrieve soOptimizePermissionFilters
otherTableInfo <- lift $ askTableInfo sourceInfo $ riRTable ri
remotePerms <- MaybeT $ tableSelectPermissions otherTableInfo
relFieldName <- lift $ textToName $ relNameToTxt $ riName ri
-- START black magic to deduplicate permission checks
thisTablePerm <-
IR._tpFilter . tablePermissionsInfo
<$> MaybeT (tableSelectPermissions =<< askTableInfo @b sourceName table)
<$> MaybeT (tableSelectPermissions =<< askTableInfo sourceInfo table)
let deduplicatePermissions :: AnnBoolExp b (UnpreparedValue b) -> AnnBoolExp b (UnpreparedValue b)
deduplicatePermissions x =
case (optimizePermissionFilters, x) of
@ -1251,7 +1251,7 @@ relationshipField sourceName table ri = runMaybeT do
case riType ri of
ObjRel -> do
let desc = Just $ G.Description "An object relationship"
selectionSetParser <- MaybeT $ tableSelectionSet sourceName otherTableInfo
selectionSetParser <- MaybeT $ tableSelectionSet sourceInfo otherTableInfo
-- We need to set the correct nullability of our GraphQL field. Manual
-- relationships are always nullable, and so are "reverse" object
-- relationships, i.e. Hasura relationships that are generated from a
@ -1287,7 +1287,7 @@ relationshipField sourceName table ri = runMaybeT do
nullable <- case (riIsManual ri, riInsertOrder ri) of
-- Automatically generated forward relationship
(False, BeforeParent) -> do
tableInfo <- askTableInfo @b sourceName table
tableInfo <- askTableInfo sourceInfo table
let columns = Map.keys $ riMapping ri
fieldInfoMap = _tciFieldInfoMap $ _tiCoreInfo tableInfo
findColumn col = Map.lookup (fromCol @b col) fieldInfoMap ^? _Just . _FIColumn
@ -1311,7 +1311,7 @@ relationshipField sourceName table ri = runMaybeT do
IR._tpFilter $ tablePermissionsInfo remotePerms
ArrRel -> do
let arrayRelDesc = Just $ G.Description "An array relationship"
otherTableParser <- MaybeT $ selectTable sourceName otherTableInfo relFieldName arrayRelDesc
otherTableParser <- MaybeT $ selectTable sourceInfo otherTableInfo relFieldName arrayRelDesc
let arrayRelField =
otherTableParser <&> \selectExp ->
IR.AFArrayRelation $
@ -1320,10 +1320,10 @@ relationshipField sourceName table ri = runMaybeT do
deduplicatePermissions' selectExp
relAggFieldName = applyFieldNameCaseCust tCase $ relFieldName <> G.__aggregate
relAggDesc = Just $ G.Description "An aggregate relationship"
remoteAggField <- lift $ selectTableAggregate sourceName otherTableInfo relAggFieldName relAggDesc
remoteAggField <- lift $ selectTableAggregate sourceInfo otherTableInfo relAggFieldName relAggDesc
remoteConnectionField <- runMaybeT $ do
-- Parse array connection field only for relay schema
queryType <- asks $ qcQueryType . getter
queryType <- retrieve soQueryType
guard $ queryType == ET.QueryRelay
_xRelayInfo <- hoistMaybe $ relayExtension @b
pkeyColumns <-
@ -1332,7 +1332,7 @@ relationshipField sourceName table ri = runMaybeT do
<$> pure otherTableInfo
let relConnectionName = relFieldName <> G.__connection
relConnectionDesc = Just $ G.Description "An array relationship connection"
MaybeT $ lift $ selectTableConnection sourceName otherTableInfo relConnectionName relConnectionDesc pkeyColumns
MaybeT $ lift $ selectTableConnection sourceInfo otherTableInfo relConnectionName relConnectionDesc pkeyColumns
pure $
catMaybes
[ Just arrayRelField,
@ -1344,14 +1344,14 @@ relationshipField sourceName table ri = runMaybeT do
computedFieldPG ::
forall pgKind r m n.
MonadBuildSchema ('Postgres pgKind) r m n =>
SourceName ->
SourceInfo ('Postgres pgKind) ->
ComputedFieldInfo ('Postgres pgKind) ->
TableName ('Postgres pgKind) ->
TableInfo ('Postgres pgKind) ->
m (Maybe (FieldParser n (AnnotatedField ('Postgres pgKind))))
computedFieldPG sourceName ComputedFieldInfo {..} parentTable tableInfo = runMaybeT do
computedFieldPG sourceInfo ComputedFieldInfo {..} parentTable tableInfo = runMaybeT do
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
stringifyNum <- asks $ qcStringifyNum . getter
stringifyNum <- retrieve soStringifyNum
fieldName <- lift $ textToName $ computedFieldNameToText _cfiName
functionArgsParser <- lift $ computedFieldFunctionArgs _cfiFunction
case _cfiReturnType of
@ -1380,10 +1380,10 @@ computedFieldPG sourceName ComputedFieldInfo {..} parentTable tableInfo = runMay
dummyParser <- lift $ columnParser @('Postgres pgKind) (ColumnScalar scalarReturnType) (G.Nullability True)
pure $ P.selection fieldName fieldDescription fieldArgsParser dummyParser
PG.CFRSetofTable tableName -> do
otherTableInfo <- lift $ askTableInfo sourceName tableName
otherTableInfo <- lift $ askTableInfo sourceInfo tableName
remotePerms <- MaybeT $ tableSelectPermissions otherTableInfo
selectionSetParser <- MaybeT (fmap (P.multiple . P.nonNullableParser) <$> tableSelectionSet sourceName otherTableInfo)
selectArgsParser <- lift $ tableArguments sourceName otherTableInfo
selectionSetParser <- MaybeT (fmap (P.multiple . P.nonNullableParser) <$> tableSelectionSet sourceInfo otherTableInfo)
selectArgsParser <- lift $ tableArguments sourceInfo otherTableInfo
let fieldArgsParser = liftA2 (,) functionArgsParser selectArgsParser
pure $
P.subselection fieldName fieldDescription fieldArgsParser selectionSetParser
@ -1405,7 +1405,8 @@ computedFieldPG sourceName ComputedFieldInfo {..} parentTable tableInfo = runMay
ComputedFieldFunction ('Postgres pgKind) ->
m (InputFieldsParser n (FunctionArgsExp ('Postgres pgKind) (UnpreparedValue ('Postgres pgKind))))
computedFieldFunctionArgs ComputedFieldFunction {..} =
functionArgs (FTAComputedField _cfiName sourceName parentTable) (IAUserProvided <$> _cffInputArgs) <&> fmap addTableAndSessionArgument
functionArgs sourceInfo (FTAComputedField _cfiName (_siName sourceInfo) parentTable) (IAUserProvided <$> _cffInputArgs)
<&> fmap addTableAndSessionArgument
where
addTableAndSessionArgument args@(FunctionArgsExp positional named) =
let withTable = case PG._cffaTableArgument _cffComputedFieldImplicitArgs of
@ -1421,12 +1422,14 @@ computedFieldPG sourceName ComputedFieldInfo {..} parentTable tableInfo = runMay
-- > function_name(args: function_args)
customSQLFunctionArgs ::
MonadBuildSchema ('Postgres pgKind) r m n =>
SourceInfo ('Postgres pgKind) ->
FunctionInfo ('Postgres pgKind) ->
G.Name ->
G.Name ->
m (InputFieldsParser n (FunctionArgsExp ('Postgres pgKind) (UnpreparedValue ('Postgres pgKind))))
customSQLFunctionArgs FunctionInfo {..} functionName functionArgsName =
customSQLFunctionArgs sourceInfo FunctionInfo {..} functionName functionArgsName =
functionArgs
sourceInfo
( FTACustomFunction $
CustomFunctionNames
{ cfnFunctionName = functionName,
@ -1449,10 +1452,11 @@ customSQLFunctionArgs FunctionInfo {..} functionName functionArgsName =
functionArgs ::
forall r m n pgKind.
MonadBuildSchema ('Postgres pgKind) r m n =>
SourceInfo ('Postgres pgKind) ->
FunctionTrackedAs ('Postgres pgKind) ->
Seq.Seq (FunctionInputArgument ('Postgres pgKind)) ->
m (InputFieldsParser n (FunctionArgsExp ('Postgres pgKind) (UnpreparedValue ('Postgres pgKind))))
functionArgs functionTrackedAs (toList -> inputArgs) = do
functionArgs sourceInfo functionTrackedAs (toList -> inputArgs) = do
-- First, we iterate through the original sql arguments in order, to find the
-- corresponding graphql names. At the same time, we create the input field
-- parsers, in three groups: session argument, optional arguments, and
@ -1476,8 +1480,8 @@ functionArgs functionTrackedAs (toList -> inputArgs) = do
objectName <-
P.mkTypename
=<< case functionTrackedAs of
FTAComputedField computedFieldName sourceName tableName -> do
tableInfo <- askTableInfo sourceName tableName
FTAComputedField computedFieldName _sourceName tableName -> do
tableInfo <- askTableInfo sourceInfo tableName
computedFieldGQLName <- textToName $ computedFieldNameToText computedFieldName
tableGQLName <- getTableGQLName @('Postgres pgKind) tableInfo
pure $ computedFieldGQLName <> G.__ <> tableGQLName <> G.__args
@ -1661,24 +1665,27 @@ nodePG = memoizeOn 'nodePG () do
let idDescription = G.Description "A globally unique identifier"
idField = P.selection_ G._id (Just idDescription) P.identifier
nodeInterfaceDescription = G.Description "An object with globally unique ID"
sources :: SourceCache <- asks getter
sources <- retrieve scSourceCache
tCase <- asks getter
let allTables = Map.fromList $ do
-- FIXME? When source name is used in type generation?
(source, sourceInfo) <- Map.toList sources
tableName <- maybe [] (Map.keys . takeValidTables) $ unsafeSourceTables @('Postgres 'Vanilla) sourceInfo
sourceConfig <- maybeToList $ unsafeSourceConfiguration @('Postgres 'Vanilla) sourceInfo
pure (tableName, (source, sourceConfig, AB.runBackend sourceInfo _siCustomization))
tables <-
Map.catMaybes <$> flip Map.traverseWithKey allTables \table (source, sourceConfig, SourceCustomization {..}) -> runMaybeT do
tableInfo <- lift $ askTableInfo source table
tablePkeyColumns <- hoistMaybe $ tableInfo ^? tiCoreInfo . tciPrimaryKey . _Just . pkColumns
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
annotatedFieldsParser <-
MaybeT $
P.withTypenameCustomization (mkCustomizedTypename _scTypeNames tCase) $
tableSelectionSet source tableInfo
pure $ (source,sourceConfig,selectPermissions,tablePkeyColumns,) <$> annotatedFieldsParser
Map.fromList . catMaybes <$> sequence do
(sourceName, sourceInfo) <- Map.toList sources
pgInfo <- maybeToList $ AB.unpackAnyBackend @('Postgres 'Vanilla) sourceInfo
tableName <- Map.keys $ takeValidTables $ _siTables pgInfo
pure $ runMaybeT do
tableInfo <- lift $ askTableInfo pgInfo tableName
tablePkeyColumns <- hoistMaybe $ tableInfo ^? tiCoreInfo . tciPrimaryKey . _Just . pkColumns
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
annotatedFieldsParser <-
MaybeT $
P.withTypenameCustomization
(mkCustomizedTypename (_scTypeNames $ _siCustomization pgInfo) tCase)
(tableSelectionSet pgInfo tableInfo)
pure
( tableName,
(sourceName,_siConfiguration pgInfo,selectPermissions,tablePkeyColumns,)
<$> annotatedFieldsParser
)
pure $
P.selectionSetInterface
G._Node
@ -1693,7 +1700,7 @@ nodeField ::
nodeField = do
let idDescription = G.Description "A globally unique id"
idArgument = P.field G._id (Just idDescription) P.identifier
stringifyNum <- asks $ qcStringifyNum . getter
stringifyNum <- retrieve soStringifyNum
nodeObject <- node
return $
P.subselection G._node Nothing idArgument nodeObject

View File

@ -26,8 +26,8 @@ import Hasura.GraphQL.Schema.Table (getTableGQLName, tableSelectColumns, tableSe
import Hasura.Prelude
import Hasura.RQL.IR.Select qualified as IR
import Hasura.RQL.Types.Column
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.SchemaCache
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization (NamingCase, applyFieldNameCaseCust, applyTypeNameCaseCust)
import Hasura.RQL.Types.Subscription
import Hasura.RQL.Types.Table
@ -114,12 +114,12 @@ streamColumnParserArg colInfo = do
streamColumnValueParser ::
forall b n m r.
(BackendSchema b, MonadSchema n m, Has P.MkTypename r, MonadReader r m, MonadError QErr m, Has NamingCase r) =>
SourceName ->
SourceInfo b ->
G.Name ->
[ColumnInfo b] ->
m (Parser 'Input n [(ColumnInfo b, ColumnValue b)])
streamColumnValueParser sourceName tableGQLName colInfos =
memoizeOn 'streamColumnValueParser (sourceName, tableGQLName) $ do
streamColumnValueParser sourceInfo tableGQLName colInfos =
memoizeOn 'streamColumnValueParser (_siName sourceInfo, tableGQLName) $ do
tCase <- asks getter
columnVals <- sequenceA <$> traverse streamColumnParserArg colInfos
objName <- P.mkTypename $ tableGQLName <> applyTypeNameCaseCust tCase G.__stream_cursor_value_input
@ -138,13 +138,13 @@ streamColumnValueParserArg ::
MonadError QErr m,
Has NamingCase r
) =>
SourceName ->
SourceInfo b ->
G.Name ->
[ColumnInfo b] ->
m (InputFieldsParser n [(ColumnInfo b, ColumnValue b)])
streamColumnValueParserArg sourceName tableGQLName colInfos = do
streamColumnValueParserArg sourceInfo tableGQLName colInfos = do
tCase <- asks getter
columnValueParser <- streamColumnValueParser sourceName tableGQLName colInfos
columnValueParser <- streamColumnValueParser sourceInfo tableGQLName colInfos
pure do
P.field (applyFieldNameCaseCust tCase G._initial_value) (Just $ G.Description "Stream column input with initial value") columnValueParser
@ -155,13 +155,13 @@ streamColumnValueParserArg sourceName tableGQLName colInfos = do
tableStreamColumnArg ::
forall n m r b.
(BackendSchema b, MonadSchema n m, Has P.MkTypename r, MonadReader r m, MonadError QErr m, Has NamingCase r) =>
SourceName ->
SourceInfo b ->
G.Name ->
[ColumnInfo b] ->
m (InputFieldsParser n [IR.StreamCursorItem b])
tableStreamColumnArg sourceName tableGQLName colInfos = do
tableStreamColumnArg sourceInfo tableGQLName colInfos = do
cursorOrderingParser <- cursorOrderingArg
streamColumnParser <- streamColumnValueParserArg sourceName tableGQLName colInfos
streamColumnParser <- streamColumnValueParserArg sourceInfo tableGQLName colInfos
pure $ do
orderingArg <- cursorOrderingParser
columnArg <- streamColumnParser
@ -176,18 +176,18 @@ tableStreamColumnArg sourceName tableGQLName colInfos = do
tableStreamCursorExp ::
forall m n r b.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (Parser 'Input n [(IR.StreamCursorItem b)])
tableStreamCursorExp sourceName tableInfo =
memoizeOn 'tableStreamCursorExp (sourceName, tableInfoName tableInfo) $ do
tableStreamCursorExp sourceInfo tableInfo =
memoizeOn 'tableStreamCursorExp (_siName sourceInfo, tableInfoName tableInfo) $ do
tCase <- asks getter
tableGQLName <- getTableGQLName tableInfo
columnInfos <- tableSelectColumns sourceName tableInfo
columnInfos <- tableSelectColumns sourceInfo tableInfo
objName <- P.mkTypename $ tableGQLName <> applyTypeNameCaseCust tCase G.__stream_cursor_input
let description =
G.Description $ "Streaming cursor of the table " <>> tableGQLName
columnParsers <- tableStreamColumnArg sourceName tableGQLName columnInfos
columnParsers <- tableStreamColumnArg sourceInfo tableGQLName columnInfos
pure $ P.object objName (Just description) columnParsers
-- | Argument to accept the cursor input object.
@ -195,11 +195,11 @@ tableStreamCursorExp sourceName tableInfo =
tableStreamCursorArg ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (InputFieldsParser n [IR.StreamCursorItem b])
tableStreamCursorArg sourceName tableInfo = do
cursorParser <- tableStreamCursorExp sourceName tableInfo
tableStreamCursorArg sourceInfo tableInfo = do
cursorParser <- tableStreamCursorExp sourceInfo tableInfo
pure $ do
cursorArgs <-
P.field cursorName cursorDesc $ P.list $ P.nullable cursorParser
@ -213,13 +213,13 @@ tableStreamCursorArg sourceName tableInfo = do
tableStreamArguments ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (InputFieldsParser n (SelectStreamArgs b))
tableStreamArguments sourceName tableInfo = do
tableStreamArguments sourceInfo tableInfo = do
tCase <- asks getter
whereParser <- tableWhereArg sourceName tableInfo
cursorParser <- tableStreamCursorArg sourceName tableInfo
whereParser <- tableWhereArg sourceInfo tableInfo
cursorParser <- tableStreamCursorArg sourceInfo tableInfo
pure $ do
whereArg <- whereParser
cursorArg <-
@ -235,7 +235,7 @@ tableStreamArguments sourceName tableInfo = do
selectStreamTable ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
-- | table info
TableInfo b ->
-- | field display name
@ -243,14 +243,14 @@ selectStreamTable ::
-- | field description, if any
Maybe G.Description ->
m (Maybe (P.FieldParser n (StreamSelectExp b)))
selectStreamTable sourceName tableInfo fieldName description = runMaybeT $ do
selectStreamTable sourceInfo tableInfo fieldName description = runMaybeT $ do
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
xStreamSubscription <- hoistMaybe $ streamSubscriptionExtension @b
stringifyNum <- asks $ qcStringifyNum . getter
tableStreamArgsParser <- lift $ tableStreamArguments sourceName tableInfo
selectionSetParser <- MaybeT $ tableSelectionList sourceName tableInfo
stringifyNum <- retrieve soStringifyNum
tableStreamArgsParser <- lift $ tableStreamArguments sourceInfo tableInfo
selectionSetParser <- MaybeT $ tableSelectionList sourceInfo tableInfo
lift $
memoizeOn 'selectStreamTable (sourceName, tableName, fieldName) $ do
memoizeOn 'selectStreamTable (_siName sourceInfo, tableName, fieldName) $ do
pure $
P.subselection fieldName description tableStreamArgsParser selectionSetParser
<&> \(args, fields) ->

View File

@ -28,7 +28,6 @@ import Hasura.GraphQL.Schema.Common
import Hasura.Prelude
import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.Column
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.ComputedField
import Hasura.RQL.Types.Relationships.Local
import Hasura.RQL.Types.SchemaCache hiding (askTableInfo)
@ -85,12 +84,12 @@ getTableIdentifierName tableInfo =
tableSelectColumnsEnum ::
forall b r m n.
MonadBuildSchema b r m n =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m (Maybe (Parser 'Both n (Column b)))
tableSelectColumnsEnum sourceName tableInfo = do
tableSelectColumnsEnum sourceInfo tableInfo = do
tableGQLName <- getTableGQLName @b tableInfo
columns <- tableSelectColumns sourceName tableInfo
columns <- tableSelectColumns sourceInfo tableInfo
enumName <- P.mkTypename $ tableGQLName <> G.__select_column
let description =
Just $
@ -173,13 +172,12 @@ tableSelectFields ::
( Backend b,
MonadError QErr m,
MonadReader r m,
Has SourceCache r,
Has RoleName r
) =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m [FieldInfo b]
tableSelectFields sourceName tableInfo = do
tableSelectFields sourceInfo tableInfo = do
let tableFields = _tciFieldInfoMap . _tiCoreInfo $ tableInfo
permissions <- tableSelectPermissions tableInfo
filterM (canBeSelected permissions) $ Map.elems tableFields
@ -188,14 +186,14 @@ tableSelectFields sourceName tableInfo = do
canBeSelected (Just permissions) (FIColumn columnInfo) =
pure $ Map.member (ciColumn columnInfo) (spiCols permissions)
canBeSelected _ (FIRelationship relationshipInfo) = do
tableInfo' <- askTableInfo sourceName $ riRTable relationshipInfo
tableInfo' <- askTableInfo sourceInfo $ riRTable relationshipInfo
isJust <$> tableSelectPermissions @b tableInfo'
canBeSelected (Just permissions) (FIComputedField computedFieldInfo) =
case computedFieldReturnType @b (_cfiReturnType computedFieldInfo) of
ReturnsScalar _ ->
pure $ Map.member (_cfiName computedFieldInfo) $ spiScalarComputedFields permissions
ReturnsTable tableName -> do
tableInfo' <- askTableInfo sourceName tableName
tableInfo' <- askTableInfo sourceInfo tableName
isJust <$> tableSelectPermissions @b tableInfo'
ReturnsOthers -> pure False
canBeSelected _ (FIRemoteRelationship _) = pure True
@ -215,14 +213,13 @@ tableSelectColumns ::
( Backend b,
MonadError QErr m,
MonadReader r m,
Has SourceCache r,
Has RoleName r
) =>
SourceName ->
SourceInfo b ->
TableInfo b ->
m [ColumnInfo b]
tableSelectColumns sourceName tableInfo =
mapMaybe columnInfo <$> tableSelectFields sourceName tableInfo
tableSelectColumns sourceInfo tableInfo =
mapMaybe columnInfo <$> tableSelectFields sourceInfo tableInfo
where
columnInfo (FIColumn ci) = Just ci
columnInfo _ = Nothing

View File

@ -35,7 +35,7 @@ import Hasura.RQL.IR.Root (RemoteRelationshipField)
import Hasura.RQL.IR.Update (AnnotatedUpdateG (..))
import Hasura.RQL.Types.Backend (Backend (..))
import Hasura.RQL.Types.Column (ColumnInfo (..), isNumCol)
import Hasura.RQL.Types.Common (SourceName)
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization (NamingCase)
import Hasura.RQL.Types.Table
import Language.GraphQL.Draft.Syntax (Description (..), Name (..), Nullability (..), litName)
@ -264,7 +264,7 @@ updateTable ::
-- | backend-specific data needed to perform an update mutation
P.InputFieldsParser n (BackendUpdate b (P.UnpreparedValue b)) ->
-- | table source
SourceName ->
SourceInfo b ->
-- | table info
TableInfo b ->
-- | field display name
@ -272,7 +272,7 @@ updateTable ::
-- | field description, if any
Maybe Description ->
m (Maybe (P.FieldParser n (AnnotatedUpdateG b (RemoteRelationshipField P.UnpreparedValue) (P.UnpreparedValue b))))
updateTable backendUpdate sourceName tableInfo fieldName description = runMaybeT do
updateTable backendUpdate sourceInfo tableInfo fieldName description = runMaybeT do
let tableName = tableInfoName tableInfo
columns = tableColumns tableInfo
whereName = $$(litName "where")
@ -280,8 +280,8 @@ updateTable backendUpdate sourceName tableInfo fieldName description = runMaybeT
viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
guard $ isMutable viIsUpdatable viewInfo
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
whereArg <- lift $ P.field whereName (Just whereDesc) <$> boolExp sourceName tableInfo
selection <- lift $ mutationSelectionSet sourceName tableInfo
whereArg <- lift $ P.field whereName (Just whereDesc) <$> boolExp sourceInfo tableInfo
selection <- lift $ mutationSelectionSet sourceInfo tableInfo
let argsParser = liftA2 (,) backendUpdate whereArg
pure $
P.subselection fieldName description argsParser selection
@ -297,7 +297,7 @@ updateTableByPk ::
-- | backend-specific data needed to perform an update mutation
P.InputFieldsParser n (BackendUpdate b (P.UnpreparedValue b)) ->
-- | table source
SourceName ->
SourceInfo b ->
-- | table info
TableInfo b ->
-- | field display name
@ -305,14 +305,14 @@ updateTableByPk ::
-- | field description, if any
Maybe Description ->
m (Maybe (P.FieldParser n (AnnotatedUpdateG b (RemoteRelationshipField P.UnpreparedValue) (P.UnpreparedValue b))))
updateTableByPk backendUpdate sourceName tableInfo fieldName description = runMaybeT $ do
updateTableByPk backendUpdate sourceInfo tableInfo fieldName description = runMaybeT $ do
let columns = tableColumns tableInfo
tableName = tableInfoName tableInfo
viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
guard $ isMutable viIsUpdatable viewInfo
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
pkArgs <- MaybeT $ primaryKeysArguments tableInfo
selection <- MaybeT $ tableSelectionSet sourceName tableInfo
selection <- MaybeT $ tableSelectionSet sourceInfo tableInfo
lift $ do
tableGQLName <- getTableGQLName tableInfo
pkObjectName <- P.mkTypename $ tableGQLName <> $$(litName "_pk_columns_input")

View File

@ -17,7 +17,7 @@ import Hasura.GraphQL.Namespace
import Hasura.GraphQL.Parser.Column (UnpreparedValue)
import Hasura.GraphQL.Parser.Constants qualified as G
import Hasura.GraphQL.Parser.Internal.Parser qualified as P
import Hasura.GraphQL.Parser.Monad
import Hasura.GraphQL.Parser.Monad (runSchemaT)
import Hasura.GraphQL.Parser.Schema
import Hasura.GraphQL.Parser.TestUtils
import Hasura.GraphQL.Schema.Common
@ -28,7 +28,6 @@ import Hasura.RQL.IR.Root
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.RemoteSchema
import Hasura.RQL.Types.SchemaCache
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization
import Hasura.Session
import Language.GraphQL.Draft.Parser qualified as G
@ -117,19 +116,20 @@ buildQueryParsers introspection = do
-- schema. Here, since there are no relationships to a source in this
-- test, we are free to give 'undefined' for such fields, as they won't be
-- evaluated.
sourceContext =
schemaInfo =
( adminRoleName :: RoleName,
undefined :: SourceCache,
undefined :: QueryContext,
mempty :: CustomizeRemoteFieldName,
mempty :: RemoteSchemaMap,
mempty :: MkTypename,
mempty :: MkRootFieldName,
HasuraCase :: NamingCase
HasuraCase :: NamingCase,
undefined :: SchemaOptions,
SchemaContext
mempty
ignoreRemoteRelationship
)
RemoteSchemaParser query _ _ <-
runError $
flip runReaderT sourceContext $
flip runReaderT schemaInfo $
runSchemaT $
buildRemoteParser introResult remoteSchemaRels remoteSchemaInfo
pure $

View File

@ -23,8 +23,9 @@ import Hasura.RQL.IR.BoolExp (AnnBoolExpFld (..), GBoolExp (..), PartialSQLExp (
import Hasura.RQL.IR.Root (RemoteRelationshipField)
import Hasura.RQL.IR.Update (AnnotatedUpdateG (..))
import Hasura.RQL.Types.Column (ColumnInfo (..), ColumnMutability (..), ColumnType (..))
import Hasura.RQL.Types.Common (Comment (..), FieldName (..), SourceName, SystemDefined (..))
import Hasura.RQL.Types.Common (Comment (..), FieldName (..), SystemDefined (..))
import Hasura.RQL.Types.Instances ()
import Hasura.RQL.Types.Source (SourceInfo)
import Hasura.RQL.Types.Table (CustomRootField (..), FieldInfo (..), RolePermInfo (..), SelPermInfo (..), TableConfig (..), TableCoreInfoG (..), TableCustomRootFields (..), TableInfo (..), UpdPermInfo (..))
import Hasura.SQL.Backend (BackendType (Postgres), PostgresKind (Vanilla))
import Language.GraphQL.Draft.Syntax (unsafeMkName)
@ -85,7 +86,7 @@ mkParser :: QualifiedTable -> [ColumnInfoBuilder] -> SchemaTestT [Parser]
mkParser table cib =
Build.buildTableUpdateMutationFields
backendUpdateParser
sourceName
sourceInfo
table
tableInfo
name
@ -114,8 +115,8 @@ mkParser table cib =
upiFilter = BoolAnd $ fmap (\ci -> BoolFld $ AVColumn ci []) columnInfos
------------------------------------------
sourceName :: SourceName
sourceName = undefined
sourceInfo :: SourceInfo PG
sourceInfo = undefined
------------------------------------------
tableInfo :: TableInfo PG

View File

@ -18,13 +18,11 @@ import Hasura.Base.Error (Code, QErr)
import Hasura.GraphQL.Execute.Types (GraphQLQueryType (..))
import Hasura.GraphQL.Parser.Class (MonadParse (..), MonadSchema (..))
import Hasura.GraphQL.Parser.Schema (MkTypename (..))
import Hasura.GraphQL.Schema.Common (QueryContext (..))
import Hasura.GraphQL.Schema.Common (SchemaContext (..), SchemaOptions (..), ignoreRemoteRelationship)
import Hasura.Prelude
import Hasura.RQL.Types.Common (StringifyNumbers (LeaveNumbersAlone))
import Hasura.RQL.Types.Function (FunctionPermissionsCtx (..))
import Hasura.RQL.Types.RemoteSchema (RemoteSchemaPermsCtx (..))
import Hasura.RQL.Types.SchemaCache (RemoteSchemaMap)
import Hasura.RQL.Types.Source (SourceCache)
import Hasura.RQL.Types.SourceCustomization (CustomizeRemoteFieldName, MkRootFieldName, NamingCase (..))
import Hasura.Session (RoleName, adminRoleName)
import Language.Haskell.TH.Syntax qualified as TH
@ -52,20 +50,6 @@ instance Has NamingCase SchemaEnvironment where
modifier :: (NamingCase -> NamingCase) -> SchemaEnvironment -> SchemaEnvironment
modifier = notImplemented "modifier<Has NamingCase SchemaEnvironment>"
instance Has SourceCache SchemaEnvironment where
getter :: SchemaEnvironment -> SourceCache
getter = notImplemented "getter<Has SourceCache SchemaEnvironment>"
modifier :: (SourceCache -> SourceCache) -> SchemaEnvironment -> SchemaEnvironment
modifier = notImplemented "modifier<Has SourceCache SchemaEnvironment>"
instance Has RemoteSchemaMap SchemaEnvironment where
getter :: SchemaEnvironment -> RemoteSchemaMap
getter = notImplemented "getter<Has RemoteSchemaMap SchemaEnvironment>"
modifier :: (RemoteSchemaMap -> RemoteSchemaMap) -> SchemaEnvironment -> SchemaEnvironment
modifier = notImplemented "modifier<Has RemoteSchemaMap SchemaEnvironment>"
instance Has RoleName SchemaEnvironment where
getter :: SchemaEnvironment -> RoleName
getter = const adminRoleName
@ -73,23 +57,33 @@ instance Has RoleName SchemaEnvironment where
modifier :: (RoleName -> RoleName) -> SchemaEnvironment -> SchemaEnvironment
modifier = notImplemented "modifier<Has RoleName SchemaEnvironment>"
queryContext :: QueryContext
queryContext =
QueryContext
{ qcStringifyNum = LeaveNumbersAlone,
qcDangerousBooleanCollapse = False,
qcQueryType = QueryHasura,
qcFunctionPermsContext = FunctionPermissionsInferred,
qcRemoteSchemaPermsCtx = RemoteSchemaPermsDisabled,
qcOptimizePermissionFilters = False
}
instance Has SchemaOptions SchemaEnvironment where
getter :: SchemaEnvironment -> SchemaOptions
getter =
const
SchemaOptions
{ soStringifyNum = LeaveNumbersAlone,
soDangerousBooleanCollapse = False,
soQueryType = QueryHasura,
soFunctionPermsContext = FunctionPermissionsInferred,
soRemoteSchemaPermsCtx = RemoteSchemaPermsDisabled,
soOptimizePermissionFilters = False
}
instance Has QueryContext SchemaEnvironment where
getter :: SchemaEnvironment -> QueryContext
getter = const queryContext
modifier :: (SchemaOptions -> SchemaOptions) -> SchemaEnvironment -> SchemaEnvironment
modifier = notImplemented "modifier<Has SchemaOptions SchemaEnvironment>"
modifier :: (QueryContext -> QueryContext) -> SchemaEnvironment -> SchemaEnvironment
modifier = notImplemented "modifier<Has QueryContext SchemaEnvironment>"
instance Has SchemaContext SchemaEnvironment where
getter :: SchemaEnvironment -> SchemaContext
getter =
const
SchemaContext
{ scSourceCache = notImplemented "scSourceCache",
scRemoteRelationshipParserBuilder = ignoreRemoteRelationship
}
modifier :: (SchemaContext -> SchemaContext) -> SchemaEnvironment -> SchemaEnvironment
modifier = notImplemented "modifier<Has SchemaContext SchemaEnvironment>"
instance Has MkTypename SchemaEnvironment where
getter :: SchemaEnvironment -> MkTypename