mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-09-11 10:46:25 +03:00
Merge branch 'master' into master
This commit is contained in:
commit
8ebb048de5
@ -30,7 +30,7 @@ services:
|
||||
MONGO_INITDB_ROOT_USERNAME: mongouser
|
||||
MONGO_INITDB_ROOT_PASSWORD: mongopassword
|
||||
hasura:
|
||||
image: hasura/graphql-engine:v2.35.0
|
||||
image: hasura/graphql-engine:v2.35.1
|
||||
restart: always
|
||||
ports:
|
||||
- 8080:8080
|
||||
@ -60,7 +60,7 @@ services:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
mongo-data-connector:
|
||||
image: hasura/mongo-data-connector:v2.32.0
|
||||
image: hasura/mongo-data-connector:v2.35.1
|
||||
ports:
|
||||
- 3000:3000
|
||||
volumes:
|
||||
|
@ -255,12 +255,16 @@ function maybe_launch_hasura_container() {
|
||||
--env HASURA_GRAPHQL_SERVER_PORT="$HASURA_GRAPHQL_SERVER_PORT" \
|
||||
--env HASURA_GRAPHQL_ADMIN_SECRET \
|
||||
--env HASURA_GRAPHQL_EE_LICENSE_KEY \
|
||||
--env HASURA_GRAPHQL_EVENTS_FETCH_INTERVAL=0 \
|
||||
--env HASURA_GRAPHQL_SCHEMA_SYNC_POLL_INTERVAL=0 \
|
||||
$DOCKER_NETWORK_HOST_MODE \
|
||||
"$REQUESTED_HASURA_DOCKER_IMAGE" \
|
||||
graphql-engine serve \
|
||||
+RTS -T $HASURA_RTS -RTS
|
||||
# ^^^ We run with `+RTS -T` to expose the /dev/rts_stats endpoint for
|
||||
# ^^^ - We run with `+RTS -T` to expose the /dev/rts_stats endpoint for
|
||||
# inspecting memory usage stats
|
||||
# - We disable some unneeded (currently) polling to try to eliminate
|
||||
# some sources of non-determinism
|
||||
else
|
||||
echo_pretty "We'll benchmark the hasura instance at port $HASURA_GRAPHQL_SERVER_PORT"
|
||||
fi
|
||||
|
@ -280,6 +280,7 @@ serveOptions =
|
||||
soEnableTelemetry = Init.TelemetryDisabled,
|
||||
soStringifyNum = Options.Don'tStringifyNumbers,
|
||||
soDangerousBooleanCollapse = Options.Don'tDangerouslyCollapseBooleans,
|
||||
soBackwardsCompatibleNullInNonNullableVariables = Options.Don'tAllowNullInNonNullableVariables,
|
||||
soRemoteNullForwardingPolicy = Options.RemoteForwardAccurately,
|
||||
soEnabledAPIs = testSuiteEnabledApis,
|
||||
soLiveQueryOpts = ES.mkSubscriptionsOptions Nothing Nothing,
|
||||
|
@ -266,7 +266,7 @@ buildAppContextRule ::
|
||||
buildAppContextRule = proc (ServeOptions {..}, env, _keys, checkFeatureFlag) -> do
|
||||
schemaSampledFeatureFlags <- arrM (liftIO . sampleFeatureFlags) -< checkFeatureFlag
|
||||
authMode <- buildAuthMode -< (soAdminSecret, soAuthHook, soJwtSecret, soUnAuthRole)
|
||||
let sqlGenCtx = initSQLGenCtx soExperimentalFeatures soStringifyNum soDangerousBooleanCollapse soRemoteNullForwardingPolicy
|
||||
let sqlGenCtx = initSQLGenCtx soExperimentalFeatures soStringifyNum soDangerousBooleanCollapse soBackwardsCompatibleNullInNonNullableVariables soRemoteNullForwardingPolicy
|
||||
responseInternalErrorsConfig <- buildResponseInternalErrorsConfig -< (soAdminInternalErrors, soDevMode)
|
||||
eventEngineCtx <- buildEventEngineCtx -< (soEventsHttpPoolSize, soEventsFetchInterval, soEventsFetchBatchSize)
|
||||
returnA
|
||||
@ -329,8 +329,14 @@ buildAppContextRule = proc (ServeOptions {..}, env, _keys, checkFeatureFlag) ->
|
||||
--------------------------------------------------------------------------------
|
||||
-- subsets
|
||||
|
||||
initSQLGenCtx :: HashSet ExperimentalFeature -> Options.StringifyNumbers -> Options.DangerouslyCollapseBooleans -> Options.RemoteNullForwardingPolicy -> SQLGenCtx
|
||||
initSQLGenCtx experimentalFeatures stringifyNum dangerousBooleanCollapse remoteNullForwardingPolicy =
|
||||
initSQLGenCtx ::
|
||||
HashSet ExperimentalFeature ->
|
||||
Options.StringifyNumbers ->
|
||||
Options.DangerouslyCollapseBooleans ->
|
||||
Options.BackwardsCompatibleNullInNonNullableVariables ->
|
||||
Options.RemoteNullForwardingPolicy ->
|
||||
SQLGenCtx
|
||||
initSQLGenCtx experimentalFeatures stringifyNum dangerousBooleanCollapse nullInNonNullableVariables remoteNullForwardingPolicy =
|
||||
let optimizePermissionFilters
|
||||
| EFOptimizePermissionFilters `elem` experimentalFeatures = Options.OptimizePermissionFilters
|
||||
| otherwise = Options.Don'tOptimizePermissionFilters
|
||||
@ -338,7 +344,7 @@ initSQLGenCtx experimentalFeatures stringifyNum dangerousBooleanCollapse remoteN
|
||||
bigqueryStringNumericInput
|
||||
| EFBigQueryStringNumericInput `elem` experimentalFeatures = Options.EnableBigQueryStringNumericInput
|
||||
| otherwise = Options.DisableBigQueryStringNumericInput
|
||||
in SQLGenCtx stringifyNum dangerousBooleanCollapse remoteNullForwardingPolicy optimizePermissionFilters bigqueryStringNumericInput
|
||||
in SQLGenCtx stringifyNum dangerousBooleanCollapse nullInNonNullableVariables remoteNullForwardingPolicy optimizePermissionFilters bigqueryStringNumericInput
|
||||
|
||||
buildCacheStaticConfig :: AppEnv -> CacheStaticConfig
|
||||
buildCacheStaticConfig AppEnv {..} =
|
||||
|
@ -390,6 +390,7 @@ getResolvedExecPlan
|
||||
tracesPropagator
|
||||
prometheusMetrics
|
||||
gCtx
|
||||
sqlGenCtx
|
||||
userInfo
|
||||
reqHeaders
|
||||
directives
|
||||
@ -426,6 +427,7 @@ getResolvedExecPlan
|
||||
G.TypedOperationDefinition G.OperationTypeSubscription _ varDefs directives inlinedSelSet -> Tracing.newSpan "Resolve subscription execution plan" $ do
|
||||
(normalizedDirectives, normalizedSelectionSet) <-
|
||||
ER.resolveVariables
|
||||
(nullInNonNullableVariables sqlGenCtx)
|
||||
varDefs
|
||||
(fromMaybe mempty (_grVariables reqUnparsed))
|
||||
directives
|
||||
|
@ -103,7 +103,7 @@ convertMutationSelectionSet
|
||||
tracesPropagator
|
||||
prometheusMetrics
|
||||
gqlContext
|
||||
SQLGenCtx {stringifyNum}
|
||||
SQLGenCtx {stringifyNum, nullInNonNullableVariables}
|
||||
userInfo
|
||||
reqHeaders
|
||||
directives
|
||||
@ -117,7 +117,7 @@ convertMutationSelectionSet
|
||||
onNothing (gqlMutationParser gqlContext)
|
||||
$ throw400 ValidationFailed "no mutations exist"
|
||||
|
||||
(resolvedDirectives, resolvedSelSet) <- resolveVariables varDefs (fromMaybe HashMap.empty (GH._grVariables gqlUnparsed)) directives fields
|
||||
(resolvedDirectives, resolvedSelSet) <- resolveVariables nullInNonNullableVariables varDefs (fromMaybe HashMap.empty (GH._grVariables gqlUnparsed)) directives fields
|
||||
-- Parse the GraphQL query into the RQL AST
|
||||
(unpreparedQueries :: RootFieldMap (MutationRootField UnpreparedValue)) <-
|
||||
Tracing.newSpan "Parse mutation IR" $ liftEither $ mutationParser resolvedSelSet
|
||||
|
@ -32,7 +32,9 @@ import Hasura.RQL.IR
|
||||
import Hasura.RQL.IR.ModelInformation
|
||||
import Hasura.RQL.Types.Action
|
||||
import Hasura.RQL.Types.Backend
|
||||
import Hasura.RQL.Types.Common
|
||||
import Hasura.RQL.Types.GraphqlSchemaIntrospection
|
||||
import Hasura.RQL.Types.Schema.Options as Options
|
||||
import Hasura.RemoteSchema.Metadata.Base (RemoteSchemaName (..))
|
||||
import Hasura.SQL.AnyBackend qualified as AB
|
||||
import Hasura.Server.Prometheus (PrometheusMetrics (..))
|
||||
@ -46,6 +48,7 @@ import Network.HTTP.Types qualified as HTTP
|
||||
|
||||
parseGraphQLQuery ::
|
||||
(MonadError QErr m) =>
|
||||
Options.BackwardsCompatibleNullInNonNullableVariables ->
|
||||
GQLContext ->
|
||||
[G.VariableDefinition] ->
|
||||
Maybe (HashMap G.Name J.Value) ->
|
||||
@ -56,8 +59,8 @@ parseGraphQLQuery ::
|
||||
[G.Directive Variable],
|
||||
G.SelectionSet G.NoFragments Variable
|
||||
)
|
||||
parseGraphQLQuery gqlContext varDefs varValsM directives fields = do
|
||||
(resolvedDirectives, resolvedSelSet) <- resolveVariables varDefs (fromMaybe HashMap.empty varValsM) directives fields
|
||||
parseGraphQLQuery nullInNonNullableVariables gqlContext varDefs varValsM directives fields = do
|
||||
(resolvedDirectives, resolvedSelSet) <- resolveVariables nullInNonNullableVariables varDefs (fromMaybe HashMap.empty varValsM) directives fields
|
||||
parsedQuery <- liftEither $ gqlQueryParser gqlContext resolvedSelSet
|
||||
pure (parsedQuery, resolvedDirectives, resolvedSelSet)
|
||||
|
||||
@ -77,6 +80,7 @@ convertQuerySelSet ::
|
||||
Tracing.HttpPropagator ->
|
||||
PrometheusMetrics ->
|
||||
GQLContext ->
|
||||
SQLGenCtx ->
|
||||
UserInfo ->
|
||||
HTTP.RequestHeaders ->
|
||||
[G.Directive G.Name] ->
|
||||
@ -94,6 +98,7 @@ convertQuerySelSet
|
||||
tracingPropagator
|
||||
prometheusMetrics
|
||||
gqlContext
|
||||
SQLGenCtx {nullInNonNullableVariables}
|
||||
userInfo
|
||||
reqHeaders
|
||||
directives
|
||||
@ -105,7 +110,7 @@ convertQuerySelSet
|
||||
maybeOperationName = do
|
||||
-- 1. Parse the GraphQL query into the 'RootFieldMap' and a 'SelectionSet'
|
||||
(unpreparedQueries, normalizedDirectives, normalizedSelectionSet) <-
|
||||
Tracing.newSpan "Parse query IR" $ parseGraphQLQuery gqlContext varDefs (GH._grVariables gqlUnparsed) directives fields
|
||||
Tracing.newSpan "Parse query IR" $ parseGraphQLQuery nullInNonNullableVariables gqlContext varDefs (GH._grVariables gqlUnparsed) directives fields
|
||||
|
||||
-- 2. Parse directives on the query
|
||||
dirMap <- toQErr $ runParse (parseDirectives customDirectives (G.DLExecutable G.EDLQUERY) normalizedDirectives)
|
||||
|
@ -5,6 +5,7 @@ module Hasura.GraphQL.Execute.Resolve
|
||||
)
|
||||
where
|
||||
|
||||
import Data.Aeson qualified as J
|
||||
import Data.HashMap.Strict.Extended qualified as HashMap
|
||||
import Data.HashSet qualified as HS
|
||||
import Data.List qualified as L
|
||||
@ -15,11 +16,13 @@ import Hasura.GraphQL.Parser.Names
|
||||
import Hasura.GraphQL.Parser.Variable
|
||||
import Hasura.GraphQL.Transport.HTTP.Protocol qualified as GH
|
||||
import Hasura.Prelude
|
||||
import Hasura.RQL.Types.Schema.Options qualified as Options
|
||||
import Language.GraphQL.Draft.Syntax qualified as G
|
||||
|
||||
resolveVariables ::
|
||||
forall m fragments.
|
||||
(MonadError QErr m, Traversable fragments) =>
|
||||
Options.BackwardsCompatibleNullInNonNullableVariables ->
|
||||
[G.VariableDefinition] ->
|
||||
GH.VariableValues ->
|
||||
[G.Directive G.Name] ->
|
||||
@ -28,7 +31,7 @@ resolveVariables ::
|
||||
( [G.Directive Variable],
|
||||
G.SelectionSet fragments Variable
|
||||
)
|
||||
resolveVariables definitions jsonValues directives selSet = do
|
||||
resolveVariables nullInNonNullableVariables definitions jsonValues directives selSet = do
|
||||
variablesByName <- HashMap.groupOnNE getName <$> traverse buildVariable definitions
|
||||
uniqueVariables <- flip
|
||||
HashMap.traverseWithKey
|
||||
@ -83,7 +86,21 @@ resolveVariables definitions jsonValues directives selSet = do
|
||||
let defaultValue = fromMaybe G.VNull _vdDefaultValue
|
||||
isOptional = isJust _vdDefaultValue || G.isNullable _vdType
|
||||
value <- case HashMap.lookup _vdName jsonValues of
|
||||
Just jsonValue -> pure $ Just $ JSONValue jsonValue
|
||||
Just jsonValue ->
|
||||
-- If variable type is non-nullalbe , then raise exception if 'null' is provided
|
||||
if not (G.isNullable _vdType)
|
||||
-- `HASURA_GRAPHQL_BACKWARDS_COMPAT_NULL_IN_NONNULLABLE_VARIABLES` option set to `false`
|
||||
&& nullInNonNullableVariables
|
||||
== Options.Don'tAllowNullInNonNullableVariables
|
||||
-- A 'null' value provided
|
||||
&& jsonValue
|
||||
== J.Null
|
||||
then -- raise validation exception
|
||||
|
||||
throw400 ValidationFailed
|
||||
$ "null value found for non-nullable type: "
|
||||
<>> G.showGT _vdType
|
||||
else pure $ Just $ JSONValue jsonValue
|
||||
Nothing
|
||||
-- If the variable value was not provided, and the variable has no
|
||||
-- default value, then don't store a value for the variable.
|
||||
|
@ -31,6 +31,7 @@ import Hasura.Prelude
|
||||
import Hasura.QueryTags
|
||||
import Hasura.RQL.IR
|
||||
import Hasura.RQL.Types.Roles (adminRoleName)
|
||||
import Hasura.RQL.Types.Schema.Options qualified as Options
|
||||
import Hasura.RQL.Types.SchemaCache
|
||||
import Hasura.SQL.AnyBackend qualified as AB
|
||||
import Hasura.Session (UserAdminSecret (..), UserInfo, UserRoleBuild (..), mkSessionVariablesText, mkUserInfo)
|
||||
@ -93,12 +94,13 @@ explainGQLQuery ::
|
||||
MonadQueryTags m,
|
||||
MonadTrace m
|
||||
) =>
|
||||
Options.BackwardsCompatibleNullInNonNullableVariables ->
|
||||
SchemaCache ->
|
||||
Maybe (CredentialCache AgentLicenseKey) ->
|
||||
[HTTP.Header] ->
|
||||
GQLExplain ->
|
||||
m EncJSON
|
||||
explainGQLQuery sc agentLicenseKey reqHeaders (GQLExplain query userVarsRaw maybeIsRelay) = do
|
||||
explainGQLQuery nullInNonNullableVariables sc agentLicenseKey reqHeaders (GQLExplain query userVarsRaw maybeIsRelay) = do
|
||||
-- NOTE!: we will be executing what follows as though admin role. See e.g. notes in explainField:
|
||||
userInfo <-
|
||||
mkUserInfo
|
||||
@ -111,7 +113,7 @@ explainGQLQuery sc agentLicenseKey reqHeaders (GQLExplain query userVarsRaw mayb
|
||||
case queryParts of
|
||||
G.TypedOperationDefinition G.OperationTypeQuery _ varDefs directives inlinedSelSet -> do
|
||||
(unpreparedQueries, _, _) <-
|
||||
E.parseGraphQLQuery graphQLContext varDefs (GH._grVariables query) directives inlinedSelSet
|
||||
E.parseGraphQLQuery nullInNonNullableVariables graphQLContext varDefs (GH._grVariables query) directives inlinedSelSet
|
||||
-- TODO: validate directives here
|
||||
encJFromList
|
||||
<$> for (InsOrdHashMap.toList unpreparedQueries) (uncurry (explainQueryField agentLicenseKey userInfo reqHeaders (_unOperationName <$> _grOperationName query)))
|
||||
@ -120,6 +122,7 @@ explainGQLQuery sc agentLicenseKey reqHeaders (GQLExplain query userVarsRaw mayb
|
||||
G.TypedOperationDefinition G.OperationTypeSubscription _ varDefs directives inlinedSelSet -> do
|
||||
(_normalizedDirectives, normalizedSelectionSet) <-
|
||||
ER.resolveVariables
|
||||
nullInNonNullableVariables
|
||||
varDefs
|
||||
(fromMaybe mempty (GH._grVariables query))
|
||||
directives
|
||||
|
@ -253,7 +253,7 @@ buildSchemaOptions ::
|
||||
HashSet ExperimentalFeature ->
|
||||
SchemaOptions
|
||||
buildSchemaOptions
|
||||
( SQLGenCtx stringifyNum dangerousBooleanCollapse remoteNullForwardingPolicy optimizePermissionFilters bigqueryStringNumericInput,
|
||||
( SQLGenCtx stringifyNum dangerousBooleanCollapse _nullInNonNullableVariables remoteNullForwardingPolicy optimizePermissionFilters bigqueryStringNumericInput,
|
||||
functionPermsCtx
|
||||
)
|
||||
expFeatures =
|
||||
|
@ -419,8 +419,8 @@ websocketConnectionReaper getLatestConfig getSchemaCache ws@(WSServer _ userConf
|
||||
-- The bigqueryStringNumericInput of SQLGenCtx is built from the experimentalFeature, hence no need to check for this field
|
||||
-- in experimentalFeatures again.
|
||||
hasBigqueryStringNumericInputChanged = bigqueryStringNumericInput currSqlGenCtx /= bigqueryStringNumericInput prevSqlGenCtx
|
||||
hasHideAggregationPredicatesChanged = (EFHideAggregationPredicates `elem` currExperimentalFeatures) && (EFHideAggregationPredicates `elem` prevExperimentalFeatures)
|
||||
hasHideStreamFieldsChanged = (EFHideStreamFields `elem` currExperimentalFeatures) && (EFHideStreamFields `elem` prevExperimentalFeatures)
|
||||
hasHideAggregationPredicatesChanged = (EFHideAggregationPredicates `elem` currExperimentalFeatures) /= (EFHideAggregationPredicates `elem` prevExperimentalFeatures)
|
||||
hasHideStreamFieldsChanged = (EFHideStreamFields `elem` currExperimentalFeatures) /= (EFHideStreamFields `elem` prevExperimentalFeatures)
|
||||
hasDefaultNamingCaseChanged = hasNamingConventionChanged (prevExperimentalFeatures, prevDefaultNamingCase) (currExperimentalFeatures, currDefaultNamingCase)
|
||||
if
|
||||
-- if CORS policy has changed, close all connections
|
||||
|
@ -301,6 +301,7 @@ isSystemDefined = unSystemDefined
|
||||
data SQLGenCtx = SQLGenCtx
|
||||
{ stringifyNum :: Options.StringifyNumbers,
|
||||
dangerousBooleanCollapse :: Options.DangerouslyCollapseBooleans,
|
||||
nullInNonNullableVariables :: Options.BackwardsCompatibleNullInNonNullableVariables,
|
||||
remoteNullForwardingPolicy :: Options.RemoteNullForwardingPolicy,
|
||||
optimizePermissionFilters :: Options.OptimizePermissionFilters,
|
||||
bigqueryStringNumericInput :: Options.BigQueryStringNumericInput
|
||||
|
@ -4,6 +4,7 @@ module Hasura.RQL.Types.Schema.Options
|
||||
( SchemaOptions (..),
|
||||
StringifyNumbers (..),
|
||||
DangerouslyCollapseBooleans (..),
|
||||
BackwardsCompatibleNullInNonNullableVariables (..),
|
||||
RemoteNullForwardingPolicy (..),
|
||||
InferFunctionPermissions (..),
|
||||
RemoteSchemaPermissions (..),
|
||||
@ -89,6 +90,27 @@ instance ToJSON DangerouslyCollapseBooleans where
|
||||
DangerouslyCollapseBooleans -> Bool True
|
||||
Don'tDangerouslyCollapseBooleans -> Bool False
|
||||
|
||||
-- | Should `null` values allowed for variables whose type is declared
|
||||
-- as non-nullable in a GraphQL query.
|
||||
-- Until version 2.34.0 (except 2.11.11), `null` value is validated for
|
||||
-- non-nullable variables. It is being fixed, to keep backwards compatible
|
||||
-- this option is introduced.
|
||||
data BackwardsCompatibleNullInNonNullableVariables
|
||||
= AllowNullInNonNullableVariables
|
||||
| Don'tAllowNullInNonNullableVariables
|
||||
deriving (Eq, Show)
|
||||
|
||||
instance FromJSON BackwardsCompatibleNullInNonNullableVariables where
|
||||
parseJSON =
|
||||
withBool "BackwardsCompatibleNullInNonNullableVariables"
|
||||
$ pure
|
||||
. bool Don'tAllowNullInNonNullableVariables AllowNullInNonNullableVariables
|
||||
|
||||
instance ToJSON BackwardsCompatibleNullInNonNullableVariables where
|
||||
toJSON = \case
|
||||
AllowNullInNonNullableVariables -> Bool True
|
||||
Don'tAllowNullInNonNullableVariables -> Bool False
|
||||
|
||||
data RemoteNullForwardingPolicy
|
||||
= RemoteForwardAccurately
|
||||
| RemoteOnlyForwardNonNull
|
||||
|
@ -79,6 +79,7 @@ import Hasura.RQL.DDL.EventTrigger (MonadEventLogCleanup)
|
||||
import Hasura.RQL.DDL.Schema
|
||||
import Hasura.RQL.DDL.Schema.Cache.Config
|
||||
import Hasura.RQL.Types.BackendType
|
||||
import Hasura.RQL.Types.Common (SQLGenCtx (nullInNonNullableVariables))
|
||||
import Hasura.RQL.Types.Endpoint as EP
|
||||
import Hasura.RQL.Types.OpenTelemetry (getOtelTracesPropagator)
|
||||
import Hasura.RQL.Types.Roles (adminRoleName, roleNameToTxt)
|
||||
@ -648,7 +649,8 @@ gqlExplainHandler query = do
|
||||
schemaCache <- asks hcSchemaCache
|
||||
reqHeaders <- asks hcReqHeaders
|
||||
licenseKeyCache <- asks hcLicenseKeyCache
|
||||
res <- GE.explainGQLQuery (lastBuiltSchemaCache schemaCache) licenseKeyCache reqHeaders query
|
||||
nullInNonNullableVariables <- asks (nullInNonNullableVariables . acSQLGenCtx . hcAppContext)
|
||||
res <- GE.explainGQLQuery nullInNonNullableVariables (lastBuiltSchemaCache schemaCache) licenseKeyCache reqHeaders query
|
||||
return $ HttpResponse res []
|
||||
|
||||
v1Alpha1PGDumpHandler :: (MonadIO m, MonadError QErr m, MonadReader HandlerCtx m) => PGD.PGDumpReqBody -> m APIResp
|
||||
|
@ -169,6 +169,7 @@ mkServeOptions sor@ServeOptionsRaw {..} = do
|
||||
Options.Don'tStringifyNumbers -> withOptionDefault Nothing stringifyNumOption
|
||||
stringifyNums -> pure stringifyNums
|
||||
soDangerousBooleanCollapse <- withOptionDefault rsoDangerousBooleanCollapse dangerousBooleanCollapseOption
|
||||
soBackwardsCompatibleNullInNonNullableVariables <- withOptionDefault rsoBackwardsCompatibleNullInNonNullableVariables backwardsCompatibleNullInNonNullableVariablesOption
|
||||
soRemoteNullForwardingPolicy <- withOptionDefault rsoRemoteNullForwardingPolicy remoteNullForwardingPolicyOption
|
||||
soEnabledAPIs <- withOptionDefault rsoEnabledAPIs enabledAPIsOption
|
||||
soLiveQueryOpts <- do
|
||||
|
@ -31,6 +31,7 @@ module Hasura.Server.Init.Arg.Command.Serve
|
||||
wsReadCookieOption,
|
||||
stringifyNumOption,
|
||||
dangerousBooleanCollapseOption,
|
||||
backwardsCompatibleNullInNonNullableVariablesOption,
|
||||
remoteNullForwardingPolicyOption,
|
||||
enabledAPIsOption,
|
||||
mxRefetchDelayOption,
|
||||
@ -124,6 +125,7 @@ serveCommandParser =
|
||||
<*> parseWsReadCookie
|
||||
<*> parseStringifyNum
|
||||
<*> parseDangerousBooleanCollapse
|
||||
<*> parseBackwardsCompatibleNullInNonNullableVariables
|
||||
<*> parseRemoteNullForwardingPolicy
|
||||
<*> parseEnabledAPIs
|
||||
<*> parseMxRefetchDelay
|
||||
@ -638,6 +640,26 @@ dangerousBooleanCollapseOption =
|
||||
<> " [DEPRECATED, WILL BE REMOVED SOON] (default: false)"
|
||||
}
|
||||
|
||||
parseBackwardsCompatibleNullInNonNullableVariables :: Opt.Parser (Maybe Options.BackwardsCompatibleNullInNonNullableVariables)
|
||||
parseBackwardsCompatibleNullInNonNullableVariables =
|
||||
Opt.optional
|
||||
$ Opt.option
|
||||
(Opt.eitherReader Env.fromEnv)
|
||||
( Opt.long "null-in-nonnullable-variables"
|
||||
<> Opt.help (Config._helpMessage backwardsCompatibleNullInNonNullableVariablesOption)
|
||||
)
|
||||
|
||||
backwardsCompatibleNullInNonNullableVariablesOption :: Config.Option Options.BackwardsCompatibleNullInNonNullableVariables
|
||||
backwardsCompatibleNullInNonNullableVariablesOption =
|
||||
Config.Option
|
||||
{ Config._default = Options.Don'tAllowNullInNonNullableVariables,
|
||||
Config._envVar = "HASURA_GRAPHQL_BACKWARDS_COMPAT_NULL_IN_NONNULLABLE_VARIABLES",
|
||||
Config._helpMessage =
|
||||
"Emulate unexpected behavior of allowing 'null' values for non-nullable variables"
|
||||
<> " exists before v2.34.0."
|
||||
<> " [DEPRECATED, WILL BE REMOVED SOON] (default: false)"
|
||||
}
|
||||
|
||||
parseRemoteNullForwardingPolicy :: Opt.Parser (Maybe Options.RemoteNullForwardingPolicy)
|
||||
parseRemoteNullForwardingPolicy =
|
||||
fmap (bool Nothing (Just Options.RemoteOnlyForwardNonNull))
|
||||
|
@ -290,6 +290,7 @@ data ServeOptionsRaw impl = ServeOptionsRaw
|
||||
rsoWsReadCookie :: WsReadCookieStatus,
|
||||
rsoStringifyNum :: Schema.Options.StringifyNumbers,
|
||||
rsoDangerousBooleanCollapse :: Maybe Schema.Options.DangerouslyCollapseBooleans,
|
||||
rsoBackwardsCompatibleNullInNonNullableVariables :: Maybe Schema.Options.BackwardsCompatibleNullInNonNullableVariables,
|
||||
rsoRemoteNullForwardingPolicy :: Maybe Schema.Options.RemoteNullForwardingPolicy,
|
||||
rsoEnabledAPIs :: Maybe (HashSet API),
|
||||
rsoMxRefetchInt :: Maybe Subscription.Options.RefetchInterval,
|
||||
@ -596,6 +597,7 @@ data ServeOptions impl = ServeOptions
|
||||
soEnableTelemetry :: TelemetryStatus,
|
||||
soStringifyNum :: Schema.Options.StringifyNumbers,
|
||||
soDangerousBooleanCollapse :: Schema.Options.DangerouslyCollapseBooleans,
|
||||
soBackwardsCompatibleNullInNonNullableVariables :: Schema.Options.BackwardsCompatibleNullInNonNullableVariables,
|
||||
soRemoteNullForwardingPolicy :: Schema.Options.RemoteNullForwardingPolicy,
|
||||
soEnabledAPIs :: HashSet API,
|
||||
soLiveQueryOpts :: Subscription.Options.LiveQueriesOptions,
|
||||
|
@ -253,6 +253,9 @@ instance FromEnv Options.RemoteSchemaPermissions where
|
||||
instance FromEnv Options.DangerouslyCollapseBooleans where
|
||||
fromEnv = fmap (bool Options.Don'tDangerouslyCollapseBooleans Options.DangerouslyCollapseBooleans) . fromEnv @Bool
|
||||
|
||||
instance FromEnv Options.BackwardsCompatibleNullInNonNullableVariables where
|
||||
fromEnv = fmap (bool Options.Don'tAllowNullInNonNullableVariables Options.AllowNullInNonNullableVariables) . fromEnv @Bool
|
||||
|
||||
instance FromEnv Options.RemoteNullForwardingPolicy where
|
||||
fromEnv = fmap (bool Options.RemoteForwardAccurately Options.RemoteOnlyForwardNonNull) . fromEnv @Bool
|
||||
|
||||
|
@ -160,7 +160,7 @@ runQueryParser ::
|
||||
HashMap.HashMap G.Name J.Value ->
|
||||
any
|
||||
runQueryParser parser (varDefs, selSet) vars = runIdentity . runError $ do
|
||||
(_, resolvedSelSet) <- resolveVariables varDefs vars [] selSet
|
||||
(_, resolvedSelSet) <- resolveVariables Options.Don'tAllowNullInNonNullableVariables varDefs vars [] selSet
|
||||
field <- case resolvedSelSet of
|
||||
[G.SelectionField f] -> pure f
|
||||
_ -> error "expecting only one field in the query"
|
||||
|
@ -64,6 +64,7 @@ emptyServeOptionsRaw =
|
||||
rsoWsReadCookie = UUT.WsReadCookieDisabled,
|
||||
rsoStringifyNum = Options.Don'tStringifyNumbers,
|
||||
rsoDangerousBooleanCollapse = Nothing,
|
||||
rsoBackwardsCompatibleNullInNonNullableVariables = Nothing,
|
||||
rsoRemoteNullForwardingPolicy = Nothing,
|
||||
rsoEnabledAPIs = Nothing,
|
||||
rsoMxRefetchInt = Nothing,
|
||||
@ -627,6 +628,37 @@ mkServeOptionsSpec =
|
||||
|
||||
fmap UUT.soDangerousBooleanCollapse result `Hspec.shouldBe` Right Options.Don'tDangerouslyCollapseBooleans
|
||||
|
||||
Hspec.describe "soBackwardsCompatibleNullInNonNullableVariables" $ do
|
||||
Hspec.it "Default == False" $ do
|
||||
let -- Given
|
||||
rawServeOptions = emptyServeOptionsRaw
|
||||
-- When
|
||||
env = []
|
||||
-- Then
|
||||
result = UUT.runWithEnv env (UUT.mkServeOptions @Hasura rawServeOptions)
|
||||
|
||||
fmap UUT.soBackwardsCompatibleNullInNonNullableVariables result `Hspec.shouldBe` Right (UUT._default UUT.backwardsCompatibleNullInNonNullableVariablesOption)
|
||||
|
||||
Hspec.it "Env > Nothing" $ do
|
||||
let -- Given
|
||||
rawServeOptions = emptyServeOptionsRaw
|
||||
-- When
|
||||
env = [(UUT._envVar UUT.backwardsCompatibleNullInNonNullableVariablesOption, "true")]
|
||||
-- Then
|
||||
result = UUT.runWithEnv env (UUT.mkServeOptions @Hasura rawServeOptions)
|
||||
|
||||
fmap UUT.soBackwardsCompatibleNullInNonNullableVariables result `Hspec.shouldBe` Right Options.AllowNullInNonNullableVariables
|
||||
|
||||
Hspec.it "Arg > Env" $ do
|
||||
let -- Given
|
||||
rawServeOptions = emptyServeOptionsRaw {UUT.rsoBackwardsCompatibleNullInNonNullableVariables = Just Options.Don'tAllowNullInNonNullableVariables}
|
||||
-- When
|
||||
env = [(UUT._envVar UUT.dangerousBooleanCollapseOption, "true")]
|
||||
-- Then
|
||||
result = UUT.runWithEnv env (UUT.mkServeOptions @Hasura rawServeOptions)
|
||||
|
||||
fmap UUT.soBackwardsCompatibleNullInNonNullableVariables result `Hspec.shouldBe` Right Options.Don'tAllowNullInNonNullableVariables
|
||||
|
||||
Hspec.describe "soEnabledAPIs" $ do
|
||||
Hspec.it "Default == metadata,graphql,pgdump,config" $ do
|
||||
let -- Given
|
||||
|
@ -62,6 +62,7 @@ serveOptions =
|
||||
soEnableTelemetry = Init.TelemetryDisabled,
|
||||
soStringifyNum = Options.Don'tStringifyNumbers,
|
||||
soDangerousBooleanCollapse = Options.Don'tDangerouslyCollapseBooleans,
|
||||
soBackwardsCompatibleNullInNonNullableVariables = Options.Don'tAllowNullInNonNullableVariables,
|
||||
soRemoteNullForwardingPolicy = Options.RemoteForwardAccurately,
|
||||
soEnabledAPIs = testSuiteEnabledApis,
|
||||
soLiveQueryOpts = ES.mkSubscriptionsOptions Nothing Nothing,
|
||||
|
@ -106,6 +106,7 @@ main = do
|
||||
SQLGenCtx
|
||||
Options.Don'tStringifyNumbers
|
||||
Options.Don'tDangerouslyCollapseBooleans
|
||||
Options.Don'tAllowNullInNonNullableVariables
|
||||
Options.RemoteForwardAccurately
|
||||
Options.Don'tOptimizePermissionFilters
|
||||
Options.EnableBigQueryStringNumericInput
|
||||
|
@ -19,8 +19,11 @@
|
||||
url: /v1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
author: []
|
||||
errors:
|
||||
- extensions:
|
||||
code: validation-failed
|
||||
path: $
|
||||
message: 'null value found for non-nullable type: "Int!"'
|
||||
query:
|
||||
variables:
|
||||
limit: null
|
||||
@ -45,7 +48,7 @@
|
||||
variables:
|
||||
author_id: null
|
||||
query: |
|
||||
mutation update_author($author_id: Int!) {
|
||||
mutation update_author($author_id: Int) {
|
||||
update_author(where: {id: {_eq: $author_id}}, _set: {name: ""}) {
|
||||
returning {
|
||||
id
|
||||
|
Loading…
Reference in New Issue
Block a user