mirror of
https://github.com/hasura/graphql-engine.git
synced 2025-01-07 08:13:18 +03:00
318bffa28d
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/9310 Co-authored-by: Sameer Kolhar <6604943+kolharsam@users.noreply.github.com> Co-authored-by: paritosh-08 <85472423+paritosh-08@users.noreply.github.com> GitOrigin-RevId: 82697ea7d0f4a5cc39f05938f92a7ba49d9b6098
165 lines
5.3 KiB
Haskell
165 lines
5.3 KiB
Haskell
{-# LANGUAGE DeriveAnyClass #-}
|
|
|
|
module Hasura.RQL.DDL.SchemaRegistry
|
|
( SchemaProjectId (..),
|
|
IsMetadataInconsistent (..),
|
|
SchemaSDL (..),
|
|
SchemaHash (..),
|
|
ProjectGQLSchemaInformation (..),
|
|
SchemaRegistryConfig (..),
|
|
SchemaRegistryDetails (..),
|
|
GQLSchemaInformation (..),
|
|
SchemaRegistryContext (..),
|
|
SchemaRegistryControlRole (..),
|
|
SchemaRegistryMap,
|
|
SchemaRegistryDetailsList,
|
|
SchemaRegistryAction,
|
|
SchemaRegistryConfigRaw (..),
|
|
calculateSchemaSDLHash,
|
|
selectNowQuery,
|
|
)
|
|
where
|
|
|
|
import Control.Concurrent.STM qualified as STM
|
|
import Data.Aeson qualified as J
|
|
import Data.Text qualified as T
|
|
import Data.Time (UTCTime)
|
|
import Database.PG.Query qualified as PG
|
|
import Hasura.Backends.Postgres.Execute.Types qualified as SQLTypes
|
|
import Hasura.Base.Error
|
|
import Hasura.Prelude
|
|
import Hasura.RQL.Types.Roles
|
|
import Hasura.RQL.Types.SchemaCache (MetadataResourceVersion)
|
|
import Hasura.Server.Utils
|
|
|
|
{-
|
|
SchemaRegistry
|
|
|
|
About:
|
|
The schema registry is a feature that is currently meant for
|
|
our users of Hasura Cloud. This feature will help users track
|
|
the evolution of their GraphQL schema across all Hasura roles.
|
|
Additional functionality around tagging schemas and viewing
|
|
the diff of the GraphQL schema across different versions of the
|
|
schema.
|
|
|
|
All of the types and other functions that are required for the
|
|
functionality provided by the Hasura server pertaining to this
|
|
feature are present in this file.
|
|
|
|
Intended Current Functionality:
|
|
1) Every time the `buildGQLContext` function is run to rebuild
|
|
the GraphQL schema(s), the changes are captured and sent to
|
|
the Hasura PRO server via a TQueue
|
|
|
|
2) On the Hasura PRO server, a thread is always maintained to
|
|
read from the aforementioned TQueue for new changes.
|
|
|
|
3) The changes that are captured are then processed (more notes
|
|
on this present on `HasuraPro.App` module) and a request with
|
|
all relevant data is sent towards the schema_registry service.
|
|
|
|
NOTE: The timestamp recorded as soon as the schema is rebuilt is
|
|
obtained from the Metadata DB. This is done in order to
|
|
make sure that we have only one source for the time to avoid
|
|
clock-skew.
|
|
|
|
-}
|
|
|
|
newtype SchemaProjectId = SchemaProjectId {_spiProjectId :: T.Text}
|
|
deriving stock (Eq, Show, Generic)
|
|
deriving anyclass (J.ToJSON, J.FromJSON)
|
|
|
|
newtype IsMetadataInconsistent = IsMetadataInconsistent {_isMdInconsistent :: Bool}
|
|
deriving stock (Eq, Show, Generic)
|
|
deriving anyclass (J.ToJSON, J.FromJSON)
|
|
|
|
newtype SchemaSDL = SchemaSDL {_sdl :: T.Text}
|
|
deriving stock (Eq, Show, Generic)
|
|
deriving anyclass (J.ToJSON, J.FromJSON)
|
|
|
|
newtype SchemaHash = SchemaHash {_schemaHash :: T.Text}
|
|
deriving stock (Eq, Show, Generic)
|
|
deriving anyclass (J.ToJSON, J.FromJSON)
|
|
|
|
type SchemaRegistryMap = HashMap RoleName GQLSchemaInformation
|
|
|
|
type SchemaRegistryAction = Maybe (MetadataResourceVersion -> IO ())
|
|
|
|
data GQLSchemaInformation = GQLSchemaInformation
|
|
{ _gsiSchemaSDL :: SchemaSDL,
|
|
_gsiSchemaHash :: SchemaHash
|
|
}
|
|
deriving stock (Eq, Show, Generic)
|
|
deriving anyclass (J.FromJSON)
|
|
|
|
instance J.ToJSON GQLSchemaInformation where
|
|
toJSON (GQLSchemaInformation schemaSdl schemaHash) =
|
|
J.object
|
|
$ [ "schema_sdl" J..= (_sdl schemaSdl),
|
|
"schema_hash" J..= (_schemaHash schemaHash)
|
|
]
|
|
|
|
data ProjectGQLSchemaInformation = ProjectGQLSchemaInformation
|
|
{ _pgsiSchemaRegistryMap :: SchemaRegistryMap,
|
|
_pgsiIsMetadataInconsistent :: IsMetadataInconsistent,
|
|
_pgsiAdminSchemaHash :: SchemaHash,
|
|
_pgsiMetadataResourceVersion :: MetadataResourceVersion,
|
|
_pgsiChangeRecordedAt :: UTCTime
|
|
}
|
|
deriving stock (Eq, Show, Generic)
|
|
deriving anyclass (J.FromJSON, J.ToJSON)
|
|
|
|
data SchemaRegistryConfig = SchemaRegistryConfig
|
|
{ _srcSchemaRegistryWebhook :: T.Text,
|
|
_srcSchemaRegistryAccessKey :: Maybe T.Text
|
|
}
|
|
deriving stock (Eq, Show)
|
|
|
|
data SchemaRegistryConfigRaw = SchemaRegistryConfigRaw
|
|
{ _srcrSchemaRegistryWebhook :: Maybe T.Text,
|
|
_srcrSchemaRegistryAccessKey :: Maybe T.Text
|
|
}
|
|
deriving stock (Eq, Show)
|
|
|
|
data SchemaRegistryDetails = SchemaRegistryDetails
|
|
{ _srdlSchemaRole :: RoleName,
|
|
_srdlSchemaInfo :: GQLSchemaInformation
|
|
}
|
|
deriving stock (Eq, Show, Generic)
|
|
deriving anyclass (J.FromJSON)
|
|
|
|
instance J.ToJSON SchemaRegistryDetails where
|
|
toJSON (SchemaRegistryDetails schemaRole schemaInfo) =
|
|
J.object
|
|
[ "hasura_schema_role" J..= schemaRole,
|
|
"schema_info" J..= schemaInfo
|
|
]
|
|
|
|
type SchemaRegistryDetailsList = [SchemaRegistryDetails]
|
|
|
|
-- | Context required to upate schema registry everytime the schema is updated
|
|
data SchemaRegistryContext = SchemaRegistryContext
|
|
{ _srpaSchemaRegistryTQueueRef :: STM.TQueue ProjectGQLSchemaInformation,
|
|
_srpaMetadataDbPoolRef :: PG.PGPool
|
|
}
|
|
|
|
newtype SchemaRegistryControlRole = SchemaRegistryControlRole {unSchemaRegistryControlRole :: T.Text}
|
|
deriving stock (Eq, Show)
|
|
|
|
selectNowQuery :: PG.TxE QErr UTCTime
|
|
selectNowQuery =
|
|
runIdentity
|
|
. PG.getRow
|
|
<$> PG.withQE SQLTypes.defaultTxErrorHandler (PG.fromText "SELECT now();") () False
|
|
|
|
calculateSchemaSDLHash :: T.Text -> RoleName -> SchemaHash
|
|
calculateSchemaSDLHash sdl role = SchemaHash $ bsToTxt hash
|
|
where
|
|
hash =
|
|
cryptoHash
|
|
$ J.object
|
|
[ "schema_sdl" J..= sdl,
|
|
"role" J..= roleNameToTxt role
|
|
]
|