add types for most of graphql
This commit is contained in:
@@ -2,9 +2,11 @@ import { Express } from 'express';
|
||||
import { DeepRequired } from 'ts-essentials';
|
||||
import { Transporter } from 'nodemailer';
|
||||
import SMTPConnection from 'nodemailer/lib/smtp-connection';
|
||||
import { GraphQLType } from 'graphql';
|
||||
import { Collection } from '../collections/config/types';
|
||||
import { Global } from '../globals/config/types';
|
||||
import { PayloadRequest } from '../express/types/payloadRequest';
|
||||
import InitializeGraphQL from '../graphql';
|
||||
|
||||
type MockEmailTransport = {
|
||||
transport?: 'mock';
|
||||
@@ -97,10 +99,10 @@ export type PayloadConfig = {
|
||||
graphQL?: {
|
||||
mutations?: {
|
||||
[key: string]: unknown
|
||||
},
|
||||
} | ((graphQL: GraphQLType, payload: InitializeGraphQL) => any),
|
||||
queries?: {
|
||||
[key: string]: unknown
|
||||
},
|
||||
} | ((graphQL: GraphQLType, payload: InitializeGraphQL) => any),
|
||||
maxComplexity?: number;
|
||||
disablePlaygroundInProduction?: boolean;
|
||||
};
|
||||
|
||||
@@ -83,19 +83,19 @@ export type SelectManyField = SelectField & {
|
||||
hasMany: true;
|
||||
}
|
||||
|
||||
type RelationShipSingleField = FieldBase & {
|
||||
export type RelationshipSingleField = FieldBase & {
|
||||
type: 'relationship';
|
||||
relationTo: string;
|
||||
hasMany?: false;
|
||||
}
|
||||
|
||||
type RelationShipManyField = FieldBase & {
|
||||
export type RelationshipManyField = FieldBase & {
|
||||
type: 'relationship';
|
||||
relationTo: string[] | string;
|
||||
relationTo: string[];
|
||||
hasMany: true;
|
||||
}
|
||||
|
||||
export type RelationshipField = RelationShipSingleField | RelationShipManyField;
|
||||
export type RelationshipField = RelationshipSingleField | RelationshipManyField;
|
||||
|
||||
type RichTextElements = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'blockquote' | 'ul' | 'ol' | 'link';
|
||||
type RichTextLeaves = 'bold' | 'italic' | 'underline' | 'strikethrough';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import executeAccess from '../auth/executeAccess';
|
||||
import { OperationArguments } from '../types';
|
||||
import { RelationshipField } from './config/types';
|
||||
|
||||
const populate = async ({
|
||||
depth,
|
||||
@@ -15,7 +16,8 @@ const populate = async ({
|
||||
}: OperationArguments) => {
|
||||
const dataToUpdate = dataReference;
|
||||
|
||||
const relation = Array.isArray(field.relationTo) ? data.relationTo : field.relationTo;
|
||||
const fieldAsRelationship = field as RelationshipField;
|
||||
const relation = Array.isArray(fieldAsRelationship.relationTo) ? data.relationTo : fieldAsRelationship.relationTo;
|
||||
const relatedCollection = payload.collections[relation];
|
||||
|
||||
if (relatedCollection) {
|
||||
@@ -24,7 +26,7 @@ const populate = async ({
|
||||
let populatedRelationship = null;
|
||||
|
||||
if (accessResult && (depth && currentDepth <= depth)) {
|
||||
let idString = Array.isArray(field.relationTo) ? data.value : data;
|
||||
let idString = Array.isArray(fieldAsRelationship.relationTo) ? data.value : data;
|
||||
|
||||
if (typeof idString !== 'string') {
|
||||
idString = idString.toString();
|
||||
@@ -45,12 +47,12 @@ const populate = async ({
|
||||
// If populatedRelationship comes back, update value
|
||||
if (!accessResult || populatedRelationship) {
|
||||
if (typeof index === 'number') {
|
||||
if (Array.isArray(field.relationTo)) {
|
||||
if (Array.isArray(fieldAsRelationship.relationTo)) {
|
||||
dataToUpdate[field.name][index].value = populatedRelationship;
|
||||
} else {
|
||||
dataToUpdate[field.name][index] = populatedRelationship;
|
||||
}
|
||||
} else if (Array.isArray(field.relationTo)) {
|
||||
} else if (Array.isArray(fieldAsRelationship.relationTo)) {
|
||||
dataToUpdate[field.name].value = populatedRelationship;
|
||||
} else {
|
||||
dataToUpdate[field.name] = populatedRelationship;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import GraphQL, { GraphQLObjectType, GraphQLSchema } from 'graphql';
|
||||
import graphQLHTTP from 'express-graphql';
|
||||
import { graphqlHTTP } from 'express-graphql';
|
||||
import queryComplexity, { simpleEstimator, fieldExtensionsEstimator } from 'graphql-query-complexity';
|
||||
import buildObjectType from './schema/buildObjectType';
|
||||
import buildMutationInputType from './schema/buildMutationInputType';
|
||||
@@ -12,7 +12,48 @@ import initCollections from '../collections/graphql/init';
|
||||
import initGlobals from '../globals/graphql/init';
|
||||
import buildWhereInputType from './schema/buildWhereInputType';
|
||||
import access from '../auth/graphql/resolvers/access';
|
||||
import { Config } from '../config/types';
|
||||
|
||||
type GraphQLTypes = {
|
||||
blockTypes: any;
|
||||
blockInputTypes: any;
|
||||
localeInputType: any;
|
||||
fallbackLocaleInputType: any;
|
||||
}
|
||||
|
||||
class InitializeGraphQL {
|
||||
types: GraphQLTypes;
|
||||
|
||||
config: Config;
|
||||
|
||||
Query: { name: string; fields: { [key: string]: any } } = { name: 'Query', fields: {} };
|
||||
|
||||
Mutation: { name: string; fields: { [key: string]: any } } = { name: 'Mutation', fields: {} };
|
||||
|
||||
buildBlockType: typeof buildBlockType;
|
||||
|
||||
buildMutationInputType: typeof buildMutationInputType;
|
||||
|
||||
buildWhereInputType: (name: any, fields: any, parentName: any) => GraphQL.GraphQLInputObjectType;
|
||||
|
||||
buildObjectType: typeof buildObjectType;
|
||||
|
||||
buildPoliciesType: typeof buildPoliciesType;
|
||||
|
||||
initCollections: typeof initCollections;
|
||||
|
||||
initGlobals: typeof initGlobals;
|
||||
|
||||
schema: GraphQL.GraphQLSchema;
|
||||
|
||||
extensions: (info: any) => Promise<any>;
|
||||
|
||||
customFormatErrorFn: () => any;
|
||||
|
||||
validationRules: any;
|
||||
|
||||
errorResponse: any;
|
||||
|
||||
constructor(init) {
|
||||
Object.assign(this, init);
|
||||
this.init = this.init.bind(this);
|
||||
@@ -20,7 +61,7 @@ class InitializeGraphQL {
|
||||
this.types = {
|
||||
blockTypes: {},
|
||||
blockInputTypes: {},
|
||||
};
|
||||
} as GraphQLTypes;
|
||||
|
||||
if (this.config.localization) {
|
||||
this.types.localeInputType = buildLocaleInputType(this.config.localization);
|
||||
@@ -108,7 +149,7 @@ class InitializeGraphQL {
|
||||
|
||||
init(req, res) {
|
||||
this.errorResponse = null;
|
||||
return graphQLHTTP(
|
||||
return graphqlHTTP(
|
||||
async (request, response, { variables }) => ({
|
||||
schema: this.schema,
|
||||
customFormatErrorFn: this.customFormatErrorFn,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import graphQLPlayground from 'graphql-playground-middleware-express';
|
||||
|
||||
function initPlayground() {
|
||||
function initPlayground(): void {
|
||||
if ((!this.config.graphQL.disablePlaygroundInProduction && process.env.NODE_ENV === 'production') || process.env.NODE_ENV !== 'production') {
|
||||
this.router.get(this.config.routes.graphQLPlayground, graphQLPlayground({
|
||||
endpoint: `${this.config.routes.api}${this.config.routes.graphQL}`,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Block } from '../../fields/config/types';
|
||||
import formatName from '../utilities/formatName';
|
||||
|
||||
function buildBlockType(block) {
|
||||
function buildBlockType(block: Block): void {
|
||||
const {
|
||||
slug,
|
||||
labels: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { GraphQLEnumType } from 'graphql';
|
||||
import { Config } from '../../config/types';
|
||||
|
||||
const buildFallbackLocaleInputType = (localization) => new GraphQLEnumType({
|
||||
const buildFallbackLocaleInputType = (localization: Config['localization']): GraphQLEnumType => new GraphQLEnumType({
|
||||
name: 'FallbackLocaleInputType',
|
||||
values: [...localization.locales, 'none'].reduce((values, locale) => ({
|
||||
...values,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { GraphQLEnumType } from 'graphql';
|
||||
import { Config } from 'src/config/types';
|
||||
|
||||
const buildLocaleInputType = (localization) => new GraphQLEnumType({
|
||||
const buildLocaleInputType = (localization: Config['localization']): GraphQLEnumType => new GraphQLEnumType({
|
||||
name: 'LocaleInputType',
|
||||
values: localization.locales.reduce((values, locale) => ({
|
||||
...values,
|
||||
|
||||
@@ -6,30 +6,33 @@ import {
|
||||
GraphQLInputObjectType,
|
||||
GraphQLList,
|
||||
GraphQLNonNull,
|
||||
GraphQLScalarType,
|
||||
GraphQLString,
|
||||
GraphQLType,
|
||||
} from 'graphql';
|
||||
import { GraphQLJSON } from 'graphql-type-json';
|
||||
import withNullableType from './withNullableType';
|
||||
import formatName from '../utilities/formatName';
|
||||
import combineParentName from '../utilities/combineParentName';
|
||||
import { ArrayField, Field, GroupField, RelationshipField, RelationshipManyField, RowField, SelectField } from '../../fields/config/types';
|
||||
|
||||
function buildMutationInputType(name, fields, parentName, forceNullable = false) {
|
||||
const fieldToSchemaMap = {
|
||||
number: (field) => ({ type: withNullableType(field, GraphQLFloat, forceNullable) }),
|
||||
text: (field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
email: (field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
textarea: (field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
richText: (field) => ({ type: withNullableType(field, GraphQLJSON, forceNullable) }),
|
||||
code: (field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
date: (field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
upload: (field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
'rich-text': (field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
html: (field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
radio: (field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
number: (field: Field) => ({ type: withNullableType(field, GraphQLFloat, forceNullable) }),
|
||||
text: (field: Field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
email: (field: Field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
textarea: (field: Field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
richText: (field: Field) => ({ type: withNullableType(field, GraphQLJSON, forceNullable) }),
|
||||
code: (field: Field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
date: (field: Field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
upload: (field: Field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
'rich-text': (field: Field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
html: (field: Field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
radio: (field: Field) => ({ type: withNullableType(field, GraphQLString, forceNullable) }),
|
||||
checkbox: () => ({ type: GraphQLBoolean }),
|
||||
select: (field) => {
|
||||
select: (field: SelectField) => {
|
||||
const formattedName = `${combineParentName(parentName, field.name)}_MutationInput`;
|
||||
let type = new GraphQLEnumType({
|
||||
let type: GraphQLType = new GraphQLEnumType({
|
||||
name: formattedName,
|
||||
values: field.options.reduce((values, option) => {
|
||||
if (typeof option === 'object' && option.value) {
|
||||
@@ -59,9 +62,10 @@ function buildMutationInputType(name, fields, parentName, forceNullable = false)
|
||||
|
||||
return { type };
|
||||
},
|
||||
relationship: (field) => {
|
||||
relationship: (field: RelationshipField) => {
|
||||
const isRelatedToManyCollections = Array.isArray(field.relationTo);
|
||||
let type = GraphQLString;
|
||||
type PayloadGraphQLRelationshipType = GraphQLScalarType | GraphQLList<GraphQLScalarType> | GraphQLInputObjectType;
|
||||
let type: PayloadGraphQLRelationshipType = GraphQLString;
|
||||
|
||||
if (isRelatedToManyCollections) {
|
||||
const fullName = `${combineParentName(parentName, field.label)}RelationshipInput`;
|
||||
@@ -71,7 +75,7 @@ function buildMutationInputType(name, fields, parentName, forceNullable = false)
|
||||
relationTo: {
|
||||
type: new GraphQLEnumType({
|
||||
name: `${fullName}RelationTo`,
|
||||
values: field.relationTo.reduce((values, option) => ({
|
||||
values: (field as RelationshipManyField).relationTo.reduce((values, option) => ({
|
||||
...values,
|
||||
[formatName(option)]: {
|
||||
value: option,
|
||||
@@ -86,21 +90,21 @@ function buildMutationInputType(name, fields, parentName, forceNullable = false)
|
||||
|
||||
return { type: field.hasMany ? new GraphQLList(type) : type };
|
||||
},
|
||||
array: (field) => {
|
||||
array: (field: ArrayField) => {
|
||||
const fullName = combineParentName(parentName, field.label);
|
||||
let type = buildMutationInputType(fullName, field.fields, fullName);
|
||||
let type: GraphQLType | GraphQLList<GraphQLType> = buildMutationInputType(fullName, field.fields, fullName);
|
||||
type = new GraphQLList(withNullableType(field, type, forceNullable));
|
||||
return { type };
|
||||
},
|
||||
group: (field) => {
|
||||
group: (field: GroupField) => {
|
||||
const requiresAtLeastOneField = field.fields.some((subField) => (subField.required && !subField.localized));
|
||||
const fullName = combineParentName(parentName, field.label);
|
||||
let type = buildMutationInputType(fullName, field.fields, fullName);
|
||||
let type: GraphQLType = buildMutationInputType(fullName, field.fields, fullName);
|
||||
if (requiresAtLeastOneField) type = new GraphQLNonNull(type);
|
||||
return { type };
|
||||
},
|
||||
blocks: () => ({ type: GraphQLJSON }),
|
||||
row: (field) => field.fields.reduce((acc, rowField) => {
|
||||
row: (field: RowField) => field.fields.reduce((acc, rowField: RowField) => {
|
||||
const getFieldSchema = fieldToSchemaMap[rowField.type];
|
||||
|
||||
if (getFieldSchema) {
|
||||
|
||||
@@ -9,25 +9,39 @@ import {
|
||||
GraphQLList,
|
||||
GraphQLObjectType,
|
||||
GraphQLString,
|
||||
GraphQLType,
|
||||
GraphQLUnionType,
|
||||
} from 'graphql';
|
||||
import { DateTimeResolver, EmailAddressResolver } from 'graphql-scalars';
|
||||
import { Field, RadioField, RelationshipField, RelationshipManyField, SelectField, UploadField } from '../../fields/config/types';
|
||||
import formatName from '../utilities/formatName';
|
||||
import combineParentName from '../utilities/combineParentName';
|
||||
import withNullableType from './withNullableType';
|
||||
|
||||
type LocaleInputType = {
|
||||
locale: {
|
||||
type: GraphQLType;
|
||||
},
|
||||
fallbackLocale: {
|
||||
type: GraphQLType;
|
||||
},
|
||||
where: {
|
||||
type: GraphQLType;
|
||||
}
|
||||
}
|
||||
|
||||
function buildObjectType(name, fields, parentName, baseFields = {}) {
|
||||
const recursiveBuildObjectType = buildObjectType.bind(this);
|
||||
|
||||
const fieldToSchemaMap = {
|
||||
number: (field) => ({ type: withNullableType(field, GraphQLFloat) }),
|
||||
text: (field) => ({ type: withNullableType(field, GraphQLString) }),
|
||||
email: (field) => ({ type: withNullableType(field, EmailAddressResolver) }),
|
||||
textarea: (field) => ({ type: withNullableType(field, GraphQLString) }),
|
||||
richText: (field) => ({ type: withNullableType(field, GraphQLJSON) }),
|
||||
code: (field) => ({ type: withNullableType(field, GraphQLString) }),
|
||||
date: (field) => ({ type: withNullableType(field, DateTimeResolver) }),
|
||||
upload: (field) => {
|
||||
number: (field: Field) => ({ type: withNullableType(field, GraphQLFloat) }),
|
||||
text: (field: Field) => ({ type: withNullableType(field, GraphQLString) }),
|
||||
email: (field: Field) => ({ type: withNullableType(field, EmailAddressResolver) }),
|
||||
textarea: (field: Field) => ({ type: withNullableType(field, GraphQLString) }),
|
||||
richText: (field: Field) => ({ type: withNullableType(field, GraphQLJSON) }),
|
||||
code: (field: Field) => ({ type: withNullableType(field, GraphQLString) }),
|
||||
date: (field: Field) => ({ type: withNullableType(field, DateTimeResolver) }),
|
||||
upload: (field: UploadField) => {
|
||||
const { relationTo, label } = field;
|
||||
const uploadName = combineParentName(parentName, label);
|
||||
|
||||
@@ -38,7 +52,7 @@ function buildObjectType(name, fields, parentName, baseFields = {}) {
|
||||
|
||||
const type = this.collections[relationTo].graphQL.type || newlyCreatedBlockType;
|
||||
|
||||
const uploadArgs = {};
|
||||
const uploadArgs = {} as LocaleInputType;
|
||||
|
||||
if (this.config.localization) {
|
||||
uploadArgs.locale = {
|
||||
@@ -108,7 +122,7 @@ function buildObjectType(name, fields, parentName, baseFields = {}) {
|
||||
|
||||
return upload;
|
||||
},
|
||||
radio: (field) => ({
|
||||
radio: (field: RadioField) => ({
|
||||
type: withNullableType(
|
||||
field,
|
||||
new GraphQLEnumType({
|
||||
@@ -122,11 +136,11 @@ function buildObjectType(name, fields, parentName, baseFields = {}) {
|
||||
}),
|
||||
),
|
||||
}),
|
||||
checkbox: (field) => ({ type: withNullableType(field, GraphQLBoolean) }),
|
||||
select: (field) => {
|
||||
checkbox: (field: Field) => ({ type: withNullableType(field, GraphQLBoolean) }),
|
||||
select: (field: SelectField) => {
|
||||
const fullName = combineParentName(parentName, field.name);
|
||||
|
||||
let type = new GraphQLEnumType({
|
||||
let type: GraphQLType = new GraphQLEnumType({
|
||||
name: fullName,
|
||||
values: field.options.reduce((values, option) => {
|
||||
if (typeof option === 'object' && option.value) {
|
||||
@@ -156,7 +170,7 @@ function buildObjectType(name, fields, parentName, baseFields = {}) {
|
||||
|
||||
return { type };
|
||||
},
|
||||
relationship: (field) => {
|
||||
relationship: (field: RelationshipField) => {
|
||||
const { relationTo, label } = field;
|
||||
const isRelatedToManyCollections = Array.isArray(relationTo);
|
||||
const hasManyValues = field.hasMany;
|
||||
@@ -168,7 +182,7 @@ function buildObjectType(name, fields, parentName, baseFields = {}) {
|
||||
if (isRelatedToManyCollections) {
|
||||
relationToType = new GraphQLEnumType({
|
||||
name: `${relationshipName}_RelationTo`,
|
||||
values: field.relationTo.reduce((relations, relation) => ({
|
||||
values: (field as RelationshipManyField).relationTo.reduce((relations, relation) => ({
|
||||
...relations,
|
||||
[formatName(relation)]: {
|
||||
value: relation,
|
||||
@@ -200,7 +214,7 @@ function buildObjectType(name, fields, parentName, baseFields = {}) {
|
||||
},
|
||||
});
|
||||
} else {
|
||||
({ type } = this.collections[relationTo].graphQL);
|
||||
({ type } = this.collections[relationTo as string].graphQL);
|
||||
}
|
||||
|
||||
// If the relationshipType is undefined at this point,
|
||||
@@ -210,7 +224,7 @@ function buildObjectType(name, fields, parentName, baseFields = {}) {
|
||||
|
||||
type = type || newlyCreatedBlockType;
|
||||
|
||||
const relationshipArgs = {};
|
||||
const relationshipArgs = {} as LocaleInputType;
|
||||
|
||||
if (this.config.localization) {
|
||||
relationshipArgs.locale = {
|
||||
|
||||
@@ -84,7 +84,6 @@ const buildWhereInputType = (name, fields, parentName) => {
|
||||
field,
|
||||
type,
|
||||
parentName,
|
||||
['equals', 'like', 'not_equals'],
|
||||
[...operators.equality, 'like'],
|
||||
),
|
||||
};
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { GraphQLNonNull } from 'graphql';
|
||||
import { GraphQLNonNull, GraphQLType } from 'graphql';
|
||||
import { Field } from '../../fields/config/types';
|
||||
|
||||
|
||||
const withNullableType = (field, type, forceNullable) => {
|
||||
const withNullableType = (field: Field, type: GraphQLType, forceNullable = false): GraphQLType => {
|
||||
const hasReadAccessControl = field.access && field.access.read;
|
||||
const condition = field.admin && field.admin.condition;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import formatName from './formatName';
|
||||
|
||||
const combineParentName = (parent, name) => formatName(`${parent ? `${parent}_` : ''}${name}`);
|
||||
const combineParentName = (parent: string, name: string): string => formatName(`${parent ? `${parent}_` : ''}${name}`);
|
||||
|
||||
export default combineParentName;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];
|
||||
|
||||
const formatName = (string) => {
|
||||
const formatName = (string: string): string => {
|
||||
let sanitizedString = String(string);
|
||||
|
||||
const firstLetter = sanitizedString.substring(0, 1);
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export default (localization) => (value) => typeof value === 'object'
|
||||
export default (localization: { locales: string[] }) => (value: unknown): boolean => typeof value === 'object'
|
||||
&& Object.keys(value).some((key) => localization.locales.indexOf(key) > -1);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function uppercase(str) {
|
||||
function uppercase(str: string): string {
|
||||
const array1 = str.split(' ');
|
||||
const newarray1 = [];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user