Skip to content

Commit

Permalink
Upgrade to graphql@16 (#7817)
Browse files Browse the repository at this point in the history
* Upgrade to graphql@16

* add changeset

Co-authored-by: Daniel Cousens <dcousens@users.noreply.github.com>
  • Loading branch information
emmatown and dcousens committed Aug 31, 2022
1 parent 6c09093 commit 0530069
Show file tree
Hide file tree
Showing 20 changed files with 114 additions and 84 deletions.
5 changes: 5 additions & 0 deletions .changeset/go-go-graphql.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@keystone-6/core': major
---

Upgrade to `graphql@16`
2 changes: 1 addition & 1 deletion .changeset/great-sloths-bake.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
'@keystone-6/core': major
---

Updates Prisma to 4.2.1
Upgrade to `prisma@4`
2 changes: 1 addition & 1 deletion changelog.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const { default: getReleasePlan } = require('@changesets/get-release-plan');
const { getInfo } = require('@changesets/get-github-info');

// TODO: move this to CI linting
const verbs = new Set(['Adds', 'Changes', 'Fixes', 'Moves', 'Removes', 'Updates']);
const verbs = new Set(['Adds', 'Changes', 'Fixes', 'Moves', 'Removes', 'Updates', 'Upgrade']);

// TODO: derived?
const publicPackages = [
Expand Down
2 changes: 1 addition & 1 deletion examples/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@keystone-ui/icons": "^6.0.1",
"@keystone-ui/tooltip": "^6.0.1",
"@types/react": "^18.0.9",
"graphql": "^15.8.0",
"graphql": "^16.6.0",
"graphql-tag": "^2.12.6",
"react": "^18.1.0",
"react-dom": "^18.1.0",
Expand Down
4 changes: 2 additions & 2 deletions examples/extend-graphql-schema-nexus/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"dependencies": {
"@graphql-tools/schema": "^8.3.1",
"@keystone-6/core": "^2.2.0",
"graphql": "^15.8.0",
"nexus": "1.1.0"
"graphql": "^16.6.0",
"nexus": "1.3.0"
},
"repository": "https://github.com/keystonejs/keystone/tree/main/examples/extend-graphql-schema-nexus"
}
2 changes: 1 addition & 1 deletion examples/extend-graphql-subscriptions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@keystone-ui/core": "^5.0.1",
"@keystone-ui/fields": "^7.1.1",
"@types/ws": "^8.5.3",
"graphql": "^15.8.0",
"graphql": "^16.6.0",
"graphql-subscriptions": "^2.0.0",
"graphql-ws": "^5.9.1",
"react": "^18.1.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@keystone-ui/notice": "^6.0.1",
"cross-fetch": "^3.1.4",
"fast-deep-equal": "^3.1.3",
"graphql": "^15.8.0"
"graphql": "^16.6.0"
},
"devDependencies": {
"@keystone-6/core": "^2.2.0",
Expand Down
3 changes: 1 addition & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@
"filenamify": "^4.3.0",
"form-data": "4.0.0",
"fs-extra": "^10.0.0",
"graphql": "^15.8.0",
"graphql-type-json": "^0.3.2",
"graphql": "^16.6.0",
"graphql-upload": "^15.0.2",
"image-size": "^1.0.0",
"image-type": "^4.1.0",
Expand Down
23 changes: 14 additions & 9 deletions packages/core/src/admin-ui/templates/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
parse,
FragmentDefinitionNode,
SelectionNode,
ExecutionResult,
Kind,
} from 'graphql';
import { AdminMetaRootVal } from '../../types';
import { staticAdminMetaQuery, StaticAdminMetaQuery } from '../admin-meta-graphql';
Expand All @@ -24,7 +26,7 @@ export const appTemplate = (
document: staticAdminMetaQuery,
schema: graphQLSchema,
contextValue: { isAdminUIBuildProcess: true },
});
}) as ExecutionResult<StaticAdminMetaQuery>;
if (result.errors) {
throw result.errors[0];
}
Expand Down Expand Up @@ -136,18 +138,21 @@ function getLazyMetadataQuery(
}

selections.push({
kind: 'Field',
name: { kind: 'Name', value: 'authenticatedItem' },
kind: Kind.FIELD,
name: { kind: Kind.NAME, value: 'authenticatedItem' },
selectionSet: {
kind: 'SelectionSet',
kind: Kind.SELECTION_SET,
selections: authenticatedItemType.getTypes().map(({ name }) => ({
kind: 'InlineFragment',
typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: name } },
kind: Kind.INLINE_FRAGMENT,
typeCondition: { kind: Kind.NAMED_TYPE, name: { kind: Kind.NAME, value: name } },
selectionSet: {
kind: 'SelectionSet',
kind: Kind.SELECTION_SET,
selections: [
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
{ kind: 'Field', name: { kind: 'Name', value: getListByKey(name)!.labelField } },
{ kind: Kind.FIELD, name: { kind: Kind.NAME, value: 'id' } },
{
kind: Kind.FIELD,
name: { kind: Kind.NAME, value: getListByKey(name)!.labelField },
},
],
},
})),
Expand Down
12 changes: 9 additions & 3 deletions packages/core/src/lib/coerceAndValidateForGraphQLInput.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { GraphQLSchema, VariableDefinitionNode, GraphQLInputType, GraphQLError } from 'graphql';
import {
GraphQLSchema,
VariableDefinitionNode,
GraphQLInputType,
GraphQLError,
Kind,
} from 'graphql';
import { getVariableValues } from 'graphql/execution/values';
import { getTypeNodeForType } from './context/executeGraphQLFieldToRootVal';

Expand All @@ -11,9 +17,9 @@ export function coerceAndValidateForGraphQLInput(
): { kind: 'valid'; value: any } | { kind: 'error'; error: GraphQLError } {
const variableDefintions: VariableDefinitionNode[] = [
{
kind: 'VariableDefinition',
kind: Kind.VARIABLE_DEFINITION,
type: getTypeNodeForType(type),
variable: { kind: 'Variable', name: { kind: 'Name', value: argName } },
variable: { kind: Kind.VARIABLE, name: { kind: Kind.NAME, value: argName } },
},
];

Expand Down
53 changes: 29 additions & 24 deletions packages/core/src/lib/context/executeGraphQLFieldToRootVal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import {
GraphQLFieldConfig,
GraphQLOutputType,
astFromValue,
Kind,
OperationTypeNode,
ConstValueNode,
} from 'graphql';
import { KeystoneContext } from '../../types';

Expand All @@ -37,33 +40,35 @@ function getNamedOrListTypeNodeForType(
| GraphQLList<any>
): NamedTypeNode | ListTypeNode {
if (type instanceof GraphQLList) {
return { kind: 'ListType', type: getTypeNodeForType(type.ofType) };
return { kind: Kind.LIST_TYPE, type: getTypeNodeForType(type.ofType) };
}
return { kind: 'NamedType', name: { kind: 'Name', value: type.name } };
return { kind: Kind.NAMED_TYPE, name: { kind: Kind.NAME, value: type.name } };
}

export function getTypeNodeForType(type: GraphQLType): TypeNode {
if (type instanceof GraphQLNonNull) {
return { kind: 'NonNullType', type: getNamedOrListTypeNodeForType(type.ofType) };
return { kind: Kind.NON_NULL_TYPE, type: getNamedOrListTypeNodeForType(type.ofType) };
}
return getNamedOrListTypeNodeForType(type);
}

export function getVariablesForGraphQLField(field: GraphQLField<any, any>) {
const variableDefinitions: VariableDefinitionNode[] = field.args.map(arg => ({
kind: 'VariableDefinition',
type: getTypeNodeForType(arg.type),
variable: { kind: 'Variable', name: { kind: 'Name', value: arg.name } },
defaultValue:
arg.defaultValue === undefined
? undefined
: astFromValue(arg.defaultValue, arg.type) ?? undefined,
}));
const variableDefinitions: VariableDefinitionNode[] = field.args.map(
(arg): VariableDefinitionNode => ({
kind: Kind.VARIABLE_DEFINITION,
type: getTypeNodeForType(arg.type),
variable: { kind: Kind.VARIABLE, name: { kind: Kind.NAME, value: arg.name } },
defaultValue:
arg.defaultValue === undefined
? undefined
: (astFromValue(arg.defaultValue, arg.type) as ConstValueNode) ?? undefined,
})
);

const argumentNodes: ArgumentNode[] = field.args.map(arg => ({
kind: 'Argument',
name: { kind: 'Name', value: arg.name },
value: { kind: 'Variable', name: { kind: 'Name', value: arg.name } },
kind: Kind.ARGUMENT,
name: { kind: Kind.NAME, value: arg.name },
value: { kind: Kind.VARIABLE, name: { kind: Kind.NAME, value: arg.name } },
}));

return { variableDefinitions, argumentNodes };
Expand Down Expand Up @@ -97,7 +102,7 @@ type RequiredButStillAllowUndefined<
[K in Key]: T[K];
};

function argsToArgsConfig(args: GraphQLArgument[]) {
function argsToArgsConfig(args: readonly GraphQLArgument[]) {
return Object.fromEntries(
args.map(arg => {
const argConfig: RequiredButStillAllowUndefined<GraphQLArgumentConfig> = {
Expand Down Expand Up @@ -144,21 +149,21 @@ function getRootValGivenOutputType(originalType: OutputType, value: any): any {
export function executeGraphQLFieldToRootVal(field: GraphQLField<any, any>) {
const { argumentNodes, variableDefinitions } = getVariablesForGraphQLField(field);
const document: DocumentNode = {
kind: 'Document',
kind: Kind.DOCUMENT,
definitions: [
{
kind: 'OperationDefinition',
operation: 'query',
kind: Kind.OPERATION_DEFINITION,
operation: OperationTypeNode.QUERY,
selectionSet: {
kind: 'SelectionSet',
kind: Kind.SELECTION_SET,
selections: [
{
kind: 'Field',
name: { kind: 'Name', value: field.name },
kind: Kind.FIELD,
name: { kind: Kind.NAME, value: field.name },
arguments: argumentNodes,
selectionSet: {
kind: 'SelectionSet',
selections: [{ kind: 'Field', name: { kind: 'Name', value: rawField } }],
kind: Kind.SELECTION_SET,
selections: [{ kind: Kind.FIELD, name: { kind: Kind.NAME, value: rawField } }],
},
},
],
Expand Down
20 changes: 12 additions & 8 deletions packages/core/src/lib/context/executeGraphQLFieldWithSelection.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import {
DocumentNode,
execute,
FragmentDefinitionNode,
GraphQLList,
GraphQLNonNull,
GraphQLOutputType,
GraphQLSchema,
Kind,
OperationTypeNode,
parse,
validate,
} from 'graphql';
Expand Down Expand Up @@ -42,18 +45,19 @@ export function executeGraphQLFieldWithSelection(
parse(`fragment x on ${rootName} {${query}}`).definitions[0] as FragmentDefinitionNode
).selectionSet;

const document = {
kind: 'Document',
const document: DocumentNode = {
kind: Kind.DOCUMENT,
definitions: [
{
kind: 'OperationDefinition',
operation,
kind: Kind.OPERATION_DEFINITION,
// OperationTypeNode is an ts enum where the values are 'query' | 'mutation' | 'subscription'
operation: operation as OperationTypeNode,
selectionSet: {
kind: 'SelectionSet',
kind: Kind.SELECTION_SET,
selections: [
{
kind: 'Field',
name: { kind: 'Name', value: field.name },
kind: Kind.FIELD,
name: { kind: Kind.NAME, value: field.name },
arguments: argumentNodes,
selectionSet: selectionSet,
},
Expand All @@ -62,7 +66,7 @@ export function executeGraphQLFieldWithSelection(
variableDefinitions,
},
],
} as const;
};

const validationErrors = validate(schema, document);

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/lib/context/itemAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export function itemAPIForList(
const exec = executeGraphQLFieldWithSelection(context.graphql.schema, operation, field);
return ({ query, ...args }: { query?: string } & Record<string, any> = {}) => {
const returnFields = query ?? 'id';
return exec(args, returnFields, context);
return exec(args, returnFields, context) as any;
};
};
const gqlNames = context.gqlNames(listKey);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/types/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export type KeystoneDbAPI<KeystoneListsTypeInfo extends Record<string, BaseListT
export type KeystoneGraphQLAPI = {
schema: GraphQLSchema;
run: (args: GraphQLExecutionArguments) => Promise<Record<string, any>>;
raw: (args: GraphQLExecutionArguments) => Promise<ExecutionResult>;
raw: (args: GraphQLExecutionArguments) => Promise<ExecutionResult<Record<string, any>>>;
};

type GraphQLExecutionArguments = {
Expand Down
27 changes: 19 additions & 8 deletions packages/core/src/types/schema/graphql-ts-schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { ReadStream } from 'fs';
import * as graphqlTsSchema from '@graphql-ts/schema';
import { GraphQLJSON } from 'graphql-type-json';
// @ts-ignore
import GraphQLUpload from 'graphql-upload/GraphQLUpload.js';
import { GraphQLError, GraphQLScalarType } from 'graphql';
Expand Down Expand Up @@ -43,7 +42,15 @@ export { field, fields, interface, interfaceField, object, union } from './schem

export type Context = KeystoneContext;

export const JSON = graphqlTsSchema.graphql.scalar<JSONValue>(GraphQLJSON);
export const JSON = graphqlTsSchema.graphql.scalar<JSONValue>(
new GraphQLScalarType({
name: 'JSON',
description:
'The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).',
specifiedByURL: 'http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf',
// the defaults for serialize, parseValue and parseLiteral do what makes sense for JSON
})
);

type FileUpload = {
filename: string;
Expand All @@ -61,12 +68,13 @@ export const Upload = graphqlTsSchema.graphql.scalar<Promise<FileUpload>>(GraphQ
export const Decimal = graphqlTsSchema.graphql.scalar<DecimalValue & { scaleToPrint?: number }>(
new GraphQLScalarType({
name: 'Decimal',
serialize(value: DecimalValue & { scaleToPrint?: number }) {
serialize(value) {
if (!DecimalValue.isDecimal(value)) {
throw new GraphQLError(`unexpected value provided to Decimal scalar: ${value}`);
}
if (value.scaleToPrint !== undefined) {
return value.toFixed(value.scaleToPrint);
const cast = value as DecimalValue & { scaleToPrint?: number };
if (cast.scaleToPrint !== undefined) {
return value.toFixed(cast.scaleToPrint);
}
return value.toString();
},
Expand Down Expand Up @@ -102,7 +110,10 @@ export const Decimal = graphqlTsSchema.graphql.scalar<DecimalValue & { scaleToPr
export const BigInt = graphqlTsSchema.graphql.scalar<bigint>(
new GraphQLScalarType({
name: 'BigInt',
serialize(value: bigint) {
serialize(value) {
if (typeof value !== 'bigint') {
throw new GraphQLError(`unexpected value provided to BigInt scalar: ${value}`);
}
return value.toString();
},
parseLiteral(value) {
Expand Down Expand Up @@ -146,7 +157,7 @@ function parseDate(input: string): Date {
export const DateTime = graphqlTsSchema.graphql.scalar<Date>(
new GraphQLScalarType({
name: 'DateTime',
specifiedByUrl: 'https://datatracker.ietf.org/doc/html/rfc3339#section-5.6',
specifiedByURL: 'https://datatracker.ietf.org/doc/html/rfc3339#section-5.6',
serialize(value: unknown) {
if (!(value instanceof Date) || isNaN(value.valueOf())) {
throw new GraphQLError(`unexpected value provided to DateTime scalar: ${value}`);
Expand Down Expand Up @@ -184,7 +195,7 @@ function validateCalendarDay(input: string) {
export const CalendarDay = graphqlTsSchema.graphql.scalar<string>(
new GraphQLScalarType({
name: 'CalendarDay',
specifiedByUrl: 'https://datatracker.ietf.org/doc/html/rfc3339#section-5.6',
specifiedByURL: 'https://datatracker.ietf.org/doc/html/rfc3339#section-5.6',
serialize(value: unknown) {
if (typeof value !== 'string') {
throw new GraphQLError(`unexpected value provided to CalendarDay scalar: ${value}`);
Expand Down
2 changes: 1 addition & 1 deletion packages/fields-document/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"apollo-server-errors": "^3.3.0",
"apply-ref": "^1.0.0",
"fp-ts": "^2.11.5",
"graphql": "^15.8.0",
"graphql": "^16.6.0",
"io-ts": "^2.2.16",
"io-ts-excess": "^1.0.1",
"is-hotkey": "^0.2.0",
Expand Down

0 comments on commit 0530069

Please sign in to comment.