feat: Handle logical models in metadata when the feature is disabled

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/8443
GitOrigin-RevId: 4df0f62979dc78103b786b6f0f8ffcde6def0739
This commit is contained in:
Philip Lykke Carlsen 2023-03-28 13:55:33 +02:00 committed by hasura-bot
parent 2fb455b813
commit 926d5ecdb0
4 changed files with 175 additions and 25 deletions

View File

@ -3,6 +3,9 @@
-- | Tests of the Logical Models feature.
module Test.API.Metadata.LogicalModelsSpec (spec) where
import Control.Lens
import Data.Aeson qualified as A
import Data.Aeson.Lens
import Data.List.NonEmpty qualified as NE
import Harness.Backend.BigQuery qualified as BigQuery
import Harness.Backend.Citus qualified as Citus
@ -10,13 +13,17 @@ import Harness.Backend.Cockroach qualified as Cockroach
import Harness.Backend.Postgres qualified as Postgres
import Harness.Backend.Sqlserver qualified as Sqlserver
import Harness.GraphqlEngine qualified as GraphqlEngine
import Harness.Quoter.Graphql
import Harness.Quoter.Yaml (yaml)
import Harness.Quoter.Yaml.InterpolateYaml
import Harness.Services.GraphqlEngine
import Harness.Services.Metadata
import Harness.Services.PostgresSource
import Harness.Test.BackendType qualified as BackendType
import Harness.Test.Fixture qualified as Fixture
import Harness.Test.Schema qualified as Schema
import Harness.TestEnvironment (GlobalTestEnvironment, TestEnvironment (options), getBackendTypeConfig, scalarTypeToText)
import Harness.Yaml (shouldReturnYaml)
import Harness.Yaml (shouldBeYaml, shouldReturnYaml)
import Hasura.Prelude
import Test.Hspec (SpecWith, describe, it)
@ -69,6 +76,8 @@ spec = do
(Fixture.runClean fixtures)
[testImplementation, testPermissions]
metadataHandlingWhenDisabledSpec
-- ** Setup and teardown
schema :: [Schema.Table]
@ -611,3 +620,109 @@ testPermissionFailures = do
error: *expectedError
path: "$.args"
|]
metadataHandlingWhenDisabledSpec :: SpecWith GlobalTestEnvironment
metadataHandlingWhenDisabledSpec = do
describe "When logical models are enabled" do
withHge
( emptyHgeConfig
{ hgeConfigEnvironmentVars =
[ (featureFlagForLogicalModels, "True")
]
}
)
$ withPostgresSource "default"
$ do
it "`replace_metadata` does not report any inconsistent objects" $ \env -> do
currentMetadata <- export_metadata env
actual <- replace_metadata env (metadataWithLogicalModel currentMetadata)
actual
`shouldBeYaml` [yaml|
inconsistent_objects: []
is_consistent: true
|]
it "They do appear in the schema" $ \env -> do
currentMetadata <- export_metadata env
_res <- replace_metadata env (metadataWithLogicalModel currentMetadata)
let expected =
[yaml|
data:
__type:
name: divided_stuff
|]
actual <- hgePostGraphql env queryTypesIntrospection
actual `shouldBeYaml` expected
describe "When logical models are disabled" do
withHge emptyHgeConfig $ do
withPostgresSource "default" $ do
it "`replace_metadata` preserves logical models" $ \env -> do
currentMetadata <- export_metadata env
_ <- replace_metadata env (metadataWithLogicalModel currentMetadata)
actual <- export_metadata env
actual `shouldBeYaml` (metadataWithLogicalModel currentMetadata)
it "`replace_metadata` reports inconsistent objects" $ \env -> do
currentMetadata <- export_metadata env
actual <- replace_metadata env (metadataWithLogicalModel currentMetadata)
actual
`shouldBeYaml` [yaml|
inconsistent_objects:
- definition: *logicalModelsMetadata
name: logical_model divided_stuff in source default
reason: 'Inconsistent object: The Logical Models feature is disabled'
type: logical_model
is_consistent: false
|]
it "They do not appear in the schema" $ \env -> do
currentMetadata <- export_metadata env
_res <- replace_metadata env (metadataWithLogicalModel currentMetadata)
let expected =
[yaml|
data:
__type: null
|]
actual <- hgePostGraphql env queryTypesIntrospection
actual `shouldBeYaml` expected
where
logicalModelsMetadata =
[yaml|
arguments:
divided:
nullable: false
type: int
code: SELECT {{divided}} as divided
returns:
columns:
- name: divided
description: a divided thing
nullable: false
type: integer
root_field_name: divided_stuff
|]
metadataWithLogicalModel :: A.Value -> A.Value
metadataWithLogicalModel currentMetadata =
currentMetadata
& key "sources"
. nth 0
. atKey "logical_models"
.~ Just [yaml| - *logicalModelsMetadata |]
queryTypesIntrospection :: A.Value
queryTypesIntrospection =
[graphql|
query {
__type(name: "divided_stuff") {
name
}
}
|]

View File

@ -9,6 +9,7 @@ module Harness.Services.GraphqlEngine
spawnServer,
emptyHgeConfig,
hgePost,
hgePostGraphql,
)
where
@ -280,10 +281,10 @@ hgeLogRelayThread logger hgeOutput = do
logParser = json' <* (option () (void (string "\n")) <|> endOfInput)
hgePost ::
( Has HgeServerInstance a,
Has Logger a
( Has HgeServerInstance env,
Has Logger env
) =>
a ->
env ->
Int ->
Text ->
Http.RequestHeaders ->
@ -296,3 +297,13 @@ hgePost env statusCode path headers requestBody = do
responseBody <- withFrozenCallStack $ Http.postValueWithStatus statusCode fullUrl headers requestBody
testLogMessage env $ LogHGEResponse path responseBody
return responseBody
hgePostGraphql ::
( Has HgeServerInstance env,
Has Logger env
) =>
env ->
Value ->
IO Value
hgePostGraphql env query = do
hgePost env 200 "/v1/graphql" [] (object ["query" .= query])

View File

@ -23,11 +23,13 @@ withPostgresSource ::
SpecWith (PostgresSource, a) ->
SpecWith a
withPostgresSource sourceName specs =
flip aroundWith specs \action env -> do
pg_add_source env sourceName
-- TODO assert that res is a success result
-- TODO: use 'managed'?
action (PostgresSource sourceName, env)
-- We mark "Postgres" to interoperate with HASURA_TEST_BACKEND_TYPE.
describe "Postgres" $
flip aroundWith specs \action env -> do
pg_add_source env sourceName
-- TODO assert that res is a success result
-- TODO: use 'managed'?
action (PostgresSource sourceName, env)
pg_add_source ::
( Has Logger env,

View File

@ -92,6 +92,7 @@ import Hasura.SQL.Backend
import Hasura.SQL.BackendMap (BackendMap)
import Hasura.SQL.BackendMap qualified as BackendMap
import Hasura.SQL.Tag
import Hasura.Server.Init.FeatureFlag qualified as FF
import Hasura.Server.Migrate.Version
import Hasura.Server.Types
import Hasura.Services
@ -624,6 +625,7 @@ buildSchemaCacheRule logger env = proc (metadataNoDefaults, serverConfigCtx, inv
ArrowKleisli m arr,
ArrowWriter (Seq (Either InconsistentMetadata MetadataDependency)) arr,
MonadError QErr m,
MonadIO m,
BackendMetadata b,
GetAggregationPredicatesDeps b
) =>
@ -722,30 +724,50 @@ buildSchemaCacheRule logger env = proc (metadataNoDefaults, serverConfigCtx, inv
let functionCache = mapFromL _fiSQLName $ catMaybes functionCacheMaybes
areLogicalModelsEnabled <-
bindA
-< do
let CheckFeatureFlag checkFeatureFlag = _sccCheckFeatureFlag serverConfigCtx
liftIO @m $ checkFeatureFlag FF.logicalModelInterface
let mkLogicalModelMetadataObject :: LogicalModelMetadata b -> MetadataObject
mkLogicalModelMetadataObject lmm =
( MetadataObject
( MOSourceObjId sourceName $
AB.mkAnyBackend $
SMOLogicalModel @b (_lmmRootFieldName lmm)
)
(toJSON lmm)
)
logicalModelCacheMaybes <-
interpretWriter
-< for
(OMap.elems logicalModels)
\LogicalModelMetadata {..} -> runExceptT do
fieldInfoMap <- case toFieldInfo _lmmReturns of
Nothing -> pure mempty
Just fields -> pure (mapFromL fieldInfoName fields)
\lmm@LogicalModelMetadata {..} ->
withRecordInconsistencyM (mkLogicalModelMetadataObject lmm) $ do
unless areLogicalModelsEnabled $
throw400 InvalidConfiguration "The Logical Models feature is disabled"
logicalModelPermissions <-
buildLogicalModelPermissions sourceName tableCoreInfos _lmmRootFieldName fieldInfoMap _lmmSelectPermissions orderedRoles
fieldInfoMap <- case toFieldInfo _lmmReturns of
Nothing -> pure mempty
Just fields -> pure (mapFromL fieldInfoName fields)
pure
LogicalModelInfo
{ _lmiRootFieldName = _lmmRootFieldName,
_lmiCode = _lmmCode,
_lmiReturns = _lmmReturns,
_lmiArguments = _lmmArguments,
_lmiPermissions = logicalModelPermissions,
_lmiDescription = _lmmDescription
}
logicalModelPermissions <-
buildLogicalModelPermissions sourceName tableCoreInfos _lmmRootFieldName fieldInfoMap _lmmSelectPermissions orderedRoles
pure
LogicalModelInfo
{ _lmiRootFieldName = _lmmRootFieldName,
_lmiCode = _lmmCode,
_lmiReturns = _lmmReturns,
_lmiArguments = _lmmArguments,
_lmiPermissions = logicalModelPermissions,
_lmiDescription = _lmmDescription
}
let logicalModelCache :: LogicalModelCache b
logicalModelCache = mapFromL _lmiRootFieldName (mapMaybe eitherToMaybe logicalModelCacheMaybes)
logicalModelCache = mapFromL _lmiRootFieldName (catMaybes logicalModelCacheMaybes)
returnA -< SourceInfo sourceName tableCache functionCache logicalModelCache sourceConfig queryTagsConfig resolvedCustomization