PR-URL: https://github.com/hasura/graphql-engine-mono/pull/1616 GitOrigin-RevId: f7eefd2367929209aa77895ea585e96a99a78d47
4.4 KiB
Source Customization
See issue #6974.
When adding multiple remote database sources there is a possibility of getting name conflicts if two sources have tables or functions with the same name.
This can be worked around for individual tables by adding a custom_name
and/or custom_root_fields
, but it would be better to have source-level customization options to avoid conflicts.
Spec
Add an optional customization
object to the *_add_source
API:
customization:
root_fields:
namespace: "something"
prefix: some_prefix
suffix: some_suffix
type_names:
prefix: some_prefix
suffix: some_suffix
All fields within the customization
object are optional.
root_fields
provides options for avoiding conflicts in root field names between sources.- If
namespace
is given then all of the source's root fields will be nested under a new namespace root field. - If
prefix
and/orsuffix
are given then they will be applied to the root field names generated for the source.
- If
type_names
provides options for avoiding conflicts in type names generated for a source.- If
prefix
and/orsuffix
are given then they will be applied to the type names generated for the source. - Prefix and suffix only affect types generated specifically for a source.
They do not affect builtin scalar types (
Int
,Float
, etc) or types starting with__
.
- If
Implementation approach
API and metadata changes
New data type SourceCustomization
to be added to AddSource
(for API) and SourceInfo
(for metadata) to represent
the customization options described above.
Type name customization
Type name customizations are applied by passing a customization function into the parser builders and applying it wherever we generate a type name. We add new type definitions:
newtype Typename = Typename {unTypename :: Name} deriving (Eq, Ord, Show, HasName, J.ToJSON)
type MkTypename = Name -> Typename
withTypenameCustomization :: forall m r a. (MonadReader r m, Has MkTypename r) => MkTypename -> m a -> m a
and add Has MkTypename r
constraint to MonadBuildSchema
to allow us to pass the typename customization
function through the schema building code and insert customizations for sources where appropriate.
Remote source relationships
To allow type name customization in remote source relationships, we add the SourceTypeCustomization
for the remote source to RemoteSourceRelationshipInfo
.
This allows us to call withTypenameCustomization
when building the remote source schema.
Relay Node type
The Relay Node
interface type is generated separately from the other query parsers.
We need to make sure type name customizations are applied here too.
Root field name customization
Similar to type name customizations, we add new type definitions:
type MkRootFieldName = Name -> Name
withRootFieldNameCustomization :: forall m r a. (MonadReader r m, Has MkRootFieldName r) => MkRootFieldName -> m a -> m a
and add Has MkRootFieldName r
constraint to MonadBuildSchema
to allow us to apss the root field name customization
function through to places where root field names are constructed.
Namespaces
The collection of root fields is represented in many places using the type InsOrdHashMap Name a
where Name
is the GraphQL name of a root field and a
is whatever data we need associated with that field, e.g. the QueryRootField
or ExecutionStep
. To represent that root fields can now optionally have a namespace, we introduce the new data type
data RootFieldAlias = RootFieldAlias
{ _rfaNamespace :: !(Maybe G.Name),
_rfaAlias :: !G.Name
}
deriving (Show, Eq, Generic)
and the type alias
type RootFieldMap = InsOrdHashMap RootFieldAlias
RootFieldMap a
will now be used instead of InsOrdHashMap Name a
where appropriate.
Subscriptions
JSON result objects for subscriptions are generated by the individual database backends (currently Postgres and MSSQL support subcriptions). If the subscription source has a namespace then we need to wrap the response from the database in an object with the namespace field before sending it to the websocket.
Tech debt
We previously implemented namespaces for remote schemas before the more general RootFieldAlias
field was added.
Now that we have RootFieldAlias
we should use this for remote schema namespaces too.