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.
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_suffixAll fields within the customization object are optional.
root_fieldsprovides options for avoiding conflicts in root field names between sources.- If
namespaceis given then all of the source's root fields will be nested under a new namespace root field. - If
prefixand/orsuffixare given then they will be applied to the root field names generated for the source.
- If
type_namesprovides options for avoiding conflicts in type names generated for a source.- If
prefixand/orsuffixare 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
New data type SourceCustomization to be added to AddSource (for API) and SourceInfo (for metadata) to represent
the customization options described above.
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 aand 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.
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.
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.
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 aand 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.
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 RootFieldAliasRootFieldMap a will now be used instead of InsOrdHashMap Name a where appropriate.
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.
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.