Files
twenty/server/src/tenant/schema-builder/schema-builder.service.ts
T
Jérémy M 80a6223d7d feat: custom objects delete one (#2278)
* feat: custom objects delete one

* fix: delete one issue
2023-10-30 12:05:03 +01:00

253 lines
7.1 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import {
GraphQLFieldConfigMap,
GraphQLID,
GraphQLInputObjectType,
GraphQLInt,
GraphQLList,
GraphQLNonNull,
GraphQLObjectType,
GraphQLSchema,
} from 'graphql';
import upperFirst from 'lodash.upperfirst';
import { EntityResolverService } from 'src/tenant/entity-resolver/entity-resolver.service';
import { ObjectMetadata } from 'src/metadata/object-metadata/object-metadata.entity';
import { generateEdgeType } from './utils/generate-edge-type.util';
import { generateConnectionType } from './utils/generate-connection-type.util';
import { generateObjectType } from './utils/generate-object-type.util';
import { generateCreateInputType } from './utils/generate-create-input-type.util';
import { generateUpdateInputType } from './utils/generate-update-input-type.util';
import { SchemaBuilderContext } from './interfaces/schema-builder-context.interface';
import { cleanEntityName } from './utils/clean-entity-name.util';
import { scalars } from './graphql-types/scalars';
import { CursorScalarType } from './graphql-types/scalars/cursor.scalar';
import { generateFilterInputType } from './utils/generate-filter-input-type.util';
import { generateOrderByInputType } from './utils/generate-order-by-input-type.util';
@Injectable()
export class SchemaBuilderService {
workspaceId: string;
constructor(private readonly entityResolverService: EntityResolverService) {}
private generateQueryFieldForEntity(
entityName: {
singular: string;
plural: string;
},
tableName: string,
ObjectType: GraphQLObjectType,
objectDefinition: ObjectMetadata,
) {
const schemaBuilderContext: SchemaBuilderContext = {
tableName,
workspaceId: this.workspaceId,
fields: objectDefinition.fields,
};
const EdgeType = generateEdgeType(ObjectType);
const ConnectionType = generateConnectionType(EdgeType);
const FilterInputType = generateFilterInputType(
entityName.singular,
objectDefinition.fields,
);
const OrderByInputType = generateOrderByInputType(
entityName.singular,
objectDefinition.fields,
);
return {
[`${entityName.plural}`]: {
type: ConnectionType,
args: {
first: { type: GraphQLInt },
last: { type: GraphQLInt },
before: { type: CursorScalarType },
after: { type: CursorScalarType },
filter: { type: FilterInputType },
orderBy: { type: OrderByInputType },
},
resolve: async (root, args, context, info) => {
return this.entityResolverService.findMany(
args,
schemaBuilderContext,
info,
);
},
},
[`${entityName.singular}`]: {
type: ObjectType,
args: {
filter: { type: FilterInputType },
},
resolve: (root, args, context, info) => {
return this.entityResolverService.findOne(
args,
schemaBuilderContext,
info,
);
},
},
} as GraphQLFieldConfigMap<any, any>;
}
private generateMutationFieldForEntity(
entityName: {
singular: string;
plural: string;
},
tableName: string,
ObjectType: GraphQLObjectType,
CreateInputType: GraphQLInputObjectType,
UpdateInputType: GraphQLInputObjectType,
objectDefinition: ObjectMetadata,
) {
const schemaBuilderContext: SchemaBuilderContext = {
tableName,
workspaceId: this.workspaceId,
fields: objectDefinition.fields,
};
return {
[`createOne${upperFirst(entityName.singular)}`]: {
type: new GraphQLNonNull(ObjectType),
args: {
data: { type: new GraphQLNonNull(CreateInputType) },
},
resolve: (root, args, context, info) => {
return this.entityResolverService.createOne(
args,
schemaBuilderContext,
info,
);
},
},
[`createMany${upperFirst(entityName.singular)}`]: {
type: new GraphQLList(ObjectType),
args: {
data: {
type: new GraphQLNonNull(
new GraphQLList(new GraphQLNonNull(CreateInputType)),
),
},
},
resolve: (root, args, context, info) => {
return this.entityResolverService.createMany(
args,
schemaBuilderContext,
info,
);
},
},
[`updateOne${upperFirst(entityName.singular)}`]: {
type: new GraphQLNonNull(ObjectType),
args: {
id: { type: new GraphQLNonNull(GraphQLID) },
data: { type: new GraphQLNonNull(UpdateInputType) },
},
resolve: (root, args, context, info) => {
return this.entityResolverService.updateOne(
args,
schemaBuilderContext,
info,
);
},
},
[`deleteOne${upperFirst(entityName.singular)}`]: {
type: new GraphQLNonNull(ObjectType),
args: {
id: { type: new GraphQLNonNull(GraphQLID) },
},
resolve: (root, args, context, info) => {
return this.entityResolverService.deleteOne(
args,
schemaBuilderContext,
info,
);
},
},
} as GraphQLFieldConfigMap<any, any>;
}
private generateQueryAndMutationTypes(objectMetadata: ObjectMetadata[]): {
query: GraphQLObjectType;
mutation: GraphQLObjectType;
} {
const queryFields: any = {};
const mutationFields: any = {};
for (const objectDefinition of objectMetadata) {
const entityName = {
singular: cleanEntityName(objectDefinition.nameSingular),
plural: cleanEntityName(objectDefinition.namePlural),
};
const tableName = objectDefinition?.targetTableName ?? '';
const ObjectType = generateObjectType(
entityName.singular,
objectDefinition.fields,
);
const CreateInputType = generateCreateInputType(
entityName.singular,
objectDefinition.fields,
);
const UpdateInputType = generateUpdateInputType(
entityName.singular,
objectDefinition.fields,
);
Object.assign(
queryFields,
this.generateQueryFieldForEntity(
entityName,
tableName,
ObjectType,
objectDefinition,
),
);
Object.assign(
mutationFields,
this.generateMutationFieldForEntity(
entityName,
tableName,
ObjectType,
CreateInputType,
UpdateInputType,
objectDefinition,
),
);
}
return {
query: new GraphQLObjectType({
name: 'Query',
fields: queryFields,
}),
mutation: new GraphQLObjectType({
name: 'Mutation',
fields: mutationFields,
}),
};
}
async generateSchema(
workspaceId: string,
objectMetadata: ObjectMetadata[],
): Promise<GraphQLSchema> {
this.workspaceId = workspaceId;
const { query, mutation } =
this.generateQueryAndMutationTypes(objectMetadata);
return new GraphQLSchema({
query,
mutation,
types: [...scalars],
});
}
}