@dossierhq/graphql
Version:
A library for creating GraphQL servers with Dossier.
1,186 lines (1,185 loc) • 62.6 kB
JavaScript
/// <reference types="./GraphQLSchemaGenerator.d.ts" />
import { EventType, FieldType, isComponentItemField, notOk, } from '@dossierhq/core';
import { GraphQLBoolean, GraphQLEnumType, GraphQLFloat, GraphQLID, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, } from 'graphql';
import { isComponent, loadAdminEntities, loadAdminEntitiesSample, loadAdminEntity, loadAdminEntityList, loadChangelogEvents, loadPublishedEntities, loadPublishedEntitiesSample, loadPublishedEntity, loadPublishedEntityList, } from './DataLoaders.js';
import * as Mutations from './Mutations.js';
import { toAdminComponentInputTypeName, toAdminCreateInputTypeName, toAdminCreatePayloadTypeName, toAdminTypeName, toAdminUpdateInputTypeName, toAdminUpdatePayloadTypeName, toAdminUpsertInputTypeName, toAdminUpsertPayloadTypeName, toPublishedTypeName, } from './NameGenerator.js';
import { DateTimeScalar } from './scalars/DateTimeScalar.js';
import { LocationScalar } from './scalars/LocationScalar.js';
import { TypeRepository } from './TypeRepository.js';
import { assertExhaustive } from './utils/AssertUtils.js';
import { GraphQLJSONObject } from './vendor/GraphQLJsonScalar.js';
function fieldConfigWithArgs(config) {
return config;
}
export class GraphQLSchemaGenerator extends TypeRepository {
schema;
publishedSchema;
constructor({ schema, publishedSchema, }) {
super();
this.schema = schema;
this.publishedSchema = publishedSchema;
}
addSharedSupportingTypes() {
// Node
this.addType(new GraphQLInterfaceType({
name: 'Node',
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
},
}));
// PageInfo
this.addType(new GraphQLObjectType({
name: 'PageInfo',
fields: {
hasNextPage: { type: new GraphQLNonNull(GraphQLBoolean) },
hasPreviousPage: { type: new GraphQLNonNull(GraphQLBoolean) },
startCursor: { type: new GraphQLNonNull(GraphQLString) },
endCursor: { type: new GraphQLNonNull(GraphQLString) },
},
}));
const containsEntityTypes = !!(this.schema && this.schema.getEntityTypeCount() > 0) ||
!!(this.publishedSchema && this.publishedSchema.getEntityTypeCount() > 0);
if (!containsEntityTypes) {
return;
}
// EntityReferenceInput
this.addType(new GraphQLInputObjectType({
name: 'EntityReferenceInput',
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
},
}));
// BoundingBoxInput
this.addType(new GraphQLInputObjectType({
name: 'BoundingBoxInput',
fields: {
minLat: { type: new GraphQLNonNull(GraphQLFloat) },
maxLat: { type: new GraphQLNonNull(GraphQLFloat) },
minLng: { type: new GraphQLNonNull(GraphQLFloat) },
maxLng: { type: new GraphQLNonNull(GraphQLFloat) },
},
}));
}
addPublishedSupportingTypes(publishedSchema) {
if (publishedSchema.getEntityTypeCount() === 0) {
return;
}
// PublishedEntityType
const entityTypeEnumValues = {};
for (const entitySpec of publishedSchema.spec.entityTypes) {
entityTypeEnumValues[entitySpec.name] = {};
}
this.addType(new GraphQLEnumType({
name: 'PublishedEntityType',
values: entityTypeEnumValues,
}));
if (publishedSchema.getComponentTypeCount() > 0) {
// PublishedComponentType
const componentTypeEnumValues = {};
for (const componentSpec of publishedSchema.spec.componentTypes) {
componentTypeEnumValues[componentSpec.name] = {};
}
this.addType(new GraphQLEnumType({
name: 'PublishedComponentType',
values: componentTypeEnumValues,
}));
}
// PublishedEntityInfo
this.addType(new GraphQLObjectType({
name: 'PublishedEntityInfo',
fields: {
name: { type: new GraphQLNonNull(GraphQLString) },
authKey: { type: new GraphQLNonNull(GraphQLString) },
createdAt: { type: new GraphQLNonNull(DateTimeScalar) },
valid: { type: new GraphQLNonNull(GraphQLBoolean) },
},
}));
// PublishedEntity
this.addType(new GraphQLInterfaceType({
name: 'PublishedEntity',
interfaces: this.getInterfaces('Node'),
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
info: { type: new GraphQLNonNull(this.getOutputType('PublishedEntityInfo')) },
},
}));
if (publishedSchema.getComponentTypeCount() > 0) {
// PublishedValue
this.addType(new GraphQLInterfaceType({
name: toPublishedTypeName('Component'),
fields: {
type: { type: new GraphQLNonNull(this.getEnumType('PublishedComponentType')) },
},
}));
}
// PublishedRichText
this.addType(new GraphQLObjectType({
name: 'PublishedRichText',
fields: {
root: { type: new GraphQLNonNull(GraphQLJSONObject) },
entities: { type: new GraphQLList(this.getInterface('PublishedEntity')) },
},
}));
// PublishedUniqueIndex
const uniqueIndexNames = publishedSchema.spec.indexes
.filter((it) => it.type === 'unique')
.map((it) => it.name);
if (uniqueIndexNames.length > 0) {
const uniqueIndexEnumValues = {};
for (const indexName of uniqueIndexNames) {
uniqueIndexEnumValues[indexName] = {};
}
this.addType(new GraphQLEnumType({
name: 'PublishedUniqueIndex',
values: uniqueIndexEnumValues,
}));
}
// PublishedEntityEdge
this.addType(new GraphQLObjectType({
name: 'PublishedEntityEdge',
fields: {
node: { type: this.getOutputType('PublishedEntity') },
cursor: { type: new GraphQLNonNull(GraphQLString) },
},
}));
// PublishedEntityConnection
this.addType(new GraphQLObjectType({
name: 'PublishedEntityConnection',
fields: {
pageInfo: { type: new GraphQLNonNull(this.getOutputType('PageInfo')) },
edges: { type: new GraphQLList(this.getOutputType('PublishedEntityEdge')) },
totalCount: { type: new GraphQLNonNull(GraphQLInt) },
},
}));
// PublishedEntitySamplingPayload
this.addType(new GraphQLObjectType({
name: 'PublishedEntitySamplingPayload',
fields: {
seed: { type: new GraphQLNonNull(GraphQLInt) },
totalCount: { type: new GraphQLNonNull(GraphQLInt) },
items: { type: new GraphQLList(this.getOutputType('PublishedEntity')) },
},
}));
// PublishedEntityQueryOrder
this.addType(new GraphQLEnumType({
name: 'PublishedEntityQueryOrder',
values: { createdAt: {}, name: {} },
}));
// PublishedQueryInput
const sharedQueryInputFields = {
authKeys: { type: new GraphQLList(new GraphQLNonNull(GraphQLString)) },
entityTypes: {
type: new GraphQLList(new GraphQLNonNull(this.getEnumType('PublishedEntityType'))),
},
...(publishedSchema.getComponentTypeCount() > 0
? {
componentTypes: {
type: new GraphQLList(new GraphQLNonNull(this.getEnumType('PublishedComponentType'))),
},
}
: {}),
linksTo: { type: this.getInputType('EntityReferenceInput') },
linksFrom: { type: this.getInputType('EntityReferenceInput') },
boundingBox: { type: this.getInputType('BoundingBoxInput') },
text: { type: GraphQLString },
};
this.addType(new GraphQLInputObjectType({
name: 'PublishedQueryInput',
fields: sharedQueryInputFields,
}));
// PublishedEntitiesQueryInput
this.addType(new GraphQLInputObjectType({
name: 'PublishedEntitiesQueryInput',
fields: {
...sharedQueryInputFields,
order: { type: this.getEnumType('PublishedEntityQueryOrder') },
reverse: { type: GraphQLBoolean },
},
}));
}
addPublishedEntityTypes(publishedSchema) {
for (const entitySpec of publishedSchema.spec.entityTypes) {
this.addPublishedEntityType(entitySpec);
}
}
addPublishedEntityType(entitySpec) {
// PublishedFooFields
const fieldsTypeName = `Published${entitySpec.name}Fields`;
if (entitySpec.fields.length > 0) {
this.addType(new GraphQLObjectType({
name: fieldsTypeName,
fields: () => {
const fields = {};
this.addTypeSpecificationOutputFields(entitySpec, fields, false);
return fields;
},
}));
}
// PublishedFoo
this.addType(new GraphQLObjectType({
name: toPublishedTypeName(entitySpec.name),
interfaces: this.getInterfaces('Node', 'PublishedEntity'),
isTypeOf: (source, _context, _info) => source.info.type === entitySpec.name,
fields: () => {
const fields = {
id: { type: new GraphQLNonNull(GraphQLID) },
info: { type: new GraphQLNonNull(this.getOutputType('PublishedEntityInfo')) },
};
if (entitySpec.fields.length > 0) {
fields.fields = { type: new GraphQLNonNull(this.getOutputType(fieldsTypeName)) };
}
return fields;
},
}));
}
addPublishedComponentTypes(publishedSchema) {
for (const componentSpec of publishedSchema.spec.componentTypes) {
this.addPublishedComponentType(componentSpec);
}
}
addPublishedComponentType(componentSpec) {
// PublishedFoo
this.addType(new GraphQLObjectType({
name: toPublishedTypeName(componentSpec.name),
interfaces: this.getInterfaces(toPublishedTypeName('Component')),
isTypeOf: (source, _context, _info) => source.type === componentSpec.name,
fields: () => {
const fields = {
type: { type: new GraphQLNonNull(this.getEnumType('PublishedComponentType')) },
};
this.addTypeSpecificationOutputFields(componentSpec, fields, false);
return fields;
},
}));
}
addAdminSupportingTypes(schema) {
if (schema.getEntityTypeCount() === 0) {
return;
}
this.addChangelogSupportingTypes();
// EntityType
const entityTypeEnumValues = {};
for (const entitySpec of schema.spec.entityTypes) {
entityTypeEnumValues[entitySpec.name] = {};
}
this.addType(new GraphQLEnumType({
name: 'EntityType',
values: entityTypeEnumValues,
}));
if (schema.getComponentTypeCount() > 0) {
// ComponentType
const componentTypeEnumValues = {};
for (const componentSpec of schema.spec.componentTypes) {
componentTypeEnumValues[componentSpec.name] = {};
}
this.addType(new GraphQLEnumType({
name: 'ComponentType',
values: componentTypeEnumValues,
}));
}
// EntityStatus
this.addType(new GraphQLEnumType({
name: 'EntityStatus',
values: {
draft: {},
published: {},
modified: {},
withdrawn: {},
archived: {},
},
}));
// EntityInfo
this.addType(new GraphQLObjectType({
name: 'EntityInfo',
fields: {
type: { type: new GraphQLNonNull(this.getOutputType('EntityType')) },
name: { type: new GraphQLNonNull(GraphQLString) },
version: { type: new GraphQLNonNull(GraphQLInt) },
authKey: { type: new GraphQLNonNull(GraphQLString) },
status: { type: new GraphQLNonNull(this.getOutputType('EntityStatus')) },
valid: { type: new GraphQLNonNull(GraphQLBoolean) },
validPublished: { type: GraphQLBoolean },
createdAt: { type: new GraphQLNonNull(DateTimeScalar) },
updatedAt: { type: new GraphQLNonNull(DateTimeScalar) },
},
}));
// EntityCreateInfo
this.addType(new GraphQLInputObjectType({
name: 'EntityCreateInfo',
fields: {
type: { type: this.getEnumType('EntityType') },
name: { type: new GraphQLNonNull(GraphQLString) },
version: { type: GraphQLInt },
authKey: { type: GraphQLString },
},
}));
// EntityCreateEffect
this.addType(new GraphQLEnumType({
name: 'EntityCreateEffect',
values: {
created: {},
createdAndPublished: {},
none: {},
},
}));
// EntityUpdateInfo
this.addType(new GraphQLInputObjectType({
name: 'EntityUpdateInfo',
fields: {
type: { type: this.getEnumType('EntityType') },
name: { type: GraphQLString },
version: { type: GraphQLInt },
authKey: { type: GraphQLString },
},
}));
// EntityUpdateEffect
this.addType(new GraphQLEnumType({
name: 'EntityUpdateEffect',
values: {
updated: {},
updatedAndPublished: {},
published: {},
none: {},
},
}));
// EntityUpsertInfo
this.addType(new GraphQLInputObjectType({
name: 'EntityUpsertInfo',
fields: {
type: { type: new GraphQLNonNull(this.getEnumType('EntityType')) },
name: { type: new GraphQLNonNull(GraphQLString) },
authKey: { type: GraphQLString },
},
}));
// EntityUpsertEffect
this.addType(new GraphQLEnumType({
name: 'EntityUpsertEffect',
values: {
created: {},
createdAndPublished: {},
updated: {},
updatedAndPublished: {},
published: {},
none: {},
},
}));
// Entity
this.addType(new GraphQLInterfaceType({
name: 'Entity',
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
info: { type: new GraphQLNonNull(this.getOutputType('EntityInfo')) },
changelogEvents: {
type: this.getOutputType('EntityChangelogEventConnection'),
args: {
query: { type: this.getInputType('ChangelogEventQueryInput') },
first: { type: GraphQLInt },
after: { type: GraphQLString },
last: { type: GraphQLInt },
before: { type: GraphQLString },
},
},
},
}));
// UniqueIndex
const uniqueIndexNames = schema.spec.indexes
.filter((it) => it.type === 'unique')
.map((it) => it.name);
if (uniqueIndexNames.length > 0) {
const uniqueIndexEnumValues = {};
for (const indexName of uniqueIndexNames) {
uniqueIndexEnumValues[indexName] = {};
}
this.addType(new GraphQLEnumType({
name: 'UniqueIndex',
values: uniqueIndexEnumValues,
}));
}
// EntityEdge
this.addType(new GraphQLObjectType({
name: 'EntityEdge',
fields: {
node: { type: this.getOutputType('Entity') },
cursor: { type: new GraphQLNonNull(GraphQLString) },
},
}));
// EntityConnection
this.addType(new GraphQLObjectType({
name: 'EntityConnection',
fields: {
pageInfo: { type: new GraphQLNonNull(this.getOutputType('PageInfo')) },
edges: { type: new GraphQLList(this.getOutputType('EntityEdge')) },
totalCount: { type: new GraphQLNonNull(GraphQLInt) },
},
}));
// EntitySamplingPayload
this.addType(new GraphQLObjectType({
name: 'EntitySamplingPayload',
fields: {
seed: { type: new GraphQLNonNull(GraphQLInt) },
totalCount: { type: new GraphQLNonNull(GraphQLInt) },
items: { type: new GraphQLList(this.getOutputType('Entity')) },
},
}));
// EntityQueryOrder
this.addType(new GraphQLEnumType({
name: 'EntityQueryOrder',
values: { createdAt: {}, updatedAt: {}, name: {} },
}));
// EntitySharedQueryInput
const sharedQueryInputFields = {
authKeys: { type: new GraphQLList(new GraphQLNonNull(GraphQLString)) },
entityTypes: {
type: new GraphQLList(new GraphQLNonNull(this.getEnumType('EntityType'))),
},
...(schema.getComponentTypeCount() > 0
? {
componentTypes: {
type: new GraphQLList(new GraphQLNonNull(this.getEnumType('ComponentType'))),
},
}
: {}),
status: { type: new GraphQLList(new GraphQLNonNull(this.getEnumType('EntityStatus'))) },
valid: { type: GraphQLBoolean },
linksTo: { type: this.getInputType('EntityReferenceInput') },
linksFrom: { type: this.getInputType('EntityReferenceInput') },
boundingBox: { type: this.getInputType('BoundingBoxInput') },
text: { type: GraphQLString },
};
this.addType(new GraphQLInputObjectType({
name: 'EntitySharedQueryInput',
fields: sharedQueryInputFields,
}));
// EntityQueryInput
this.addType(new GraphQLInputObjectType({
name: 'EntityQueryInput',
fields: {
...sharedQueryInputFields,
order: { type: this.getEnumType('EntityQueryOrder') },
reverse: { type: GraphQLBoolean },
},
}));
// EntityVersionReferenceInput
this.addType(new GraphQLInputObjectType({
name: 'EntityVersionReferenceInput',
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
version: { type: new GraphQLNonNull(GraphQLInt) },
},
}));
if (this.schema && this.schema.getComponentTypeCount() > 0) {
// Component
this.addType(new GraphQLInterfaceType({
name: 'Component',
fields: {
type: { type: new GraphQLNonNull(this.getEnumType('ComponentType')) },
},
}));
}
// RichText
this.addType(new GraphQLObjectType({
name: 'RichText',
fields: {
root: { type: new GraphQLNonNull(GraphQLJSONObject) },
entities: { type: new GraphQLList(this.getInterface('Entity')) },
},
}));
// RichTextInput
this.addType(new GraphQLInputObjectType({
name: 'RichTextInput',
fields: {
root: { type: new GraphQLNonNull(GraphQLJSONObject) },
},
}));
// EntityVersionInfo
this.addType(new GraphQLObjectType({
name: 'EntityVersionInfo',
fields: {
version: { type: new GraphQLNonNull(GraphQLInt) },
published: { type: new GraphQLNonNull(GraphQLBoolean) },
createdBy: { type: new GraphQLNonNull(GraphQLID) },
createdAt: { type: new GraphQLNonNull(DateTimeScalar) },
},
}));
// EntityPublishEffect
this.addType(new GraphQLEnumType({
name: 'EntityPublishEffect',
values: {
published: {},
none: {},
},
}));
// EntityPublishPayload
this.addType(new GraphQLObjectType({
name: 'EntityPublishPayload',
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
status: { type: new GraphQLNonNull(this.getEnumType('EntityStatus')) },
effect: { type: new GraphQLNonNull(this.getEnumType('EntityPublishEffect')) },
updatedAt: { type: new GraphQLNonNull(DateTimeScalar) },
},
}));
// EntityUnpublishEffect
this.addType(new GraphQLEnumType({
name: 'EntityUnpublishEffect',
values: {
unpublished: {},
none: {},
},
}));
// EntityUnpublishPayload
this.addType(new GraphQLObjectType({
name: 'EntityUnpublishPayload',
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
status: { type: new GraphQLNonNull(this.getEnumType('EntityStatus')) },
effect: { type: new GraphQLNonNull(this.getEnumType('EntityUnpublishEffect')) },
updatedAt: { type: new GraphQLNonNull(DateTimeScalar) },
},
}));
// EntityArchiveEffect
this.addType(new GraphQLEnumType({
name: 'EntityArchiveEffect',
values: {
archived: {},
none: {},
},
}));
// EntityArchivePayload
this.addType(new GraphQLObjectType({
name: 'EntityArchivePayload',
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
status: { type: new GraphQLNonNull(this.getEnumType('EntityStatus')) },
effect: { type: new GraphQLNonNull(this.getEnumType('EntityArchiveEffect')) },
updatedAt: { type: new GraphQLNonNull(DateTimeScalar) },
},
}));
// EntityUnarchiveEffect
this.addType(new GraphQLEnumType({
name: 'EntityUnarchiveEffect',
values: {
unarchived: {},
none: {},
},
}));
// EntityUnarchivePayload
this.addType(new GraphQLObjectType({
name: 'EntityUnarchivePayload',
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
status: { type: new GraphQLNonNull(this.getEnumType('EntityStatus')) },
effect: { type: new GraphQLNonNull(this.getEnumType('EntityUnarchiveEffect')) },
updatedAt: { type: new GraphQLNonNull(DateTimeScalar) },
},
}));
// EntityDeleteEffect
this.addType(new GraphQLEnumType({
name: 'EntityDeleteEffect',
values: {
deleted: {},
},
}));
// EntityDeletePayload
this.addType(new GraphQLObjectType({
name: 'EntityDeletePayload',
fields: {
effect: { type: new GraphQLNonNull(this.getEnumType('EntityDeleteEffect')) },
deletedAt: { type: new GraphQLNonNull(DateTimeScalar) },
},
}));
// AdvisoryLockPayload
this.addType(new GraphQLObjectType({
name: 'AdvisoryLockPayload',
fields: {
name: { type: new GraphQLNonNull(GraphQLString) },
handle: { type: new GraphQLNonNull(GraphQLInt) },
},
}));
// AdvisoryLockReleasePayload
this.addType(new GraphQLObjectType({
name: 'AdvisoryLockReleasePayload',
fields: {
name: { type: new GraphQLNonNull(GraphQLString) },
},
}));
}
addChangelogSupportingTypes() {
// EventType
this.addType(new GraphQLEnumType({
name: 'EventType',
values: {
createPrincipal: {},
updateSchema: {},
createEntity: {},
createAndPublishEntity: {},
updateEntity: {},
updateAndPublishEntity: {},
publishEntities: {},
unpublishEntities: {},
archiveEntity: {},
unarchiveEntity: {},
deleteEntities: {},
},
}));
// ChangelogEventQueryInput
this.addType(new GraphQLInputObjectType({
name: 'ChangelogEventQueryInput',
fields: {
reverse: { type: GraphQLBoolean },
createdBy: { type: GraphQLID },
types: { type: new GraphQLList(new GraphQLNonNull(this.getEnumType('EventType'))) },
},
}));
// ChangelogEvent
this.addType(new GraphQLInterfaceType({
name: 'ChangelogEvent',
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
type: { type: new GraphQLNonNull(this.getEnumType('EventType')) },
createdBy: { type: new GraphQLNonNull(GraphQLID) },
createdAt: { type: new GraphQLNonNull(DateTimeScalar) },
},
}));
// CreatePrincipalChangelogEvent
this.addType(new GraphQLObjectType({
name: 'CreatePrincipalChangelogEvent',
interfaces: this.getInterfaces('ChangelogEvent'),
isTypeOf: (source, _context, _info) => source.type === EventType.createPrincipal,
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
type: { type: new GraphQLNonNull(this.getEnumType('EventType')) },
createdBy: { type: new GraphQLNonNull(GraphQLID) },
createdAt: { type: new GraphQLNonNull(DateTimeScalar) },
},
}));
// SchemaChangelogEvent
this.addType(new GraphQLObjectType({
name: 'SchemaChangelogEvent',
interfaces: this.getInterfaces('ChangelogEvent'),
isTypeOf: (source, _context, _info) => source.type === EventType.updateSchema,
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
type: { type: new GraphQLNonNull(this.getEnumType('EventType')) },
createdBy: { type: new GraphQLNonNull(GraphQLID) },
createdAt: { type: new GraphQLNonNull(DateTimeScalar) },
version: { type: new GraphQLNonNull(GraphQLInt) },
},
}));
// EntityChangelogEventEntityInfo
this.addType(new GraphQLObjectType({
name: 'EntityChangelogEventEntityInfo',
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
version: { type: new GraphQLNonNull(GraphQLInt) },
type: { type: new GraphQLNonNull(GraphQLString) },
name: { type: new GraphQLNonNull(GraphQLString) },
},
}));
// EntityChangelogEvent
this.addType(new GraphQLObjectType({
name: 'EntityChangelogEvent',
interfaces: this.getInterfaces('ChangelogEvent'),
isTypeOf: (source, _context, _info) => source.type !== EventType.updateSchema && source.type !== EventType.createPrincipal,
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
type: { type: new GraphQLNonNull(this.getEnumType('EventType')) },
createdBy: { type: new GraphQLNonNull(GraphQLID) },
createdAt: { type: new GraphQLNonNull(DateTimeScalar) },
entities: {
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(this.getOutputType('EntityChangelogEventEntityInfo')))),
},
unauthorizedEntityCount: { type: new GraphQLNonNull(GraphQLInt) },
},
}));
// ChangelogEventEdge
this.addType(new GraphQLObjectType({
name: 'ChangelogEventEdge',
fields: {
node: { type: this.getOutputType('ChangelogEvent') },
cursor: { type: new GraphQLNonNull(GraphQLString) },
},
}));
// ChangelogEventConnection
this.addType(new GraphQLObjectType({
name: 'ChangelogEventConnection',
fields: {
pageInfo: { type: new GraphQLNonNull(this.getOutputType('PageInfo')) },
edges: { type: new GraphQLList(this.getOutputType('ChangelogEventEdge')) },
totalCount: { type: new GraphQLNonNull(GraphQLInt) },
},
}));
// EntityChangelogEventEdge
this.addType(new GraphQLObjectType({
name: 'EntityChangelogEventEdge',
fields: {
node: { type: this.getOutputType('EntityChangelogEvent') },
cursor: { type: new GraphQLNonNull(GraphQLString) },
},
}));
// EntityChangelogEventConnection
this.addType(new GraphQLObjectType({
name: 'EntityChangelogEventConnection',
fields: {
pageInfo: { type: new GraphQLNonNull(this.getOutputType('PageInfo')) },
edges: { type: new GraphQLList(this.getOutputType('EntityChangelogEventEdge')) },
totalCount: { type: new GraphQLNonNull(GraphQLInt) },
},
}));
}
addEntityTypes(schema) {
for (const entitySpec of schema.spec.entityTypes) {
this.addEntityType(entitySpec);
}
}
addEntityType(entitySpec) {
// FooFields
const fieldsName = entitySpec.fields.length > 0 ? `${toAdminTypeName(entitySpec.name)}Fields` : null;
if (fieldsName) {
this.addType(new GraphQLObjectType({
name: fieldsName,
fields: () => {
const fields = {};
this.addTypeSpecificationOutputFields(entitySpec, fields, true);
return fields;
},
}));
}
// Foo
this.addType(new GraphQLObjectType({
name: toAdminTypeName(entitySpec.name),
interfaces: this.getInterfaces(toAdminTypeName('Entity')),
isTypeOf: (source, _context, _info) => source.info.type === entitySpec.name,
fields: () => {
const fields = {
id: { type: new GraphQLNonNull(GraphQLID) },
info: { type: new GraphQLNonNull(this.getOutputType('EntityInfo')) },
changelogEvents: {
type: this.getOutputType('EntityChangelogEventConnection'),
args: {
query: { type: this.getInputType('ChangelogEventQueryInput') },
first: { type: GraphQLInt },
after: { type: GraphQLString },
last: { type: GraphQLInt },
before: { type: GraphQLString },
},
},
};
if (fieldsName) {
fields.fields = { type: new GraphQLNonNull(this.getOutputType(fieldsName)) };
}
return fields;
},
}));
// FooFieldsInput
const inputFieldsName = entitySpec.fields.length > 0 ? `${toAdminTypeName(entitySpec.name)}FieldsInput` : null;
if (inputFieldsName) {
this.addType(new GraphQLInputObjectType({
name: inputFieldsName,
fields: () => {
const fields = {};
this.addTypeSpecificationInputFields(entitySpec, fields);
return fields;
},
}));
}
// FooCreateInput
this.addType(new GraphQLInputObjectType({
name: toAdminCreateInputTypeName(entitySpec.name),
fields: () => {
const fields = {
id: { type: GraphQLID },
info: { type: new GraphQLNonNull(this.getInputType('EntityCreateInfo')) },
};
if (inputFieldsName) {
fields.fields = { type: new GraphQLNonNull(this.getInputType(inputFieldsName)) };
}
return fields;
},
}));
// FooCreatePayload
this.addType(new GraphQLObjectType({
name: toAdminCreatePayloadTypeName(entitySpec.name),
fields: () => {
const fields = {
effect: { type: new GraphQLNonNull(this.getEnumType('EntityCreateEffect')) },
entity: {
type: new GraphQLNonNull(this.getOutputType(toAdminTypeName(entitySpec.name))),
},
};
return fields;
},
}));
// FooUpdateInput
this.addType(new GraphQLInputObjectType({
name: toAdminUpdateInputTypeName(entitySpec.name),
fields: () => {
const fields = {
id: { type: new GraphQLNonNull(GraphQLID) },
info: { type: this.getInputType('EntityUpdateInfo') },
};
if (inputFieldsName) {
fields.fields = { type: new GraphQLNonNull(this.getInputType(inputFieldsName)) };
}
return fields;
},
}));
// FooUpdatePayload
this.addType(new GraphQLObjectType({
name: toAdminUpdatePayloadTypeName(entitySpec.name),
fields: () => {
const fields = {
effect: { type: new GraphQLNonNull(this.getEnumType('EntityUpdateEffect')) },
entity: {
type: new GraphQLNonNull(this.getOutputType(toAdminTypeName(entitySpec.name))),
},
};
return fields;
},
}));
// FooUpsertInput
this.addType(new GraphQLInputObjectType({
name: toAdminUpsertInputTypeName(entitySpec.name),
fields: () => {
const fields = {
id: { type: new GraphQLNonNull(GraphQLID) },
info: { type: new GraphQLNonNull(this.getInputType('EntityUpsertInfo')) },
};
if (inputFieldsName) {
fields.fields = { type: new GraphQLNonNull(this.getInputType(inputFieldsName)) };
}
return fields;
},
}));
// AdminFooUpsertPayload
this.addType(new GraphQLObjectType({
name: toAdminUpsertPayloadTypeName(entitySpec.name),
fields: () => {
const fields = {
effect: { type: new GraphQLNonNull(this.getEnumType('EntityUpsertEffect')) },
entity: {
type: new GraphQLNonNull(this.getOutputType(toAdminTypeName(entitySpec.name))),
},
};
return fields;
},
}));
}
addAdminComponentTypes(schema) {
for (const componentSpec of schema.spec.componentTypes) {
this.addAdminComponentType(componentSpec);
}
}
addAdminComponentType(componentSpec) {
// Foo
this.addType(new GraphQLObjectType({
name: toAdminTypeName(componentSpec.name),
interfaces: this.getInterfaces(toAdminTypeName('Component')),
isTypeOf: (source, _context, _info) => source.type === componentSpec.name,
fields: () => {
const fields = {
type: { type: new GraphQLNonNull(this.getEnumType('ComponentType')) },
};
this.addTypeSpecificationOutputFields(componentSpec, fields, true);
return fields;
},
}));
this.addType(new GraphQLInputObjectType({
name: toAdminComponentInputTypeName(componentSpec.name),
fields: () => {
const fields = {
type: { type: new GraphQLNonNull(this.getEnumType('ComponentType')) },
};
this.addTypeSpecificationInputFields(componentSpec, fields);
return fields;
},
}));
}
addTypeSpecificationOutputFields(typeSpec, fields, isAdmin) {
for (const fieldSpec of typeSpec.fields) {
let fieldType;
switch (fieldSpec.type) {
case FieldType.Boolean:
fieldType = GraphQLBoolean;
break;
case FieldType.Component:
fieldType = this.getOrCreateValueUnion(isAdmin, fieldSpec.componentTypes ?? []);
break;
case FieldType.Reference:
fieldType = this.getOrCreateEntityUnion(isAdmin, fieldSpec.entityTypes ?? []);
break;
case FieldType.Location:
fieldType = LocationScalar;
break;
case FieldType.Number:
fieldType = fieldSpec.integer ? GraphQLInt : GraphQLFloat;
break;
case FieldType.RichText:
fieldType = this.getOutputType(toAdminTypeName('RichText', isAdmin));
break;
case FieldType.String:
fieldType = GraphQLString;
break;
default:
assertExhaustive(fieldSpec);
}
if (fieldSpec.list) {
fieldType = new GraphQLList(new GraphQLNonNull(fieldType));
}
if (fieldSpec.required && !isAdmin) {
fieldType = new GraphQLNonNull(fieldType);
}
fields[fieldSpec.name] = { type: fieldType };
}
}
addTypeSpecificationInputFields(typeSpec, fields) {
for (const fieldSpec of typeSpec.fields) {
let fieldType;
switch (fieldSpec.type) {
case FieldType.Boolean:
fieldType = GraphQLBoolean;
break;
case FieldType.Reference:
fieldType = this.getInputType('EntityReferenceInput');
break;
case FieldType.Location:
fieldType = LocationScalar;
break;
case FieldType.Number:
fieldType = fieldSpec.integer ? GraphQLInt : GraphQLFloat;
break;
case FieldType.RichText:
fieldType = this.getInputType('RichTextInput');
break;
case FieldType.String:
fieldType = GraphQLString;
break;
case FieldType.Component: {
//TODO use GraphQLJSON. Is it still needed or is normal fieldType enough?
fields[`${fieldSpec.name}Json`] = { type: GraphQLString };
fieldType = this.getValueInputType(fieldSpec.componentTypes ?? []);
break;
}
default:
assertExhaustive(fieldSpec);
}
if (fieldType) {
fields[fieldSpec.name] = {
type: fieldSpec.list ? new GraphQLList(new GraphQLNonNull(fieldType)) : fieldType,
};
}
}
}
buildQueryFieldNode(publishedSchema) {
return fieldConfigWithArgs({
type: this.getInterface('Node'),
args: {
id: { type: new GraphQLNonNull(GraphQLID) },
},
resolve: async (_source, args, context, _info) => {
return await loadPublishedEntity(publishedSchema, context, args);
},
});
}
buildQueryFieldNodes(publishedSchema) {
return fieldConfigWithArgs({
type: new GraphQLList(this.getInterface('Node')),
args: {
ids: { type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLID))) },
},
resolve: async (_source, args, context, _info) => {
return await loadPublishedEntityList(publishedSchema, context, args.ids);
},
});
}
buildQueryFieldPublishedEntity(publishedSchema) {
if (publishedSchema.spec.indexes.length === 0) {
return fieldConfigWithArgs({
type: this.getInterface('PublishedEntity'),
args: {
id: { type: new GraphQLNonNull(GraphQLID) },
},
resolve: async (_source, args, context, _info) => {
return await loadPublishedEntity(publishedSchema, context, args);
},
});
}
return fieldConfigWithArgs({
type: this.getInterface('PublishedEntity'),
args: {
id: { type: GraphQLID },
index: { type: this.getInputType('PublishedUniqueIndex') },
value: { type: GraphQLString },
},
resolve: async (_source, args, context, _info) => {
let reference;
if (args.id) {
reference = { id: args.id };
}
else if (args.index && args.value) {
reference = { index: args.index, value: args.value };
}
else {
throw new Error('Either id or index and value must be specified');
}
return await loadPublishedEntity(publishedSchema, context, reference);
},
});
}
buildQueryFieldAdminEntity(schema) {
if (schema.spec.indexes.length === 0) {
return fieldConfigWithArgs({
type: this.getInterface('Entity'),
args: {
id: { type: new GraphQLNonNull(GraphQLID) },
version: { type: GraphQLInt },
},
resolve: async (_source, args, context, _info) => {
let reference;
if (typeof args.version === 'number') {
reference = { id: args.id, version: args.version };
}
else {
reference = { id: args.id };
}
return await loadAdminEntity(schema, context, reference);
},
});
}
return fieldConfigWithArgs({
type: this.getInterface('Entity'),
args: {
id: { type: GraphQLID },
version: { type: GraphQLInt },
index: { type: this.getInputType('UniqueIndex') },
value: { type: GraphQLString },
},
resolve: async (_source, args, context, _info) => {
let reference;
if (args.id && typeof args.version === 'number') {
reference = { id: args.id, version: args.version };
}
else if (args.id) {
reference = { id: args.id };
}
else if (args.index && args.value) {
reference = { index: args.index, value: args.value };
}
else {
throw new Error('Either (id), (id and version) or (index and value) must be specified');
}
return await loadAdminEntity(schema, context, reference);
},
});
}
buildQueryFieldAdminEntityList(schema) {
return fieldConfigWithArgs({
type: new GraphQLList(this.getInterface('Entity')),
args: {
ids: { type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLID))) },
},
resolve: async (_source, args, context, _info) => {
return await loadAdminEntityList(schema, context, args.ids);
},
});
}
buildQueryFieldAdminEntitiesSample(schema) {
return fieldConfigWithArgs({
type: this.getOutputType('EntitySamplingPayload'),
args: {
query: { type: this.getInputType('EntitySharedQueryInput') },
seed: { type: GraphQLInt },
count: { type: GraphQLInt },
},
resolve: async (_source, args, context, _info) => {
const { query, seed, count } = args;
const options = { seed, count };
return await loadAdminEntitiesSample(schema, context, query, options);
},
});
}
buildQueryFieldAdminEntities(schema) {
return fieldConfigWithArgs({
type: this.getOutputType('EntityConnection'),
args: {
query: { type: this.getInputType('EntityQueryInput') },
first: { type: GraphQLInt },
after: { type: GraphQLString },
last: { type: GraphQLInt },
before: { type: GraphQLString },
},
resolve: async (_source, args, context, info) => {
const { query, first, after, last, before } = args;
const paging = { first, after, last, before };
return await loadAdminEntities(schema, context, query, paging, info);
},
});
}
buildQueryFieldPublishedSampleEntities(publishedSchema) {
return fieldConfigWithArgs({
type: this.getOutputType('PublishedEntitySamplingPayload'),
args: {
query: { type: this.getInputType('PublishedQueryInput') },
seed: { type: GraphQLInt },
count: { type: GraphQLInt },
},
resolve: async (_source, args, context, _info) => {
const { query, count, seed } = args;
const options = { count, seed };
return await loadPublishedEntitiesSample(publishedSchema, context, query, options);
},
});
}
buildQueryFieldPublishedEntities(publishedSchema) {
return fieldConfigWithArgs({
type: this.getOutputType('PublishedEntityConnection'),
args: {
query: { type: this.getInputType('PublishedEntitiesQueryInput') },
first: { type: GraphQLInt },
after: { type: GraphQLString },
last: { type: GraphQLInt },
before: { type: GraphQLString },
},
resolve: async (_source, args, context, info) => {
const { query, first, after, last, before } = args;
const paging = { first, after, last, before };
return await loadPublishedEntities(publishedSchema, context, query, paging, info);
},
});
}
buildQueryFieldChangelogEvents() {
return fieldConfigWithArgs({
type: this.getOutputType('ChangelogEventConnection'),
args: {
query: { type: this.getInputType('ChangelogEventQueryInput') },
first: { type: GraphQLInt },
after: { type: GraphQLString },
last: { type: GraphQLInt },
before: { type: GraphQLString },
},
resolve: async (_source, args, context, info) => {
const { query, first, after, last, before } = args;
const paging = { first, after, last, before };
return await loadChangelogEvents(context, query, paging, info);
},
});
}
buildQueryType() {
return new GraphQLObjectType({
name: 'Query',
fields: {
...(this.publishedSchema && this.publishedSchema.getEntityTypeCount() > 0
? {
node: this.buildQueryFieldNode(this.publishedSchema),
nodes: this.buildQueryFieldNodes(this.publishedSchema),
publishedEntity: this.buildQueryFieldPublishedEntity(this.publishedSchema),
publishedEntities: this.buildQueryFieldPublishedEntities(this.publishedSchema),
publishedEntitiesSample: this.buildQueryFieldPublishedSampleEntities(this.publishedSchema),
}
: {}),
...(this.schema && this.schema.getEntityTypeCount() > 0
? {
entity: this.buildQueryFieldAdminEntity(this.schema),
entityList: this.buildQueryFieldAdminEntityList(this.schema),
entities: this.buildQueryFieldAdminEntities(this.schema),