From 7c7d8c68414d22231c3d7b9268eb3aea5fb267ac Mon Sep 17 00:00:00 2001 From: Enda Phelan Date: Wed, 23 Sep 2020 16:53:45 +0100 Subject: [PATCH 1/3] test: add test to ensure generation does not occur if all flags disabled --- .../tests/GraphQLSchemaCreatorTest.ts | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/packages/graphback-codegen-schema/tests/GraphQLSchemaCreatorTest.ts b/packages/graphback-codegen-schema/tests/GraphQLSchemaCreatorTest.ts index 165b29aaa4..4fce14404c 100644 --- a/packages/graphback-codegen-schema/tests/GraphQLSchemaCreatorTest.ts +++ b/packages/graphback-codegen-schema/tests/GraphQLSchemaCreatorTest.ts @@ -415,4 +415,41 @@ test('Transient field is excluded from input types', () => { const userSubscriptionInput = assertInputObjectType(schema.getType('UserFilter')) expect(Object.keys(userSubscriptionInput.getFields())).toEqual(['id', 'name', 'and', 'or', 'not']) +}) + +test('When all CRUD flags are disabled, resolvers and root schema types are not generated', () => { + const model = buildSchema(` + """@model""" + type Note { + id: ID! + title: String + }`) + + const pluginEngine = new GraphbackPluginEngine({ + schema: model, + plugins: [ + new SchemaCRUDPlugin() + ], + config: { + crudMethods: { + find: false, + findOne: false, + create: false, + update: false, + delete: false, + subCreate: false, + subDelete: false, + subUpdate: false + } + } + }); + + const metadata = pluginEngine.createResources(); + const schema = metadata.getSchema(); + const resolvers = metadata.getResolvers(); + + expect(resolvers).toBeUndefined() + expect(schema.getQueryType().getFields()).toEqual({}) + expect(schema.getMutationType()).toBeUndefined() + expect(schema.getSubscriptionType()).toBeUndefined() }) \ No newline at end of file From 8a38d7e713016890e5b8a6e6f98278db1fc6fc56 Mon Sep 17 00:00:00 2001 From: Enda Phelan Date: Thu, 24 Sep 2020 08:29:45 +0100 Subject: [PATCH 2/3] fix(graphql-serve): fix "Unsafe call of an any typed value" --- packages/graphql-serve/src/commands/printSchema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/graphql-serve/src/commands/printSchema.ts b/packages/graphql-serve/src/commands/printSchema.ts index 028b22177b..b12213032d 100644 --- a/packages/graphql-serve/src/commands/printSchema.ts +++ b/packages/graphql-serve/src/commands/printSchema.ts @@ -1,5 +1,5 @@ import yargs from 'yargs'; -import * as chalk from 'chalk'; +import chalk from 'chalk'; import { printSchemaHandler } from '../components'; type Params = { model?: string }; From 5b1b6f73b9c30628a2b402b1272084c0ec241aca Mon Sep 17 00:00:00 2001 From: Enda Phelan Date: Thu, 24 Sep 2020 09:34:40 +0100 Subject: [PATCH 3/3] refactor: move schemaDefinitions to core --- .../src/SchemaCRUDPlugin.ts | 135 +++++++++--------- .../graphback-codegen-schema/src/index.ts | 1 - .../tests/GraphQLSchemaCreatorTest.ts | 6 +- packages/graphback-core/package.json | 1 + packages/graphback-core/src/crud/index.ts | 1 + .../src/crud}/schemaDefinitions.ts | 62 +++++--- .../src/plugin/GraphbackCoreMetadata.ts | 4 +- .../src/relationships/relationshipHelpers.ts | 2 +- .../src/utils}/copyWrappingType.ts | 2 +- .../graphback-datasync/src/DataSyncPlugin.ts | 34 +++-- 10 files changed, 141 insertions(+), 107 deletions(-) rename packages/{graphback-codegen-schema/src/definitions => graphback-core/src/crud}/schemaDefinitions.ts (83%) rename packages/{graphback-codegen-schema/src/definitions => graphback-core/src/utils}/copyWrappingType.ts (99%) diff --git a/packages/graphback-codegen-schema/src/SchemaCRUDPlugin.ts b/packages/graphback-codegen-schema/src/SchemaCRUDPlugin.ts index b83b01aa19..9fa0a45564 100644 --- a/packages/graphback-codegen-schema/src/SchemaCRUDPlugin.ts +++ b/packages/graphback-codegen-schema/src/SchemaCRUDPlugin.ts @@ -5,10 +5,9 @@ import * as DataLoader from "dataloader"; import { parseMetadata } from "graphql-metadata"; import { SchemaComposer, NamedTypeComposer } from 'graphql-compose'; import { IResolvers, IObjectTypeResolver } from '@graphql-tools/utils'; -import { GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLInt, GraphQLFloat, isScalarType, isSpecifiedScalarType, GraphQLResolveInfo, isObjectType, GraphQLInputObjectType, GraphQLScalarType } from 'graphql'; -import { getFieldName, metadataMap, printSchemaWithDirectives, getSubscriptionName, GraphbackCoreMetadata, GraphbackOperationType, GraphbackPlugin, ModelDefinition, addRelationshipFields, extendRelationshipFields, extendOneToManyFieldArguments, getInputTypeName, FieldRelationshipMetadata, GraphbackContext, getSelectedFieldsFromResolverInfo, isModelType, getPrimaryKey, graphbackScalarsTypes, GraphbackTimestamp, FILTER_SUPPORTED_SCALARS, FindByArgs } from '@graphback/core'; +import { GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLInt, GraphQLFloat, isScalarType, isSpecifiedScalarType, GraphQLResolveInfo, isObjectType, GraphQLInputObjectType, GraphQLScalarType, buildSchema } from 'graphql'; +import { getFieldName, metadataMap, printSchemaWithDirectives, schemaDefinitions, getSubscriptionName, GraphbackCoreMetadata, GraphbackOperationType, GraphbackPlugin, ModelDefinition, addRelationshipFields, extendRelationshipFields, extendOneToManyFieldArguments, getInputTypeName, FieldRelationshipMetadata, GraphbackContext, getSelectedFieldsFromResolverInfo, isModelType, getPrimaryKey, graphbackScalarsTypes, GraphbackTimestamp, FILTER_SUPPORTED_SCALARS, FindByArgs } from '@graphback/core'; import { gqlSchemaFormatter, jsSchemaFormatter, tsSchemaFormatter } from './writer/schemaFormatters'; -import { buildFilterInputType, createModelListResultType, StringScalarInputType, BooleanScalarInputType, SortDirectionEnum, buildCreateMutationInputType, buildFindOneFieldMap, buildMutationInputType, OrderByInputType, buildSubscriptionFilterType, IDScalarInputType, PageRequest, createInputTypeForScalar, createVersionedFields, createVersionedInputFields, addCreateObjectInputType, addUpdateObjectInputType, getInputName } from './definitions/schemaDefinitions'; /** * Configuration for Schema generator CRUD plugin @@ -64,7 +63,7 @@ export class SchemaCRUDPlugin extends GraphbackPlugin { this.buildSchemaForModels(schemaComposer, models); this.addVersionedMetadataFields(schemaComposer, models); - return schemaComposer.buildSchema() + return schemaComposer.buildSchema(); } /** @@ -158,56 +157,57 @@ export class SchemaCRUDPlugin extends GraphbackPlugin { const modelTC = schemaComposer.getOTC(name) const modelType = modelTC.getType() - buildSubscriptionFilterType(schemaComposer, modelType); + if (model.crudOptions.subCreate || model.crudOptions.subUpdate || model.crudOptions.subDelete) { + schemaDefinitions.buildSubscriptionFilterType(schemaComposer, modelType); - const subscriptionFields = {} - if (model.crudOptions.subCreate) { - const operation = getSubscriptionName(name, GraphbackOperationType.CREATE) + const subscriptionFields = {} + if (model.crudOptions.subCreate) { + const operation = getSubscriptionName(name, GraphbackOperationType.CREATE) - const filterInputName = getInputTypeName(name, GraphbackOperationType.SUBSCRIPTION_CREATE) - const subCreateFilterInputType = schemaComposer.getITC(filterInputName).getType() + const filterInputName = getInputTypeName(name, GraphbackOperationType.SUBSCRIPTION_CREATE) + const subCreateFilterInputType = schemaComposer.getITC(filterInputName).getType() - subscriptionFields[operation] = { - type: GraphQLNonNull(modelType), - args: { - filter: { - type: subCreateFilterInputType, - }, - } - }; - } - if (model.crudOptions.subUpdate) { - const operation = getSubscriptionName(name, GraphbackOperationType.UPDATE) + subscriptionFields[operation] = { + type: GraphQLNonNull(modelType), + args: { + filter: { + type: subCreateFilterInputType, + }, + } + }; + } + if (model.crudOptions.subUpdate) { + const operation = getSubscriptionName(name, GraphbackOperationType.UPDATE) - const filterInputName = getInputTypeName(name, GraphbackOperationType.SUBSCRIPTION_UPDATE) - const subUpdateFilterInputType = schemaComposer.getITC(filterInputName).getType() + const filterInputName = getInputTypeName(name, GraphbackOperationType.SUBSCRIPTION_UPDATE) + const subUpdateFilterInputType = schemaComposer.getITC(filterInputName).getType() - subscriptionFields[operation] = { - type: GraphQLNonNull(modelType), - args: { - filter: { - type: subUpdateFilterInputType, - }, - } - }; - } - if (model.crudOptions.subDelete) { - const operation = getSubscriptionName(name, GraphbackOperationType.DELETE) + subscriptionFields[operation] = { + type: GraphQLNonNull(modelType), + args: { + filter: { + type: subUpdateFilterInputType, + }, + } + }; + } + if (model.crudOptions.subDelete) { + const operation = getSubscriptionName(name, GraphbackOperationType.DELETE) - const filterInputName = getInputTypeName(name, GraphbackOperationType.SUBSCRIPTION_DELETE) - const subDeleteFilterInputType = schemaComposer.getITC(filterInputName).getType() + const filterInputName = getInputTypeName(name, GraphbackOperationType.SUBSCRIPTION_DELETE) + const subDeleteFilterInputType = schemaComposer.getITC(filterInputName).getType() - subscriptionFields[operation] = { - type: GraphQLNonNull(modelType), - args: { - filter: { - type: subDeleteFilterInputType, - }, - } - }; + subscriptionFields[operation] = { + type: GraphQLNonNull(modelType), + args: { + filter: { + type: subDeleteFilterInputType, + }, + } + }; + } + schemaComposer.Subscription.addFields(subscriptionFields) } - - schemaComposer.Subscription.addFields(subscriptionFields) } protected createSchema(queryTypes: any, mutationTypes: any, subscriptionTypes: any) { @@ -244,14 +244,13 @@ export class SchemaCRUDPlugin extends GraphbackPlugin { const modelTC = schemaComposer.getOTC(name) const modelType = modelTC.getType() - buildMutationInputType(schemaComposer, modelType) + schemaDefinitions.buildMutationInputType(schemaComposer, modelType) + schemaDefinitions.buildCreateMutationInputType(schemaComposer, modelType) const mutationFields = {} if (model.crudOptions.create) { const operationType = GraphbackOperationType.CREATE - buildCreateMutationInputType(schemaComposer, modelType) - const inputTypeName = getInputTypeName(name, operationType) const createMutationInputType = schemaComposer.getITC(inputTypeName).getType() @@ -306,14 +305,15 @@ export class SchemaCRUDPlugin extends GraphbackPlugin { const modelTC = schemaComposer.getOTC(name) const modelType = modelTC.getType() - buildFilterInputType(schemaComposer, modelType); + schemaDefinitions.buildFilterInputType(schemaComposer, modelType); + const resultListType = schemaDefinitions.createModelListResultType(modelType) const queryFields = {} if (model.crudOptions.findOne) { const operation = getFieldName(name, GraphbackOperationType.FIND_ONE) queryFields[operation] = { type: model.graphqlType, - args: buildFindOneFieldMap(model, schemaComposer) + args: schemaDefinitions.buildFindOneFieldMap(model, schemaComposer) }; } if (model.crudOptions.find) { @@ -322,7 +322,6 @@ export class SchemaCRUDPlugin extends GraphbackPlugin { const inputTypeName = getInputTypeName(name, operationType) const filterInputType = schemaComposer.getITC(inputTypeName).getType() - const resultListType = createModelListResultType(modelType) queryFields[operation] = { type: GraphQLNonNull(resultListType), @@ -331,10 +330,10 @@ export class SchemaCRUDPlugin extends GraphbackPlugin { type: filterInputType }, page: { - type: PageRequest + type: schemaDefinitions.PageRequest }, orderBy: { - type: OrderByInputType + type: schemaDefinitions.OrderByInputType } } }; @@ -344,7 +343,7 @@ export class SchemaCRUDPlugin extends GraphbackPlugin { } protected addVersionedMetadataFields(schemaComposer: SchemaComposer, models: ModelDefinition[]) { - const timeStampInputName = getInputName(GraphbackTimestamp); + const timeStampInputName = schemaDefinitions.getInputName(GraphbackTimestamp); let timestampInputType: GraphQLInputObjectType; let timestampType: GraphQLScalarType; for (const model of models) { const name = model.graphqlType.name; @@ -369,21 +368,21 @@ export class SchemaCRUDPlugin extends GraphbackPlugin { timestampInputType = schemaComposer.getITC(timeStampInputName).getType(); } else { schemaComposer.createScalarTC(GraphbackTimestamp); - timestampInputType = createInputTypeForScalar(GraphbackTimestamp); + timestampInputType = schemaDefinitions.createInputTypeForScalar(GraphbackTimestamp); schemaComposer.add(timestampInputType); } timestampType = schemaComposer.getSTC(GraphbackTimestamp.name).getType(); } - const metadataFields = createVersionedFields(timestampType); + const metadataFields = schemaDefinitions.createVersionedFields(timestampType); // metadata fields needed for @versioned modelTC.addFields(metadataFields); const inputType = schemaComposer.getITC(getInputTypeName(name, GraphbackOperationType.FIND)) if (inputType) { - const metadataInputFields = createVersionedInputFields(timestampInputType); + const metadataInputFields = schemaDefinitions.createVersionedInputFields(timestampInputType); inputType.addFields(metadataInputFields); } } @@ -745,26 +744,26 @@ export class SchemaCRUDPlugin extends GraphbackPlugin { } private createSchemaCRUDTypes(schemaComposer: SchemaComposer) { - schemaComposer.add(PageRequest); - schemaComposer.add(IDScalarInputType); - schemaComposer.add(SortDirectionEnum); - schemaComposer.add(StringScalarInputType); - schemaComposer.add(BooleanScalarInputType); - schemaComposer.add(createInputTypeForScalar(GraphQLInt)); - schemaComposer.add(createInputTypeForScalar(GraphQLFloat)); + schemaComposer.add(schemaDefinitions.PageRequest); + schemaComposer.add(schemaDefinitions.IDScalarInputType); + schemaComposer.add(schemaDefinitions.SortDirectionEnum); + schemaComposer.add(schemaDefinitions.StringScalarInputType); + schemaComposer.add(schemaDefinitions.BooleanScalarInputType); + schemaComposer.add(schemaDefinitions.createInputTypeForScalar(GraphQLInt)); + schemaComposer.add(schemaDefinitions.createInputTypeForScalar(GraphQLFloat)); schemaComposer.forEach((tc: NamedTypeComposer) => { const namedType = tc.getType(); if (isScalarType(namedType) && !isSpecifiedScalarType(namedType) && FILTER_SUPPORTED_SCALARS.includes(namedType.name)) { - schemaComposer.add(createInputTypeForScalar(namedType)); + schemaComposer.add(schemaDefinitions.createInputTypeForScalar(namedType)); return; } const isRootType = ['Query', 'Subscription', 'Mutation'].includes(namedType.name) if (isObjectType(namedType) && !isModelType(namedType) && !isRootType) { - addCreateObjectInputType(schemaComposer, namedType) - addUpdateObjectInputType(schemaComposer, namedType) + schemaDefinitions.addCreateObjectInputType(schemaComposer, namedType) + schemaDefinitions.addUpdateObjectInputType(schemaComposer, namedType) } }); } diff --git a/packages/graphback-codegen-schema/src/index.ts b/packages/graphback-codegen-schema/src/index.ts index d2f2c49475..bf38e63836 100644 --- a/packages/graphback-codegen-schema/src/index.ts +++ b/packages/graphback-codegen-schema/src/index.ts @@ -1,5 +1,4 @@ export * from './SchemaCRUDPlugin' -export * from './definitions/schemaDefinitions' //Required for plugins export { SchemaCRUDPlugin as Plugin } from './SchemaCRUDPlugin' \ No newline at end of file diff --git a/packages/graphback-codegen-schema/tests/GraphQLSchemaCreatorTest.ts b/packages/graphback-codegen-schema/tests/GraphQLSchemaCreatorTest.ts index 4fce14404c..62163f437f 100644 --- a/packages/graphback-codegen-schema/tests/GraphQLSchemaCreatorTest.ts +++ b/packages/graphback-codegen-schema/tests/GraphQLSchemaCreatorTest.ts @@ -449,7 +449,7 @@ test('When all CRUD flags are disabled, resolvers and root schema types are not const resolvers = metadata.getResolvers(); expect(resolvers).toBeUndefined() - expect(schema.getQueryType().getFields()).toEqual({}) - expect(schema.getMutationType()).toBeUndefined() - expect(schema.getSubscriptionType()).toBeUndefined() + expect(schema.getQueryType()).toBeUndefined(); + expect(schema.getMutationType()).toBeUndefined(); + expect(schema.getSubscriptionType()).toBeUndefined(); }) \ No newline at end of file diff --git a/packages/graphback-core/package.json b/packages/graphback-core/package.json index f02590d4dd..7929a7a5ed 100644 --- a/packages/graphback-core/package.json +++ b/packages/graphback-core/package.json @@ -31,6 +31,7 @@ "@types/jest": "26.0.14", "@types/node": "12.12.62", "@types/pino": "6.3.0", + "@types/pluralize": "0.0.29", "graphql": "15.3.0", "jest": "26.4.2", "rimraf": "3.0.2", diff --git a/packages/graphback-core/src/crud/index.ts b/packages/graphback-core/src/crud/index.ts index ad1fe93d23..cc8e967c37 100644 --- a/packages/graphback-core/src/crud/index.ts +++ b/packages/graphback-core/src/crud/index.ts @@ -1,2 +1,3 @@ export * from "./mappingHelpers" export * from "./GraphbackOperationType" +export { schemaDefinitions } from './schemaDefinitions' diff --git a/packages/graphback-codegen-schema/src/definitions/schemaDefinitions.ts b/packages/graphback-core/src/crud/schemaDefinitions.ts similarity index 83% rename from packages/graphback-codegen-schema/src/definitions/schemaDefinitions.ts rename to packages/graphback-core/src/crud/schemaDefinitions.ts index 6d0fc8a1e3..719bbcefc0 100644 --- a/packages/graphback-codegen-schema/src/definitions/schemaDefinitions.ts +++ b/packages/graphback-core/src/crud/schemaDefinitions.ts @@ -1,14 +1,14 @@ /* eslint-disable max-lines */ import { GraphQLInputObjectType, GraphQLList, GraphQLBoolean, GraphQLInt, GraphQLString, GraphQLID, GraphQLEnumType, GraphQLObjectType, GraphQLNonNull, GraphQLField, getNamedType, isScalarType, GraphQLInputFieldMap, GraphQLScalarType, GraphQLNamedType, GraphQLInputField, isEnumType, isObjectType, isInputObjectType, GraphQLInputType, getNullableType } from "graphql"; -import { GraphbackOperationType, getInputTypeName, getInputFieldName, getInputFieldTypeName, isOneToManyField, getPrimaryKey, metadataMap, ModelDefinition, FILTER_SUPPORTED_SCALARS, isTransientField } from '@graphback/core'; import { SchemaComposer } from 'graphql-compose'; -import { copyWrappingType } from './copyWrappingType'; +import { GraphbackOperationType, getInputTypeName, getInputFieldName, getInputFieldTypeName, isOneToManyField, getPrimaryKey, metadataMap, ModelDefinition, FILTER_SUPPORTED_SCALARS, isTransientField } from '../../src'; +import { copyWrappingType } from '../utils/copyWrappingType'; const PageRequestTypeName = 'PageRequest'; const SortDirectionEnumName = 'SortDirectionEnum'; const OrderByInputTypeName = 'OrderByInput'; -export const getInputName = (type: GraphQLNamedType) => { +const getInputName = (type: GraphQLNamedType) => { if (isEnumType(type)) { return `StringInput` } @@ -20,7 +20,7 @@ export const getInputName = (type: GraphQLNamedType) => { return `${type.name}Input` } -export const createInputTypeForScalar = (scalarType: GraphQLScalarType) => { +const createInputTypeForScalar = (scalarType: GraphQLScalarType) => { const newInput = new GraphQLInputObjectType({ name: getInputName(scalarType), fields: { @@ -38,7 +38,7 @@ export const createInputTypeForScalar = (scalarType: GraphQLScalarType) => { return newInput; } -export const StringScalarInputType = new GraphQLInputObjectType({ +const StringScalarInputType = new GraphQLInputObjectType({ name: getInputName(GraphQLString), fields: { ne: { type: GraphQLString }, @@ -54,7 +54,7 @@ export const StringScalarInputType = new GraphQLInputObjectType({ } }) -export const IDScalarInputType = new GraphQLInputObjectType({ +const IDScalarInputType = new GraphQLInputObjectType({ name: getInputName(GraphQLID), fields: { ne: { type: GraphQLID }, @@ -65,9 +65,9 @@ export const IDScalarInputType = new GraphQLInputObjectType({ gt: { type: GraphQLID }, in: { type: GraphQLList(GraphQLNonNull(GraphQLID)) }, } -}) +}); -export const BooleanScalarInputType = new GraphQLInputObjectType({ +const BooleanScalarInputType = new GraphQLInputObjectType({ name: getInputName(GraphQLBoolean), fields: { ne: { type: GraphQLBoolean }, @@ -75,7 +75,7 @@ export const BooleanScalarInputType = new GraphQLInputObjectType({ } }) -export const PageRequest = new GraphQLInputObjectType({ +const PageRequest = new GraphQLInputObjectType({ name: PageRequestTypeName, fields: { limit: { @@ -87,7 +87,7 @@ export const PageRequest = new GraphQLInputObjectType({ } }) -export const SortDirectionEnum = new GraphQLEnumType({ +const SortDirectionEnum = new GraphQLEnumType({ name: SortDirectionEnumName, values: { DESC: { value: 'desc' }, @@ -95,7 +95,7 @@ export const SortDirectionEnum = new GraphQLEnumType({ } }) -export const OrderByInputType = new GraphQLInputObjectType({ +const OrderByInputType = new GraphQLInputObjectType({ name: OrderByInputTypeName, fields: { field: { type: GraphQLNonNull(GraphQLString) }, @@ -135,7 +135,7 @@ function getModelInputFields(schemaComposer: SchemaComposer, modelType: Gra return inputFields; } -export function buildFindOneFieldMap(modelType: ModelDefinition, schemaComposer: SchemaComposer): GraphQLInputFieldMap { +function buildFindOneFieldMap(modelType: ModelDefinition, schemaComposer: SchemaComposer): GraphQLInputFieldMap { const { type } = modelType.primaryKey; return { @@ -148,7 +148,7 @@ export function buildFindOneFieldMap(modelType: ModelDefinition, schemaComposer: } } -export const buildFilterInputType = (schemaComposer: SchemaComposer, modelType: GraphQLObjectType) => { +const buildFilterInputType = (schemaComposer: SchemaComposer, modelType: GraphQLObjectType) => { const operationType = GraphbackOperationType.FIND const inputTypeName = getInputTypeName(modelType.name, operationType); @@ -188,7 +188,7 @@ export const buildFilterInputType = (schemaComposer: SchemaComposer, modelT schemaComposer.add(filterInput) } -export const buildCreateMutationInputType = (schemaComposer: SchemaComposer, modelType: GraphQLObjectType) => { +const buildCreateMutationInputType = (schemaComposer: SchemaComposer, modelType: GraphQLObjectType) => { const operationType = GraphbackOperationType.CREATE const inputTypeName = getInputTypeName(modelType.name, operationType); @@ -219,7 +219,7 @@ export const buildCreateMutationInputType = (schemaComposer: SchemaComposer schemaComposer.add(mutationInputType) } -export const buildSubscriptionFilterType = (schemaComposer: SchemaComposer, modelType: GraphQLObjectType) => { +const buildSubscriptionFilterType = (schemaComposer: SchemaComposer, modelType: GraphQLObjectType) => { const inputTypeName = getInputTypeName(modelType.name, GraphbackOperationType.SUBSCRIPTION_CREATE); const modelFields = Object.values(modelType.getFields()); const subscriptionFilterFields = modelFields.filter((f: GraphQLField) => { @@ -255,7 +255,7 @@ export const buildSubscriptionFilterType = (schemaComposer: SchemaComposer, }) } -export const buildMutationInputType = (schemaComposer: SchemaComposer, modelType: GraphQLObjectType) => { +const buildMutationInputType = (schemaComposer: SchemaComposer, modelType: GraphQLObjectType) => { const operationType = GraphbackOperationType.UPDATE const inputTypeName = getInputTypeName(modelType.name, operationType); @@ -307,7 +307,7 @@ function mapObjectInputFields(schemaComposer: SchemaComposer, fields: Graph }) } -export function addCreateObjectInputType(schemaComposer: SchemaComposer, objectType: GraphQLObjectType) { +function addCreateObjectInputType(schemaComposer: SchemaComposer, objectType: GraphQLObjectType) { const objectFields = Object.values(objectType.getFields()) const operationType = GraphbackOperationType.CREATE @@ -324,7 +324,7 @@ export function addCreateObjectInputType(schemaComposer: SchemaComposer, ob schemaComposer.add(inputType) } -export function addUpdateObjectInputType(schemaComposer: SchemaComposer, objectType: GraphQLObjectType) { +function addUpdateObjectInputType(schemaComposer: SchemaComposer, objectType: GraphQLObjectType) { const objectFields = Object.values(objectType.getFields()) const operationType = GraphbackOperationType.UPDATE @@ -341,7 +341,7 @@ export function addUpdateObjectInputType(schemaComposer: SchemaComposer, ob schemaComposer.add(inputType) } -export const createModelListResultType = (modelType: GraphQLObjectType) => { +const createModelListResultType = (modelType: GraphQLObjectType) => { return new GraphQLObjectType({ name: `${modelType.name}ResultList`, fields: { @@ -355,7 +355,7 @@ export const createModelListResultType = (modelType: GraphQLObjectType) => { }) } -export function createVersionedInputFields(versionedInputType: GraphQLInputObjectType) { +function createVersionedInputFields(versionedInputType: GraphQLInputObjectType) { return { [metadataMap.fieldNames.createdAt]: { type: versionedInputType @@ -366,7 +366,7 @@ export function createVersionedInputFields(versionedInputType: GraphQLInputObjec }; } -export function createVersionedFields(type: GraphQLScalarType) { +function createVersionedFields(type: GraphQLScalarType) { return { [metadataMap.fieldNames.createdAt]: { type, @@ -379,3 +379,23 @@ export function createVersionedFields(type: GraphQLScalarType) { }; } +export const schemaDefinitions = Object.freeze({ + StringScalarInputType, + IDScalarInputType, + BooleanScalarInputType, + PageRequest, + SortDirectionEnum, + OrderByInputType, + getInputName, + createInputTypeForScalar, + buildFindOneFieldMap, + buildFilterInputType, + buildCreateMutationInputType, + buildSubscriptionFilterType, + buildMutationInputType, + addCreateObjectInputType, + addUpdateObjectInputType, + createModelListResultType, + createVersionedInputFields, + createVersionedFields +}); \ No newline at end of file diff --git a/packages/graphback-core/src/plugin/GraphbackCoreMetadata.ts b/packages/graphback-core/src/plugin/GraphbackCoreMetadata.ts index 51ca13ee1c..1a5442d633 100644 --- a/packages/graphback-core/src/plugin/GraphbackCoreMetadata.ts +++ b/packages/graphback-core/src/plugin/GraphbackCoreMetadata.ts @@ -1,7 +1,7 @@ import { parseMetadata } from 'graphql-metadata'; import { mergeResolvers } from '@graphql-tools/merge'; import { GraphQLObjectType, GraphQLSchema, getNamedType } from 'graphql'; -import { getUserTypesFromSchema, IResolvers } from '@graphql-tools/utils'; +import { getUserTypesFromSchema, IResolvers, pruneSchema } from '@graphql-tools/utils'; import { getPrimaryKey } from '../db'; import { RelationshipMetadataBuilder, FieldRelationshipMetadata } from '../relationships/RelationshipMetadataBuilder'; import { isTransientField } from '../utils/isTransientField'; @@ -40,7 +40,7 @@ export class GraphbackCoreMetadata { } public setSchema(newSchema: GraphQLSchema) { - this.schema = newSchema; + this.schema = pruneSchema(newSchema); } public addResolvers(resolvers: IResolvers) { diff --git a/packages/graphback-core/src/relationships/relationshipHelpers.ts b/packages/graphback-core/src/relationships/relationshipHelpers.ts index 3b7ee8cdc9..25e781020a 100644 --- a/packages/graphback-core/src/relationships/relationshipHelpers.ts +++ b/packages/graphback-core/src/relationships/relationshipHelpers.ts @@ -10,7 +10,7 @@ import { RelationshipAnnotation } from './RelationshipMetadataBuilder'; * * @param description field description */ -export function parseRelationshipAnnotation(description: string = ''): RelationshipAnnotation | undefined { +export function parseRelationshipAnnotation(description: string | undefined | null): RelationshipAnnotation | undefined { const relationshipKinds = ['oneToMany', 'oneToOne', 'manyToOne']; for (const kind of relationshipKinds) { diff --git a/packages/graphback-codegen-schema/src/definitions/copyWrappingType.ts b/packages/graphback-core/src/utils/copyWrappingType.ts similarity index 99% rename from packages/graphback-codegen-schema/src/definitions/copyWrappingType.ts rename to packages/graphback-core/src/utils/copyWrappingType.ts index aaa88648ee..201db732ff 100644 --- a/packages/graphback-codegen-schema/src/definitions/copyWrappingType.ts +++ b/packages/graphback-core/src/utils/copyWrappingType.ts @@ -33,4 +33,4 @@ export function copyWrappingType(copyFromType: InputOrOutTypeType, copyToType: I } return namedNewType -} +} \ No newline at end of file diff --git a/packages/graphback-datasync/src/DataSyncPlugin.ts b/packages/graphback-datasync/src/DataSyncPlugin.ts index 7c8acc8e9b..a9e365fb45 100644 --- a/packages/graphback-datasync/src/DataSyncPlugin.ts +++ b/packages/graphback-datasync/src/DataSyncPlugin.ts @@ -1,7 +1,7 @@ import { SchemaComposer } from 'graphql-compose'; import { IResolvers, IFieldResolver } from '@graphql-tools/utils'; import { GraphQLNonNull, GraphQLSchema, buildSchema, GraphQLResolveInfo, GraphQLInt, GraphQLBoolean, GraphQLList, GraphQLObjectType, GraphQLField } from 'graphql'; -import { GraphbackCoreMetadata, GraphbackPlugin, ModelDefinition, getInputTypeName, GraphbackOperationType, parseRelationshipAnnotation, GraphbackContext, GraphbackTimestamp } from '@graphback/core'; +import { GraphbackCoreMetadata, GraphbackPlugin, ModelDefinition, getInputTypeName, GraphbackOperationType, parseRelationshipAnnotation, GraphbackContext, GraphbackTimestamp, schemaDefinitions } from '@graphback/core'; import { getDeltaType, getDeltaListType, getDeltaQuery } from "./deltaMappingHelper"; import { isDataSyncService, isDataSyncModel, DataSyncFieldNames, GlobalConflictConfig, getModelConfigFromGlobal } from "./util"; @@ -76,18 +76,18 @@ export class DataSyncPlugin extends GraphbackPlugin { * @param {GraphbackCoreMetadata} metadata - Core metatata containing all model information */ public createResolvers(metadata: GraphbackCoreMetadata): IResolvers { - const resolvers: IResolvers = { - Query: {}, - Mutation: {}, - Subscription: {} + const models = metadata.getModelDefinitions() + + if (models.length === 0) { + return undefined; } - const models = metadata.getModelDefinitions() + const resolvers: IResolvers = {} for (const model of models) { // If delta marker is encountered, add resolver for `delta` query if (isDataSyncModel(model)) { - this.addDeltaSyncResolver(model, resolvers.Query as IFieldResolver) + this.addDeltaSyncResolver(model, resolvers) } } @@ -105,11 +105,15 @@ export class DataSyncPlugin extends GraphbackPlugin { return DATASYNC_PLUGIN_NAME; } - protected addDeltaSyncResolver(model: ModelDefinition, queryObj: IFieldResolver) { + protected addDeltaSyncResolver(model: ModelDefinition, resolvers: IResolvers) { const modelName = model.graphqlType.name; const deltaQuery = getDeltaQuery(modelName) - queryObj[deltaQuery] = async (_: any, args: any, context: GraphbackContext, info: GraphQLResolveInfo) => { + if (!resolvers.Query) { + resolvers.Query = {} as IFieldResolver + } + + resolvers.Query[deltaQuery] = async (_: any, args: any, context: GraphbackContext, info: GraphQLResolveInfo) => { if (!context.graphback || !context.graphback[modelName]) { throw new Error(`Missing service for ${modelName}`); } @@ -145,9 +149,13 @@ export class DataSyncPlugin extends GraphbackPlugin { } protected addDataSyncFieldsToInputTypes(schemaComposer: SchemaComposer, model: ModelDefinition) { + const modelUpdateInputName = getInputTypeName(model.graphqlType.name, GraphbackOperationType.UPDATE); + if (!schemaComposer.has(modelUpdateInputName)) { + schemaDefinitions.buildMutationInputType(schemaComposer, model.graphqlType); + } // Add _version argument to UpdateInputType - const updateInputType = schemaComposer.getITC(getInputTypeName(model.graphqlType.name, GraphbackOperationType.UPDATE)); + const updateInputType = schemaComposer.getITC(modelUpdateInputName); const modelUsesVersion = getModelConfigFromGlobal(model.graphqlType.name, this.config.conflictConfig).enabled; if (modelUsesVersion && updateInputType) { updateInputType.addFields({ @@ -193,6 +201,12 @@ export class DataSyncPlugin extends GraphbackPlugin { [deltaQuery]: GraphQLNonNull(DeltaListOTC.getType()) }); + const modelFilterName = getInputTypeName(modelName, GraphbackOperationType.FIND); + + if (!schemaComposer.has(modelFilterName)) { + schemaDefinitions.buildFilterInputType(schemaComposer, model.graphqlType); + } + const findFilterITC = schemaComposer.getITC(getInputTypeName(modelName, GraphbackOperationType.FIND)); schemaComposer.Query.addFieldArgs(deltaQuery, { lastSync: GraphQLNonNull(TimestampSTC.getType()),