server: collect remote schema and database introspections while building schema cache

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/9297
GitOrigin-RevId: 143f50be2eba382d129669e26ef3a7eb24c921ca
This commit is contained in:
Rakesh Emmadi 2023-06-01 22:02:38 +05:30 committed by hasura-bot
parent 800be3c915
commit 427ca18e85
16 changed files with 285 additions and 140 deletions

View File

@ -185,6 +185,24 @@ instance FromJSON RestType where
"STRUCT" -> pure STRUCT
_ -> fail ("invalid type " ++ show s)
instance ToJSON RestType where
toJSON =
String . \case
STRING -> "STRING"
BYTES -> "BYTES"
INTEGER -> "INTEGER"
FLOAT -> "FLOAT"
BOOL -> "BOOLEAN"
TIMESTAMP -> "TIMESTAMP"
DATE -> "DATE"
TIME -> "TIME"
DATETIME -> "DATETIME"
GEOGRAPHY -> "GEOGRAPHY"
DECIMAL -> "DECIMAL"
BIGDECIMAL -> "BIGDECIMAL"
JSON -> "JSON"
STRUCT -> "STRUCT"
--------------------------------------------------------------------------------
-- REST request
@ -304,6 +322,8 @@ data RestRoutineType
instance FromJSON RestRoutineType
instance ToJSON RestRoutineType
-- | Input argument of a function/routine.
-- Ref: https://cloud.google.com/bigquery/docs/reference/rest/v2/routines#Argument
data RestArgument = RestArgument
@ -331,6 +351,13 @@ instance FromJSON RestArgument where
pure $ RestArgument name type'
)
instance ToJSON RestArgument where
toJSON (RestArgument name ty) =
object
[ "name" .= name,
"dataType" .= object ["typeKind" .= ty]
]
-- | A field or a column.
-- Ref: https://cloud.google.com/bigquery/docs/reference/rest/v2/StandardSqlField
data RestStandardSqlField = RestStandardSqlField
@ -358,6 +385,10 @@ instance FromJSON RestStandardSqlField where
pure $ RestStandardSqlField name type'
)
instance ToJSON RestStandardSqlField where
toJSON (RestStandardSqlField name ty) =
object ["name" .= name, "type" .= (object ["typeKind" .= ty])]
-- | A table type, which has only list of columns with names and types.
-- Ref: https://cloud.google.com/bigquery/docs/reference/rest/v2/routines#StandardSqlTableType
data RestStandardSqlTableType = RestStandardSqlTableType
@ -368,6 +399,9 @@ data RestStandardSqlTableType = RestStandardSqlTableType
instance FromJSON RestStandardSqlTableType where
parseJSON = genericParseJSON hasuraJSON
instance ToJSON RestStandardSqlTableType where
toJSON = genericToJSON hasuraJSON
-- | Id path of a routine.
-- Ref: https://cloud.google.com/bigquery/docs/reference/rest/v2/routines#RoutineReference
data RestRoutineReference = RestRoutineReference
@ -379,6 +413,8 @@ data RestRoutineReference = RestRoutineReference
instance FromJSON RestRoutineReference
instance ToJSON RestRoutineReference
routineReferenceToFunctionName :: RestRoutineReference -> FunctionName
routineReferenceToFunctionName RestRoutineReference {..} =
FunctionName {functionName = routineId, functionNameSchema = Just datasetId}
@ -399,6 +435,8 @@ data RestRoutine = RestRoutine
instance FromJSON RestRoutine
instance ToJSON RestRoutine
-- | List of routines
-- Ref: https://cloud.google.com/bigquery/docs/reference/rest/v2/routines/list
data RestRoutineList = RestRoutineList

View File

@ -217,7 +217,7 @@ resolveBackendInfo' ::
( ArrowChoice arr,
Inc.ArrowCache m arr,
Inc.ArrowDistribute arr,
ArrowWriter (Seq (Either InconsistentMetadata MetadataDependency)) arr,
ArrowWriter (Seq CollectItem) arr,
MonadIO m,
MonadBaseControl IO m,
ProvidesNetwork m

View File

@ -344,6 +344,8 @@ deriving newtype instance (Backend b) => Show (FunctionOverloads b)
deriving newtype instance (FromJSON (RawFunctionInfo b)) => FromJSON (FunctionOverloads b)
deriving newtype instance (ToJSON (RawFunctionInfo b)) => ToJSON (FunctionOverloads b)
data FunctionArgsExpG a = FunctionArgsExp
{ _faePositional :: [a],
_faeNamed :: (HashMap.HashMap Text a)

View File

@ -21,7 +21,6 @@ import Data.Aeson
import Hasura.Base.Error
import Hasura.Eventing.ScheduledTrigger.Types
import Hasura.Prelude
import Hasura.RQL.DDL.Schema.Cache.Common (StoredIntrospection)
import Hasura.RQL.Types.Action
import Hasura.RQL.Types.EECredentials
import Hasura.RQL.Types.EventTrigger

View File

@ -173,7 +173,7 @@ buildRebuildableSchemaCacheWithReason reason logger env metadataWithVersion dyna
flip runReaderT reason
$ Inc.build (buildSchemaCacheRule logger env mSchemaRegistryContext) (metadataWithVersion, dynamicConfig, initialInvalidationKeys, Nothing)
pure $ RebuildableSchemaCache (Inc.result result) initialInvalidationKeys (Inc.rebuildRule result)
pure $ RebuildableSchemaCache (fst $ Inc.result result) initialInvalidationKeys (Inc.rebuildRule result)
newtype CacheRWT m a
= -- The CacheInvalidations component of the state could actually be collected
@ -253,7 +253,7 @@ instance
runCacheBuildM
$ flip runReaderT buildReason
$ Inc.build rule (metadataWithVersion, dynamicConfig, newInvalidationKeys, storedIntrospection)
let schemaCache = Inc.result result
let (schemaCache, _storedIntrospectionStatus) = Inc.result result
prunedInvalidationKeys = pruneInvalidationKeys schemaCache newInvalidationKeys
!newCache = RebuildableSchemaCache schemaCache prunedInvalidationKeys (Inc.rebuildRule result)
!newInvalidations = oldInvalidations <> invalidations
@ -315,6 +315,45 @@ buildSourcePingCache sources =
connection = _smConfiguration sourceMetadata
in SourcePingInfo sourceName connection
partitionCollectedInfo ::
Seq CollectItem -> ([InconsistentMetadata], [MetadataDependency], [StoredIntrospectionItem])
partitionCollectedInfo =
let go item = case item of
CollectInconsistentMetadata inconsistentMetadata ->
_1 %~ ([inconsistentMetadata] <>)
CollectMetadataDependency dependency ->
_2 %~ ([dependency] <>)
CollectStoredIntrospection storedIntrospection ->
_3 %~ ([storedIntrospection] <>)
in foldr go ([], [], []) . toList
buildStoredIntrospectionStatus ::
Sources -> RemoteSchemas -> [StoredIntrospectionItem] -> StoredIntrospectionStatus
buildStoredIntrospectionStatus sourcesMetadata remoteSchemasMetadata = \case
[] -> StoredIntrospectionUnchanged
items ->
let go item (sources, remoteSchemas) = case item of
SourceIntrospectionItem name introspection ->
(sources <> [(name, introspection)], remoteSchemas)
RemoteSchemaIntrospectionItem name introspection ->
(sources, remoteSchemas <> [(name, introspection)])
(allSources, allRemoteSchemas) = foldr go ([], []) items
storedIntrospection = StoredIntrospection (HashMap.fromList allSources) (HashMap.fromList allRemoteSchemas)
in if allSourcesAndRemoteSchemasCollected allSources allRemoteSchemas
then StoredIntrospectionChangedFull storedIntrospection
else StoredIntrospectionChangedPartial storedIntrospection
where
allSourcesAndRemoteSchemasCollected ::
[(SourceName, sourceIntrospection)] ->
[(RemoteSchemaName, remoteSchemaIntrospection)] ->
Bool
allSourcesAndRemoteSchemasCollected sources remoteSchemas =
allPresent sourcesMetadata (map fst sources)
&& allPresent remoteSchemasMetadata (map fst remoteSchemas)
allPresent :: (Hashable a) => InsOrdHashMap a b -> [a] -> Bool
allPresent hashMap = all (`InsOrdHashMap.member` hashMap)
{- Note [Avoiding GraphQL schema rebuilds when changing irrelevant Metadata]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There are many Metadata operations that don't influence the GraphQL schema. So
@ -359,17 +398,18 @@ buildSchemaCacheRule ::
Logger Hasura ->
Env.Environment ->
Maybe SchemaRegistryContext ->
(MetadataWithResourceVersion, CacheDynamicConfig, InvalidationKeys, Maybe StoredIntrospection) `arr` SchemaCache
(MetadataWithResourceVersion, CacheDynamicConfig, InvalidationKeys, Maybe StoredIntrospection) `arr` (SchemaCache, StoredIntrospectionStatus)
buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResourceVersion metadataNoDefaults metadataResourceVersion, dynamicConfig, invalidationKeys, storedIntrospection) -> do
invalidationKeysDep <- Inc.newDependency -< invalidationKeys
let metadataDefaults = _cdcMetadataDefaults dynamicConfig
metadata@Metadata {..} = overrideMetadataDefaults metadataNoDefaults metadataDefaults
metadataDep <- Inc.newDependency -< metadata
(inconsistentObjects, (resolvedOutputs, dependencyInconsistentObjects, resolvedDependencies), ((adminIntrospection, gqlContext, gqlContextUnauth, inconsistentRemoteSchemas), (relayContext, relayContextUnauth), schemaRegistryAction)) <-
(inconsistentObjects, storedIntrospections, (resolvedOutputs, dependencyInconsistentObjects, resolvedDependencies), ((adminIntrospection, gqlContext, gqlContextUnauth, inconsistentRemoteSchemas), (relayContext, relayContextUnauth), schemaRegistryAction)) <-
Inc.cache buildOutputsAndSchema -< (metadataDep, dynamicConfig, invalidationKeysDep, storedIntrospection)
let (resolvedEndpoints, endpointCollectedInfo) = runIdentity $ runWriterT $ buildRESTEndpoints _metaQueryCollections (InsOrdHashMap.elems _metaRestEndpoints)
let storedIntrospectionStatus = buildStoredIntrospectionStatus _metaSources _metaRemoteSchemas storedIntrospections
(resolvedEndpoints, endpointCollectedInfo) = runIdentity $ runWriterT $ buildRESTEndpoints _metaQueryCollections (InsOrdHashMap.elems _metaRestEndpoints)
(cronTriggersMap, cronTriggersCollectedInfo) = runIdentity $ runWriterT $ buildCronTriggers (InsOrdHashMap.elems _metaCronTriggers)
(openTelemetryInfo, openTelemetryCollectedInfo) = runIdentity $ runWriterT $ buildOpenTelemetry _metaOpenTelemetryConfig
@ -408,13 +448,13 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
globalAllowLists = HS.toList . iaGlobal $ inlinedAllowlist
-- Endpoints don't generate any dependencies
endpointInconsistencies = either id absurd <$> toList endpointCollectedInfo
(endpointInconsistencies, _, _) = partitionCollectedInfo endpointCollectedInfo
-- Cron triggers don't generate any dependencies
cronTriggersInconsistencies = either id absurd <$> toList cronTriggersCollectedInfo
(cronTriggersInconsistencies, _, _) = partitionCollectedInfo cronTriggersCollectedInfo
-- OpenTelemerty doesn't generate any dependencies
openTelemetryInconsistencies = either id absurd <$> toList openTelemetryCollectedInfo
(openTelemetryInconsistencies, _, _) = partitionCollectedInfo openTelemetryCollectedInfo
inconsistentQueryCollections = getInconsistentQueryCollections adminIntrospection _metaQueryCollections listedQueryObjects endpoints globalAllowLists
@ -425,53 +465,53 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
for_ schemaRegistryAction $ \action -> do
liftIO $ action metadataResourceVersion
returnA
-<
SchemaCache
{ scSources = _boSources resolvedOutputs,
scActions = _boActions resolvedOutputs,
-- TODO this is not the right value: we should track what part of the schema
-- we can stitch without consistencies, I think.
scRemoteSchemas = fmap fst (_boRemoteSchemas resolvedOutputs), -- remoteSchemaMap
scAllowlist = inlinedAllowlist,
-- , scCustomTypes = _boCustomTypes resolvedOutputs
scAdminIntrospection = adminIntrospection,
scGQLContext = gqlContext,
scUnauthenticatedGQLContext = gqlContextUnauth,
scRelayContext = relayContext,
scUnauthenticatedRelayContext = relayContextUnauth,
-- , scGCtxMap = gqlSchema
-- , scDefaultRemoteGCtx = remoteGQLSchema
scDepMap = resolvedDependencies,
scCronTriggers = cronTriggersMap,
scEndpoints = endpoints,
scInconsistentObjs =
inconsistentObjects
<> dependencyInconsistentObjects
<> toList inconsistentRemoteSchemas
<> duplicateRestVariables
<> invalidRestSegments
<> ambiguousRestEndpoints
<> endpointInconsistencies
<> cronTriggersInconsistencies
<> openTelemetryInconsistencies
<> inconsistentQueryCollections,
scApiLimits = _metaApiLimits,
scMetricsConfig = _metaMetricsConfig,
scMetadataResourceVersion = metadataResourceVersion,
scSetGraphqlIntrospectionOptions = _metaSetGraphqlIntrospectionOptions,
scTlsAllowlist = networkTlsAllowlist _metaNetwork,
scQueryCollections = _metaQueryCollections,
scBackendCache = _boBackendCache resolvedOutputs,
scSourceHealthChecks = buildHealthCheckCache _metaSources,
scSourcePingConfig = buildSourcePingCache _metaSources,
scOpenTelemetryConfig = openTelemetryInfo
}
let schemaCache =
SchemaCache
{ scSources = _boSources resolvedOutputs,
scActions = _boActions resolvedOutputs,
-- TODO this is not the right value: we should track what part of the schema
-- we can stitch without consistencies, I think.
scRemoteSchemas = fmap fst (_boRemoteSchemas resolvedOutputs), -- remoteSchemaMap
scAllowlist = inlinedAllowlist,
-- , scCustomTypes = _boCustomTypes resolvedOutputs
scAdminIntrospection = adminIntrospection,
scGQLContext = gqlContext,
scUnauthenticatedGQLContext = gqlContextUnauth,
scRelayContext = relayContext,
scUnauthenticatedRelayContext = relayContextUnauth,
-- , scGCtxMap = gqlSchema
-- , scDefaultRemoteGCtx = remoteGQLSchema
scDepMap = resolvedDependencies,
scCronTriggers = cronTriggersMap,
scEndpoints = endpoints,
scInconsistentObjs =
inconsistentObjects
<> dependencyInconsistentObjects
<> toList inconsistentRemoteSchemas
<> duplicateRestVariables
<> invalidRestSegments
<> ambiguousRestEndpoints
<> endpointInconsistencies
<> cronTriggersInconsistencies
<> openTelemetryInconsistencies
<> inconsistentQueryCollections,
scApiLimits = _metaApiLimits,
scMetricsConfig = _metaMetricsConfig,
scMetadataResourceVersion = metadataResourceVersion,
scSetGraphqlIntrospectionOptions = _metaSetGraphqlIntrospectionOptions,
scTlsAllowlist = networkTlsAllowlist _metaNetwork,
scQueryCollections = _metaQueryCollections,
scBackendCache = _boBackendCache resolvedOutputs,
scSourceHealthChecks = buildHealthCheckCache _metaSources,
scSourcePingConfig = buildSourcePingCache _metaSources,
scOpenTelemetryConfig = openTelemetryInfo
}
returnA -< (schemaCache, storedIntrospectionStatus)
where
-- See Note [Avoiding GraphQL schema rebuilds when changing irrelevant Metadata]
buildOutputsAndSchema = proc (metadataDep, dynamicConfig, invalidationKeysDep, storedIntrospection) -> do
(outputs, collectedInfo) <- runWriterA buildAndCollectInfo -< (dynamicConfig, metadataDep, invalidationKeysDep, storedIntrospection)
let (inconsistentObjects, unresolvedDependencies) = partitionEithers $ toList collectedInfo
let (inconsistentObjects, unresolvedDependencies, storedIntrospections) = partitionCollectedInfo collectedInfo
out2@(resolvedOutputs, _dependencyInconsistentObjects, _resolvedDependencies) <- resolveDependencies -< (outputs, unresolvedDependencies)
out3 <-
bindA
@ -488,7 +528,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
(_boCustomTypes resolvedOutputs)
mSchemaRegistryContext
logger
returnA -< (inconsistentObjects, out2, out3)
returnA -< (inconsistentObjects, storedIntrospections, out2, out3)
resolveBackendInfo' ::
forall arr m b.
@ -496,7 +536,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
ArrowChoice arr,
Inc.ArrowCache m arr,
Inc.ArrowDistribute arr,
ArrowWriter (Seq (Either InconsistentMetadata MetadataDependency)) arr,
ArrowWriter (Seq CollectItem) arr,
MonadIO m,
MonadBaseControl IO m,
ProvidesNetwork m
@ -514,7 +554,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
( ArrowChoice arr,
Inc.ArrowCache m arr,
Inc.ArrowDistribute arr,
ArrowWriter (Seq (Either InconsistentMetadata MetadataDependency)) arr,
ArrowWriter (Seq CollectItem) arr,
MonadIO m,
MonadBaseControl IO m,
ProvidesNetwork m,
@ -534,7 +574,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
forall b arr m.
( ArrowChoice arr,
Inc.ArrowCache m arr,
ArrowWriter (Seq (Either InconsistentMetadata MetadataDependency)) arr,
ArrowWriter (Seq CollectItem) arr,
MonadIO m,
MonadBaseControl IO m,
MonadResolveSource m,
@ -567,7 +607,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
forall b arr m.
( ArrowChoice arr,
Inc.ArrowCache m arr,
ArrowWriter (Seq (Either InconsistentMetadata MetadataDependency)) arr,
ArrowWriter (Seq CollectItem) arr,
MonadIO m,
MonadBaseControl IO m,
MonadResolveSource m,
@ -589,7 +629,10 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
Just sourceConfig -> do
databaseResponse <- bindA -< resolveDatabaseMetadata logger _bcasmSourceMetadata sourceConfig
case databaseResponse of
Right databaseMetadata -> returnA -< Just (sourceConfig, databaseMetadata)
Right databaseMetadata -> do
-- Collect database introspection to persist in the storage
tellA -< pure (CollectStoredIntrospection $ SourceIntrospectionItem sourceName $ encJFromJValue databaseMetadata)
returnA -< Just (sourceConfig, databaseMetadata)
Left databaseError ->
-- If database exception occurs, try to lookup from stored introspection
case sourceIntrospection >>= decode' of
@ -626,7 +669,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
forall b arr m.
( ArrowChoice arr,
Inc.ArrowCache m arr,
ArrowWriter (Seq (Either InconsistentMetadata MetadataDependency)) arr,
ArrowWriter (Seq CollectItem) arr,
MonadIO m,
BackendMetadata b,
MonadBaseControl IO m,
@ -684,7 +727,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
forall b arr m.
( ArrowChoice arr,
ArrowKleisli m arr,
ArrowWriter (Seq (Either InconsistentMetadata MetadataDependency)) arr,
ArrowWriter (Seq CollectItem) arr,
MonadError QErr m,
HasCacheStaticConfig m,
BackendMetadata b,
@ -962,7 +1005,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
( ArrowChoice arr,
Inc.ArrowDistribute arr,
Inc.ArrowCache m arr,
ArrowWriter (Seq (Either InconsistentMetadata MetadataDependency)) arr,
ArrowWriter (Seq CollectItem) arr,
MonadIO m,
MonadError QErr m,
MonadReader BuildReason m,
@ -1165,7 +1208,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
}
buildOpenTelemetry ::
(MonadWriter (Seq (Either InconsistentMetadata md)) m) =>
(MonadWriter (Seq CollectItem) m) =>
OpenTelemetryConfig ->
m OpenTelemetryInfo
buildOpenTelemetry OpenTelemetryConfig {..} = do
@ -1194,7 +1237,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
)
buildRESTEndpoints ::
(MonadWriter (Seq (Either InconsistentMetadata md)) m) =>
(MonadWriter (Seq CollectItem) m) =>
QueryCollections ->
[CreateEndpoint] ->
m (HashMap EndpointName (EndpointMetadata GQLQueryWithText))
@ -1284,7 +1327,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
forall arr m b.
( ArrowChoice arr,
Inc.ArrowDistribute arr,
ArrowWriter (Seq (Either InconsistentMetadata MetadataDependency)) arr,
ArrowWriter (Seq CollectItem) arr,
Inc.ArrowCache m arr,
MonadIO m,
MonadBaseControl IO m,
@ -1422,7 +1465,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
primaryKey
buildCronTriggers ::
(MonadWriter (Seq (Either InconsistentMetadata md)) m) =>
(MonadWriter (Seq CollectItem) m) =>
[CronTriggerMetadata] ->
m (HashMap TriggerName CronTriggerInfo)
buildCronTriggers = buildInfoMapM ctName mkCronTriggerMetadataObject buildCronTrigger
@ -1435,7 +1478,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
$ resolveCronTrigger env cronTrigger
buildInheritedRoles ::
(MonadWriter (Seq (Either InconsistentMetadata MetadataDependency)) m) =>
(MonadWriter (Seq CollectItem) m) =>
HashSet RoleName ->
[InheritedRole] ->
m (HashMap RoleName Role)
@ -1451,7 +1494,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
pure resolvedInheritedRole
buildActions ::
(MonadWriter (Seq (Either InconsistentMetadata MetadataDependency)) m) =>
(MonadWriter (Seq CollectItem) m) =>
AnnotatedCustomTypes ->
BackendMap ScalarMap ->
OrderedRoles ->
@ -1471,7 +1514,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
return $ ActionInfo name (outputType, outObject) resolvedDef permissionsMap forwardClientHeaders comment
buildRemoteSchemaRemoteRelationship ::
(MonadWriter (Seq (Either InconsistentMetadata MetadataDependency)) m) =>
(MonadWriter (Seq CollectItem) m) =>
HashMap SourceName (AB.AnyBackend PartiallyResolvedSource) ->
PartiallyResolvedRemoteSchemaMap ->
RemoteSchemaName ->

View File

@ -13,7 +13,6 @@ module Hasura.RQL.DDL.Schema.Cache.Common
CacheBuild,
CacheBuildParams (CacheBuildParams),
InvalidationKeys (..),
StoredIntrospection (..),
ikMetadata,
ikRemoteSchemas,
ikSources,
@ -40,6 +39,7 @@ module Hasura.RQL.DDL.Schema.Cache.Common
runCacheBuild,
runCacheBuildM,
withRecordDependencies,
StoredIntrospectionStatus (..),
)
where
@ -47,13 +47,11 @@ import Control.Arrow.Extended
import Control.Arrow.Interpret
import Control.Lens hiding ((.=))
import Control.Monad.Trans.Control (MonadBaseControl)
import Data.Aeson.Extended
import Data.HashMap.Strict.Extended qualified as HashMap
import Data.HashMap.Strict.InsOrd qualified as InsOrdHashMap
import Data.Sequence qualified as Seq
import Data.Text.Extended
import Hasura.Base.Error
import Hasura.EncJSON
import Hasura.Incremental qualified as Inc
import Hasura.LogicalModel.Types (LogicalModelName)
import Hasura.Prelude
@ -132,29 +130,6 @@ invalidateKeys CacheInvalidations {..} InvalidationKeys {..} =
invalidateDataConnectors (BackendInvalidationKeysWrapper invalidationKeys) =
BackendInvalidationKeysWrapper $ foldl' (flip invalidate) invalidationKeys ciDataConnectors
data StoredIntrospection = StoredIntrospection
{ -- Just catalog introspection - not including enums
siBackendIntrospection :: HashMap SourceName EncJSON,
siRemotes :: HashMap RemoteSchemaName EncJSON
}
deriving stock (Generic)
-- Note that we don't want to introduce an `Eq EncJSON` instance, as this is a
-- bit of a footgun. But for Stored Introspection purposes, it's fine: the
-- worst-case effect of a semantically inaccurate `Eq` instance is that we
-- rebuild the Schema Cache too often.
--
-- However, this does mean that we have to spell out this instance a bit.
instance Eq StoredIntrospection where
StoredIntrospection bs1 rs1 == StoredIntrospection bs2 rs2 =
(encJToLBS <$> bs1) == (encJToLBS <$> bs2) && (encJToLBS <$> rs1) == (encJToLBS <$> rs2)
instance FromJSON StoredIntrospection where
parseJSON = genericParseJSON hasuraJSON
instance ToJSON StoredIntrospection where
toJSON = genericToJSON hasuraJSON
data TableBuildInput b = TableBuildInput
{ _tbiName :: TableName b,
_tbiIsEnum :: Bool,
@ -286,14 +261,23 @@ runCacheBuildM m = do
<*> askCacheStaticConfig
runCacheBuild params m
-- | The status of collection of stored introspections of remote schemas and data sources.
data StoredIntrospectionStatus
= -- | A full introspection collection of all available remote schemas and data sources.
StoredIntrospectionChangedFull StoredIntrospection
| -- | A partial introspection collection. Does not include all configured remote schemas and data sources, because they were not available.
StoredIntrospectionChangedPartial StoredIntrospection
| -- | None of remote schemas or data sources introspection is refetched.
StoredIntrospectionUnchanged
data RebuildableSchemaCache = RebuildableSchemaCache
{ lastBuiltSchemaCache :: SchemaCache,
_rscInvalidationMap :: InvalidationKeys,
_rscRebuild :: Inc.Rule (ReaderT BuildReason CacheBuild) (MetadataWithResourceVersion, CacheDynamicConfig, InvalidationKeys, Maybe StoredIntrospection) SchemaCache
_rscRebuild :: Inc.Rule (ReaderT BuildReason CacheBuild) (MetadataWithResourceVersion, CacheDynamicConfig, InvalidationKeys, Maybe StoredIntrospection) (SchemaCache, StoredIntrospectionStatus)
}
withRecordDependencies ::
(ArrowWriter (Seq (Either im MetadataDependency)) arr) =>
(ArrowWriter (Seq CollectItem) arr) =>
WriterA (Seq SchemaDependency) arr (e, s) a ->
arr (e, (MetadataObject, (SchemaObjId, s))) a
withRecordDependencies f = proc (e, (metadataObject, (schemaObjectId, s))) -> do
@ -303,7 +287,7 @@ withRecordDependencies f = proc (e, (metadataObject, (schemaObjectId, s))) -> do
{-# INLINEABLE withRecordDependencies #-}
noDuplicates ::
(MonadWriter (Seq (Either InconsistentMetadata md)) m) =>
(MonadWriter (Seq CollectItem) m) =>
(a -> MetadataObject) ->
[a] ->
m (Maybe a)
@ -313,7 +297,7 @@ noDuplicates mkMetadataObject = \case
values@(value : _) -> do
let objectId = _moId $ mkMetadataObject value
definitions = map (_moDefinition . mkMetadataObject) values
tell $ Seq.singleton $ Left (DuplicateObjects objectId definitions)
tell $ Seq.singleton $ CollectInconsistentMetadata (DuplicateObjects objectId definitions)
return Nothing
-- | Processes a list of catalog metadata into a map of processed information, marking any duplicate
@ -321,7 +305,7 @@ noDuplicates mkMetadataObject = \case
buildInfoMap ::
( ArrowChoice arr,
Inc.ArrowDistribute arr,
ArrowWriter (Seq (Either InconsistentMetadata md)) arr,
ArrowWriter (Seq CollectItem) arr,
Hashable k
) =>
(a -> k) ->
@ -345,7 +329,7 @@ buildInfoMap extractKey mkMetadataObject buildInfo = proc (e, infos) -> do
{-# INLINEABLE buildInfoMap #-}
buildInfoMapM ::
( MonadWriter (Seq (Either InconsistentMetadata md)) m,
( MonadWriter (Seq CollectItem) m,
Hashable k
) =>
(a -> k) ->
@ -369,7 +353,7 @@ buildInfoMapM extractKey mkMetadataObject buildInfo infos = do
buildInfoMapPreservingMetadata ::
( ArrowChoice arr,
Inc.ArrowDistribute arr,
ArrowWriter (Seq (Either InconsistentMetadata md)) arr,
ArrowWriter (Seq CollectItem) arr,
Hashable k
) =>
(a -> k) ->
@ -385,7 +369,7 @@ buildInfoMapPreservingMetadata extractKey mkMetadataObject buildInfo =
{-# INLINEABLE buildInfoMapPreservingMetadata #-}
buildInfoMapPreservingMetadataM ::
( MonadWriter (Seq (Either InconsistentMetadata md)) m,
( MonadWriter (Seq CollectItem) m,
Hashable k
) =>
(a -> k) ->

View File

@ -32,7 +32,7 @@ import Language.GraphQL.Draft.Syntax qualified as G
addNonColumnFields ::
forall b m.
( MonadWriter (Seq (Either InconsistentMetadata MetadataDependency)) m,
( MonadWriter (Seq CollectItem) m,
BackendMetadata b
) =>
HashMap SourceName (AB.AnyBackend PartiallyResolvedSource) ->
@ -129,7 +129,7 @@ addNonColumnFields allSources sourceName sourceConfig rawTableInfos columns remo
These (_, thisMetadata) (_, thatMetadata) -> do
tell
$ Seq.singleton
$ Left
$ CollectInconsistentMetadata
$ ConflictingObjects
("conflicting definitions for field " <>> fieldName)
[thisMetadata, thatMetadata]
@ -175,7 +175,7 @@ mkRelationshipMetadataObject relType source table relDef =
in MetadataObject objectId $ toJSON $ WithTable @b source table relDef
buildObjectRelationship ::
( MonadWriter (Seq (Either InconsistentMetadata MetadataDependency)) m,
( MonadWriter (Seq CollectItem) m,
BackendMetadata b
) =>
HashMap (TableName b) (HashSet (ForeignKey b)) ->
@ -189,7 +189,7 @@ buildObjectRelationship fkeysMap sourceName sourceConfig table relDef = do
buildRelationship sourceName table buildRelInfo ObjRel relDef
buildArrayRelationship ::
( MonadWriter (Seq (Either InconsistentMetadata MetadataDependency)) m,
( MonadWriter (Seq CollectItem) m,
BackendMetadata b
) =>
HashMap (TableName b) (HashSet (ForeignKey b)) ->
@ -204,7 +204,7 @@ buildArrayRelationship fkeysMap sourceName sourceConfig table relDef = do
buildRelationship ::
forall m b a.
( MonadWriter (Seq (Either InconsistentMetadata MetadataDependency)) m,
( MonadWriter (Seq CollectItem) m,
ToJSON a,
Backend b
) =>
@ -247,7 +247,7 @@ mkComputedFieldMetadataObject source table ComputedFieldMetadata {..} =
buildComputedField ::
forall b m.
( MonadWriter (Seq (Either InconsistentMetadata MetadataDependency)) m,
( MonadWriter (Seq CollectItem) m,
BackendMetadata b
) =>
HashSet (TableName b) ->
@ -268,7 +268,6 @@ buildComputedField trackedTableNames tableColumns source pgFunctions table cf@Co
onNothing
(HashMap.lookup function pgFunctions)
(throw400 NotExists $ "no such function exists: " <>> function)
rawfi <- getSingleUniqueFunctionOverload @b (computedFieldFunction @b _cfmDefinition) funcDefs
buildComputedFieldInfo trackedTableNames table tableColumns _cfmName _cfmDefinition rawfi _cfmComment
@ -294,7 +293,7 @@ mkRemoteRelationshipMetadataObject source table RemoteRelationship {..} =
-- dependencies on the remote relationship on the LHS entity are computed here
buildRemoteRelationship ::
forall b m.
( MonadWriter (Seq (Either InconsistentMetadata MetadataDependency)) m,
( MonadWriter (Seq CollectItem) m,
BackendMetadata b
) =>
HashMap SourceName (AB.AnyBackend PartiallyResolvedSource) ->

View File

@ -147,7 +147,7 @@ orderRoles allRoles = do
-- | `resolveCheckPermission` is a helper function which will convert the indermediate
-- type `CheckPermission` to its original type. It will record any metadata inconsistencies, if exists.
resolveCheckPermission ::
(MonadWriter (Seq (Either InconsistentMetadata md)) m) =>
(MonadWriter (Seq CollectItem) m) =>
CheckPermission p ->
RoleName ->
InconsistentRoleEntity ->
@ -157,7 +157,7 @@ resolveCheckPermission checkPermission roleName inconsistentEntity = do
CPInconsistent -> do
let inconsistentObj =
-- check `Conflicts while inheriting permissions` in `rfcs/inherited-roles-improvements.md`
Left
CollectInconsistentMetadata
$ ConflictingInheritedPermission roleName inconsistentEntity
tell $ Seq.singleton inconsistentObj
pure Nothing
@ -165,7 +165,7 @@ resolveCheckPermission checkPermission roleName inconsistentEntity = do
CPUndefined -> pure Nothing
resolveCheckTablePermission ::
( MonadWriter (Seq (Either InconsistentMetadata md)) m,
( MonadWriter (Seq CollectItem) m,
BackendMetadata b
) =>
CheckPermission perm ->
@ -186,7 +186,7 @@ resolveCheckTablePermission inheritedRolePermission accumulatedRolePermInfo perm
buildTablePermissions ::
forall b m.
( MonadError QErr m,
MonadWriter (Seq (Either InconsistentMetadata MetadataDependency)) m,
MonadWriter (Seq CollectItem) m,
BackendMetadata b,
GetAggregationPredicatesDeps b
) =>
@ -289,7 +289,7 @@ buildTablePermissions source tableCache tableFields tablePermissions orderedRole
buildLogicalModelPermissions ::
forall b m.
( MonadError QErr m,
MonadWriter (Seq (Either InconsistentMetadata MetadataDependency)) m,
MonadWriter (Seq CollectItem) m,
BackendMetadata b,
GetAggregationPredicatesDeps b
) =>

View File

@ -135,6 +135,7 @@ class
ToJSON (FunctionArgument b),
ToJSON (FunctionName b),
ToJSON (FunctionReturnType b),
ToJSON (RawFunctionInfo b),
ToJSON (ScalarType b),
ToJSON (TableName b),
ToJSON (ExtraTableMetadata b),

View File

@ -24,7 +24,6 @@ import Hasura.RQL.Types.Common
import Hasura.RQL.Types.ComputedField
import Hasura.RQL.Types.EventTrigger
import Hasura.RQL.Types.Metadata
import Hasura.RQL.Types.Metadata.Object
import Hasura.RQL.Types.NamingCase (NamingCase)
import Hasura.RQL.Types.Relationships.Local
import Hasura.RQL.Types.SchemaCache
@ -78,7 +77,7 @@ class
( ArrowChoice arr,
Inc.ArrowCache m arr,
Inc.ArrowDistribute arr,
ArrowWriter (Seq (Either InconsistentMetadata MetadataDependency)) arr,
ArrowWriter (Seq CollectItem) arr,
MonadIO m,
MonadBaseControl IO m,
ProvidesNetwork m

View File

@ -31,6 +31,9 @@ module Hasura.RQL.Types.SchemaCache.Build
throwOnInconsistencies,
withNewInconsistentObjsCheck,
getInconsistentQueryCollections,
StoredIntrospection (..),
StoredIntrospectionItem (..),
CollectItem (..),
)
where
@ -51,6 +54,7 @@ import Database.PG.Query qualified as PG
import Hasura.Backends.DataConnector.Adapter.Types (DataConnectorName)
import Hasura.Backends.Postgres.Connection
import Hasura.Base.Error
import Hasura.EncJSON
import Hasura.GraphQL.Analyse
import Hasura.GraphQL.Transport.HTTP.Protocol
import Hasura.Prelude
@ -75,22 +79,22 @@ import Language.GraphQL.Draft.Syntax qualified as G
-- * Inconsistencies
recordInconsistencies ::
(ArrowWriter (Seq (Either InconsistentMetadata md)) arr, Functor f, Foldable f) => ((Maybe Value, f MetadataObject), Text) `arr` ()
(ArrowWriter (Seq CollectItem) arr, Functor f, Foldable f) => ((Maybe Value, f MetadataObject), Text) `arr` ()
recordInconsistencies = proc ((val, mo), reason) ->
tellA -< Seq.fromList $ toList $ fmap (Left . InconsistentObject reason val) mo
tellA -< Seq.fromList $ toList $ fmap (CollectInconsistentMetadata . InconsistentObject reason val) mo
recordInconsistencyM ::
(MonadWriter (Seq (Either InconsistentMetadata md)) m) => Maybe Value -> MetadataObject -> Text -> m ()
(MonadWriter (Seq CollectItem) m) => Maybe Value -> MetadataObject -> Text -> m ()
recordInconsistencyM val mo reason = recordInconsistenciesM' [(val, mo)] reason
recordInconsistenciesM ::
(MonadWriter (Seq (Either InconsistentMetadata md)) m) => [MetadataObject] -> Text -> m ()
(MonadWriter (Seq CollectItem) m) => [MetadataObject] -> Text -> m ()
recordInconsistenciesM metadataObjects reason = recordInconsistenciesM' ((Nothing,) <$> metadataObjects) reason
recordInconsistenciesM' ::
(MonadWriter (Seq (Either InconsistentMetadata md)) m) => [(Maybe Value, MetadataObject)] -> Text -> m ()
(MonadWriter (Seq CollectItem) m) => [(Maybe Value, MetadataObject)] -> Text -> m ()
recordInconsistenciesM' metadataObjects reason =
tell $ Seq.fromList $ map (Left . uncurry (InconsistentObject reason)) metadataObjects
tell $ Seq.fromList $ map (CollectInconsistentMetadata . uncurry (InconsistentObject reason)) metadataObjects
-- * Dependencies
@ -100,28 +104,28 @@ data MetadataDependency
MetadataObject
SchemaObjId
SchemaDependency
deriving (Eq)
deriving (Eq, Show)
recordDependencies ::
(ArrowWriter (Seq (Either im MetadataDependency)) arr) =>
(ArrowWriter (Seq CollectItem) arr) =>
(MetadataObject, SchemaObjId, Seq SchemaDependency) `arr` ()
recordDependencies = proc (metadataObject, schemaObjectId, dependencies) ->
tellA -< Right . MetadataDependency metadataObject schemaObjectId <$> dependencies
tellA -< CollectMetadataDependency . MetadataDependency metadataObject schemaObjectId <$> dependencies
recordDependenciesM ::
(MonadWriter (Seq (Either im MetadataDependency)) m) =>
(MonadWriter (Seq CollectItem) m) =>
MetadataObject ->
SchemaObjId ->
Seq SchemaDependency ->
m ()
recordDependenciesM metadataObject schemaObjectId dependencies = do
tell $ Right . MetadataDependency metadataObject schemaObjectId <$> dependencies
tell $ CollectMetadataDependency . MetadataDependency metadataObject schemaObjectId <$> dependencies
-- * Helpers
-- | Monadic version of 'withRecordInconsistency'
withRecordInconsistencyM ::
(MonadWriter (Seq (Either InconsistentMetadata md)) m) =>
(MonadWriter (Seq CollectItem) m) =>
MetadataObject ->
ExceptT QErr m a ->
m (Maybe a)
@ -146,8 +150,8 @@ withRecordInconsistencyM metadataObject f = do
Right v -> return $ Just v
recordInconsistenciesWith ::
(ArrowChoice arr, ArrowWriter (Seq (Either InconsistentMetadata md)) arr) =>
((ArrowWriter (Seq (Either InconsistentMetadata md)) arr) => ((Maybe Value, mo), Text) `arr` ()) ->
(ArrowChoice arr, ArrowWriter (Seq CollectItem) arr) =>
((ArrowWriter (Seq CollectItem) arr) => ((Maybe Value, mo), Text) `arr` ()) ->
ErrorA QErr arr (e, s) a ->
arr (e, (mo, s)) (Maybe a)
recordInconsistenciesWith recordInconsistency' f = proc (e, (metadataObject, s)) -> do
@ -173,7 +177,7 @@ recordInconsistenciesWith recordInconsistency' f = proc (e, (metadataObject, s))
-- | Record any errors resulting from a computation as inconsistencies
withRecordInconsistency ::
(ArrowChoice arr, ArrowWriter (Seq (Either InconsistentMetadata md)) arr) =>
(ArrowChoice arr, ArrowWriter (Seq CollectItem) arr) =>
ErrorA QErr arr (e, s) a ->
arr (e, (MetadataObject, s)) (Maybe a)
withRecordInconsistency err = proc (e, (mo, s)) ->
@ -181,7 +185,7 @@ withRecordInconsistency err = proc (e, (mo, s)) ->
{-# INLINEABLE withRecordInconsistency #-}
withRecordInconsistencies ::
(ArrowChoice arr, ArrowWriter (Seq (Either InconsistentMetadata md)) arr) =>
(ArrowChoice arr, ArrowWriter (Seq CollectItem) arr) =>
ErrorA QErr arr (e, s) a ->
arr (e, ([MetadataObject], s)) (Maybe a)
withRecordInconsistencies = recordInconsistenciesWith recordInconsistencies
@ -487,3 +491,52 @@ getInconsistentQueryCollections rs qcs lqToMetadataObj restEndpoints allowLst =
-- perform the validation
for_ (diagnoseGraphQLQuery rs singleOperation) \errors ->
throwError (lqToMetadataObj eMeta, formatError eMeta errors)
data StoredIntrospection = StoredIntrospection
{ -- Just catalog introspection - not including enums
siBackendIntrospection :: HashMap SourceName EncJSON,
siRemotes :: HashMap RemoteSchemaName EncJSON
}
deriving stock (Generic)
-- Note that we don't want to introduce an `Eq EncJSON` instance, as this is a
-- bit of a footgun. But for Stored Introspection purposes, it's fine: the
-- worst-case effect of a semantically inaccurate `Eq` instance is that we
-- rebuild the Schema Cache too often.
--
-- However, this does mean that we have to spell out this instance a bit.
instance Eq StoredIntrospection where
StoredIntrospection bs1 rs1 == StoredIntrospection bs2 rs2 =
(encJToLBS <$> bs1) == (encJToLBS <$> bs2) && (encJToLBS <$> rs1) == (encJToLBS <$> rs2)
instance FromJSON StoredIntrospection where
parseJSON = genericParseJSON hasuraJSON
instance ToJSON StoredIntrospection where
toJSON = genericToJSON hasuraJSON
-- | Represents remote schema or source introspection data to be persisted in a storage (database).
data StoredIntrospectionItem
= SourceIntrospectionItem SourceName EncJSON
| RemoteSchemaIntrospectionItem RemoteSchemaName EncJSON
-- The same comment as above for `Eq StoredIntrospection` applies here as well: our refusal to have an `Eq EncJSON` instance means that we can't `stock`-derive this instance.
instance Eq StoredIntrospectionItem where
SourceIntrospectionItem lSource lIntrospection == SourceIntrospectionItem rSource rIntrospection =
(lSource == rSource) && (encJToLBS lIntrospection) == (encJToLBS rIntrospection)
RemoteSchemaIntrospectionItem lRemoteSchema lIntrospection == RemoteSchemaIntrospectionItem rRemoteSchema rIntrospection =
(lRemoteSchema == rRemoteSchema) && (encJToLBS lIntrospection) == (encJToLBS rIntrospection)
_ == _ = False
instance Show StoredIntrospectionItem where
show = \case
SourceIntrospectionItem sourceName _ -> "introspection data of source " ++ show sourceName
RemoteSchemaIntrospectionItem remoteSchemaName _ -> "introspection data of source " ++ show remoteSchemaName
-- | Items to be collected while building schema cache
-- See @'buildSchemaCacheRule' for more details.
data CollectItem
= CollectInconsistentMetadata InconsistentMetadata
| CollectMetadataDependency MetadataDependency
| CollectStoredIntrospection StoredIntrospectionItem
deriving (Show, Eq)

View File

@ -156,6 +156,7 @@ data DBObjectsIntrospection b = DBObjectsIntrospection
instance (Backend b) => FromJSON (DBObjectsIntrospection b) where
parseJSON = withObject "DBObjectsIntrospection" \o -> do
-- "tables": [["<table-1>", "<table-metadata-1>"], ["<table-2>", "<table-metadata-2>"]]
tables <- o .: "tables"
functions <- o .: "functions"
scalars <- o .: "scalars"
@ -168,6 +169,16 @@ instance (Backend b) => FromJSON (DBObjectsIntrospection b) where
_rsLogicalModels = InsOrdHashMap.fromList logicalModels
}
instance (Backend b) => ToJSON (DBObjectsIntrospection b) where
toJSON (DBObjectsIntrospection tables functions (ScalarMap scalars) logicalModels) =
-- "tables": [["<table-1>", "<table-metadata-1>"], ["<table-2>", "<table-metadata-2>"]]
object
[ "tables" .= HashMap.toList tables,
"functions" .= HashMap.toList functions,
"scalars" .= HashMap.toList scalars,
"logical_models" .= InsOrdHashMap.toList logicalModels
]
instance (L.ToEngineLog (DBObjectsIntrospection b) L.Hasura) where
toEngineLog _ = (L.LevelDebug, L.ELTStartup, toJSON rsLog)
where

View File

@ -16,6 +16,7 @@ import Data.HashMap.Strict.Extended qualified as HashMap
import Data.Text qualified as T
import Data.Text.Extended
import Hasura.Base.Error
import Hasura.EncJSON (encJFromLBS)
import Hasura.GraphQL.RemoteServer
import Hasura.Incremental qualified as Inc
import Hasura.Prelude
@ -38,7 +39,7 @@ import Hasura.Tracing qualified as Tracing
buildRemoteSchemas ::
( ArrowChoice arr,
Inc.ArrowDistribute arr,
ArrowWriter (Seq (Either InconsistentMetadata MetadataDependency)) arr,
ArrowWriter (Seq CollectItem) arr,
Inc.ArrowCache m arr,
MonadIO m,
MonadBaseControl IO m,
@ -64,7 +65,10 @@ buildRemoteSchemas env =
upstreamResponse <- bindA -< runExceptT (noopTrace $ addRemoteSchemaP2Setup env defn)
remoteSchemaContextParts <-
case upstreamResponse of
Right upstream -> returnA -< Just upstream
Right upstream@(_, byteString, _) -> do
-- Collect upstream introspection response to persist in the storage
tellA -< pure (CollectStoredIntrospection $ RemoteSchemaIntrospectionItem name $ encJFromLBS byteString)
returnA -< Just upstream
Left upstreamError -> do
-- If upstream is not available, try to lookup from stored introspection
case (HashMap.lookup name =<< storedIntrospection) of
@ -123,7 +127,7 @@ buildRemoteSchemas env =
buildRemoteSchemaPermissions ::
( ArrowChoice arr,
Inc.ArrowDistribute arr,
ArrowWriter (Seq (Either InconsistentMetadata MetadataDependency)) arr,
ArrowWriter (Seq CollectItem) arr,
ArrowKleisli m arr,
MonadError QErr m
) =>

View File

@ -691,7 +691,7 @@ buildTableCache ::
forall arr m b.
( ArrowChoice arr,
Inc.ArrowDistribute arr,
ArrowWriter (Seq (Either InconsistentMetadata MetadataDependency)) arr,
ArrowWriter (Seq CollectItem) arr,
Inc.ArrowCache m arr,
MonadIO m,
MonadBaseControl IO m,

View File

@ -1115,6 +1115,16 @@ instance (Backend b) => FromJSON (ForeignKeyMetadata b) where
$ NE.zip columns foreignColumns
}
instance (Backend b) => ToJSON (ForeignKeyMetadata b) where
toJSON (ForeignKeyMetadata (ForeignKey constraint foreignTable columnMapping)) =
let (columns, foreignColumns) = NE.unzip $ NEHashMap.toList columnMapping
in object
[ "constraint" .= constraint,
"foreign_table" .= foreignTable,
"columns" .= columns,
"foreign_columns" .= foreignColumns
]
-- | Metadata of any Backend table which is being extracted from source database
data DBTableMetadata (b :: BackendType) = DBTableMetadata
{ _ptmiOid :: OID,
@ -1138,6 +1148,9 @@ instance (Backend b) => NFData (DBTableMetadata b)
instance (Backend b) => FromJSON (DBTableMetadata b) where
parseJSON = genericParseJSON hasuraJSON
instance (Backend b) => ToJSON (DBTableMetadata b) where
toJSON = genericToJSON hasuraJSON
type DBTablesMetadata b = HashMap (TableName b) (DBTableMetadata b)
getFieldInfoM ::

View File

@ -15,7 +15,6 @@ import Hasura.Generator.Common
import Hasura.Prelude
import Hasura.QuickCheck.Instances ()
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.Metadata.Object
import Hasura.RQL.Types.SchemaCache.Build
import Hedgehog.Gen qualified as Gen
import Hedgehog.Generic
@ -97,7 +96,7 @@ withRecordInconsistencyEqualSpec =
prop "Should equal withRecordInconsistencyM"
$ \inputMetadata (errOrUnit :: Either QErr ()) ->
let arrowInputArr = ErrorA (arr (const errOrUnit))
arrow = withRecordInconsistency @_ @InconsistentMetadata arrowInputArr
arrow = withRecordInconsistency arrowInputArr
arrowOutput =
runWriter $ runKleisli arrow ((), (inputMetadata, ()))
monadInput = liftEither errOrUnit