met qua
This commit is contained in:
5
package-lock.json
generated
5
package-lock.json
generated
@@ -36,6 +36,7 @@
|
|||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.1",
|
"class-validator": "^0.14.1",
|
||||||
|
"epess-web-backend": "file:",
|
||||||
"graphql": "^16.9.0",
|
"graphql": "^16.9.0",
|
||||||
"graphql-scalars": "^1.23.0",
|
"graphql-scalars": "^1.23.0",
|
||||||
"graphql-tools": "^9.0.1",
|
"graphql-tools": "^9.0.1",
|
||||||
@@ -8812,6 +8813,10 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/epess-web-backend": {
|
||||||
|
"resolved": "",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/error-ex": {
|
"node_modules/error-ex": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
"build": "nest build",
|
"build": "nest build",
|
||||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||||
"start": "nest start",
|
"start": "nest start",
|
||||||
"start:dev": "npm run prisma:generate && nest start --watch",
|
"start:dev": "nest start --watch",
|
||||||
"start:debug": "nest start --debug --watch",
|
"start:debug": "nest start --debug --watch",
|
||||||
"start:prod": "node dist/main",
|
"start:prod": "node dist/main",
|
||||||
"prisma:generate": "npx prisma generate --schema=./epess-database/prisma/schema.prisma",
|
"prisma:generate": "npx prisma generate --schema=./epess-database/prisma/schema.prisma",
|
||||||
@@ -50,6 +50,7 @@
|
|||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.1",
|
"class-validator": "^0.14.1",
|
||||||
|
"epess-web-backend": "file:",
|
||||||
"graphql": "^16.9.0",
|
"graphql": "^16.9.0",
|
||||||
"graphql-scalars": "^1.23.0",
|
"graphql-scalars": "^1.23.0",
|
||||||
"graphql-tools": "^9.0.1",
|
"graphql-tools": "^9.0.1",
|
||||||
|
|||||||
@@ -4,10 +4,6 @@ import { ClerkModule } from './clerk/clerk.module';
|
|||||||
import { RestfulModule } from './restful/restful.module';
|
import { RestfulModule } from './restful/restful.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [GraphqlModule, ClerkModule, RestfulModule],
|
||||||
GraphqlModule, // GraphQL setup
|
|
||||||
ClerkModule, // Clerk setup
|
|
||||||
RestfulModule,
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ export class CenterSchema extends PothosSchema {
|
|||||||
description: t.exposeString('description'),
|
description: t.exposeString('description'),
|
||||||
location: t.exposeString('location'),
|
location: t.exposeString('location'),
|
||||||
individual: t.exposeBoolean('individual'),
|
individual: t.exposeBoolean('individual'),
|
||||||
createdAt: t.expose('createdAt', { type: 'Date' }),
|
createdAt: t.expose('createdAt', { type: 'DateTime' }),
|
||||||
updatedAt: t.expose('updatedAt', { type: 'Date' }),
|
updatedAt: t.expose('updatedAt', { type: 'DateTime' }),
|
||||||
services: t.relation('services'),
|
services: t.relation('services'),
|
||||||
centerOwner: t.relation('centerOwner'),
|
centerOwner: t.relation('centerOwner'),
|
||||||
chatRoom: t.relation('chatRoom'),
|
// chatRoom: t.relation('chatRoom'),
|
||||||
centerStaff: t.relation('CenterStaff'),
|
centerStaff: t.relation('CenterStaff'),
|
||||||
resume: t.relation('Resume'),
|
resume: t.relation('Resume'),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
import SchemaBuilder from '@pothos/core';
|
import SchemaBuilder from '@pothos/core';
|
||||||
import PrismaPlugin, { PothosPrismaDatamodel } from '@pothos/plugin-prisma';
|
import PrismaPlugin, {
|
||||||
import { PrismaClient } from '@prisma/client';
|
PothosPrismaDatamodel,
|
||||||
|
PrismaClient,
|
||||||
|
} from '@pothos/plugin-prisma';
|
||||||
import PrismaUtils from '@pothos/plugin-prisma-utils';
|
import PrismaUtils from '@pothos/plugin-prisma-utils';
|
||||||
import { Request } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import type PrismaTypes from '../types/pothos.generated';
|
import type PrismaTypes from '../types/pothos.generated';
|
||||||
import { getDatamodel } from '../types/pothos.generated';
|
import { getDatamodel } from '../types/pothos.generated';
|
||||||
import { DateTimeResolver } from 'graphql-scalars';
|
import { DateTimeResolver, JSONResolver } from 'graphql-scalars';
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { PrismaCrudGenerator } from './graphql.generator';
|
||||||
|
|
||||||
export interface SchemaContext {
|
export interface SchemaContext {
|
||||||
req: Request;
|
req: Request;
|
||||||
|
res: Response;
|
||||||
|
generator: PrismaCrudGenerator<BuilderTypes>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SchemaBuilderOption {
|
export interface SchemaBuilderOption {
|
||||||
@@ -16,30 +22,38 @@ export interface SchemaBuilderOption {
|
|||||||
PrismaTypes: PrismaTypes;
|
PrismaTypes: PrismaTypes;
|
||||||
DataModel: PothosPrismaDatamodel;
|
DataModel: PothosPrismaDatamodel;
|
||||||
Scalars: {
|
Scalars: {
|
||||||
Date: {
|
DateTime: {
|
||||||
Input: Date;
|
Input: Date;
|
||||||
Output: Date;
|
Output: Date;
|
||||||
};
|
};
|
||||||
|
Json: {
|
||||||
|
Input: JSON;
|
||||||
|
Output: JSON;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
export function createBuilder(client: PrismaClient) {
|
|
||||||
const builder = new SchemaBuilder<SchemaBuilderOption>({
|
@Injectable()
|
||||||
|
export class Builder extends SchemaBuilder<SchemaBuilderOption> {
|
||||||
|
public generator: PrismaCrudGenerator<BuilderTypes>;
|
||||||
|
|
||||||
|
constructor(private readonly prisma: PrismaClient) {
|
||||||
|
super({
|
||||||
plugins: [PrismaPlugin, PrismaUtils],
|
plugins: [PrismaPlugin, PrismaUtils],
|
||||||
prisma: {
|
prisma: {
|
||||||
client,
|
client: prisma,
|
||||||
exposeDescriptions: true,
|
exposeDescriptions: true,
|
||||||
filterConnectionTotalCount: true,
|
filterConnectionTotalCount: true,
|
||||||
onUnusedQuery: process.env.NODE_ENV === 'production' ? null : 'warn',
|
onUnusedQuery: process.env.NODE_ENV === 'production' ? null : 'warn',
|
||||||
dmmf: getDatamodel(),
|
dmmf: getDatamodel(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
this.generator = new PrismaCrudGenerator<BuilderTypes>(this);
|
||||||
builder.queryType({});
|
this.addScalarType('DateTime', DateTimeResolver);
|
||||||
// builder.mutationType({});
|
this.addScalarType('Json', JSONResolver);
|
||||||
// builder.subscriptionType({});
|
this.queryType({});
|
||||||
|
// this.mutationType({});
|
||||||
builder.addScalarType('Date', DateTimeResolver, {});
|
|
||||||
return builder;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
export type Builder = ReturnType<typeof createBuilder>;
|
export type BuilderTypes =
|
||||||
|
PothosSchemaTypes.ExtendDefaultTypes<SchemaBuilderOption>;
|
||||||
|
|||||||
637
src/graphql/graphql.generator.ts
Normal file
637
src/graphql/graphql.generator.ts
Normal file
@@ -0,0 +1,637 @@
|
|||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import {
|
||||||
|
type BaseEnum,
|
||||||
|
type EnumRef,
|
||||||
|
InputObjectRef,
|
||||||
|
type InputType,
|
||||||
|
type InputTypeParam,
|
||||||
|
type SchemaTypes,
|
||||||
|
} from '@pothos/core';
|
||||||
|
import { type PrismaModelTypes, getModel } from '@pothos/plugin-prisma';
|
||||||
|
import type { FilterOps } from '@pothos/plugin-prisma-utils';
|
||||||
|
import * as Prisma from '@prisma/client';
|
||||||
|
import { SchemaBuilderToken } from '@smatch-corp/nestjs-pothos';
|
||||||
|
|
||||||
|
//
|
||||||
|
const filterOps = ['equals', 'in', 'notIn', 'not', 'is', 'isNot'] as const;
|
||||||
|
const sortableFilterProps = ['lt', 'lte', 'gt', 'gte'] as const;
|
||||||
|
const stringFilterOps = [
|
||||||
|
...filterOps,
|
||||||
|
'contains',
|
||||||
|
'startsWith',
|
||||||
|
'endsWith',
|
||||||
|
] as const;
|
||||||
|
const sortableTypes = ['String', 'Int', 'Float', 'DateTime', 'BigInt'] as const;
|
||||||
|
const listOps = ['every', 'some', 'none'] as const;
|
||||||
|
const scalarListOps = [
|
||||||
|
'has',
|
||||||
|
'hasSome',
|
||||||
|
'hasEvery',
|
||||||
|
'isEmpty',
|
||||||
|
'equals',
|
||||||
|
] as const;
|
||||||
|
const JsonFilterOps = ['equals', 'in', 'notIn', 'not', 'is', 'isNot'] as const;
|
||||||
|
const EnumFilterOps = ['equals', 'not'] as const;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PrismaCrudGenerator<Types extends SchemaTypes> {
|
||||||
|
private refCache = new Map<
|
||||||
|
InputType<Types> | string,
|
||||||
|
Map<string, InputObjectRef<Types, unknown>>
|
||||||
|
>();
|
||||||
|
|
||||||
|
private enumRefs = new Map<string, EnumRef<Types, unknown>>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(SchemaBuilderToken)
|
||||||
|
private builder: PothosSchemaTypes.SchemaBuilder<Types>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
findManyArgs<Name extends string & keyof Types['PrismaTypes']>(
|
||||||
|
modelName: Name,
|
||||||
|
) {
|
||||||
|
return this.builder.args((t) => ({
|
||||||
|
filter: t.field({
|
||||||
|
type: this.getWhere(modelName),
|
||||||
|
required: false,
|
||||||
|
}),
|
||||||
|
orderBy: t.field({
|
||||||
|
type: this.getOrderBy(modelName),
|
||||||
|
required: false,
|
||||||
|
}),
|
||||||
|
cursor: t.field({
|
||||||
|
type: this.getWhereUnique(modelName),
|
||||||
|
required: false,
|
||||||
|
}),
|
||||||
|
take: t.field({
|
||||||
|
type: 'Int',
|
||||||
|
required: false,
|
||||||
|
}),
|
||||||
|
skip: t.field({
|
||||||
|
type: 'Int',
|
||||||
|
required: false,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
getWhere<Name extends string & keyof Types['PrismaTypes']>(
|
||||||
|
modelName: Name,
|
||||||
|
without?: string[],
|
||||||
|
) {
|
||||||
|
const withoutName = (without ?? [])
|
||||||
|
.map((name) => `Without${capitalize(name)}`)
|
||||||
|
.join('');
|
||||||
|
const fullName = `${modelName}${withoutName}Filter`;
|
||||||
|
|
||||||
|
return this.getRef(modelName, fullName, () => {
|
||||||
|
const model = getModel(modelName, this.builder);
|
||||||
|
|
||||||
|
return this.builder.prismaWhere(modelName, {
|
||||||
|
name: fullName,
|
||||||
|
fields: (() => {
|
||||||
|
const fields: Record<string, InputType<Types>> = {};
|
||||||
|
const withoutFields = model.fields.filter((field) =>
|
||||||
|
without?.includes(field.name),
|
||||||
|
);
|
||||||
|
|
||||||
|
model.fields
|
||||||
|
.filter(
|
||||||
|
(field) =>
|
||||||
|
!withoutFields.some(
|
||||||
|
(f) =>
|
||||||
|
f.name === field.name ||
|
||||||
|
f.relationFromFields?.includes(field.name),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.forEach((field) => {
|
||||||
|
// biome-ignore lint/suspicious/noImplicitAnyLet: <explanation>
|
||||||
|
let type;
|
||||||
|
switch (field.kind) {
|
||||||
|
case 'scalar':
|
||||||
|
type = field.isList
|
||||||
|
? this.getScalarListFilter(
|
||||||
|
this.mapScalarType(field.type) as InputType<Types>,
|
||||||
|
)
|
||||||
|
: this.getFilter(
|
||||||
|
this.mapScalarType(field.type) as InputType<Types>,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'enum':
|
||||||
|
type = field.isList
|
||||||
|
? this.getScalarListFilter(this.getEnum(field.type))
|
||||||
|
: this.getFilter(this.getEnum(field.type));
|
||||||
|
break;
|
||||||
|
case 'object':
|
||||||
|
type = field.isList
|
||||||
|
? this.getListFilter(this.getWhere(field.type as Name))
|
||||||
|
: this.getWhere(field.type as Name);
|
||||||
|
break;
|
||||||
|
case 'unsupported':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown field kind ${field.kind}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fields[field.name] = type;
|
||||||
|
});
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}) as never,
|
||||||
|
}) as InputObjectRef<
|
||||||
|
Types,
|
||||||
|
(PrismaModelTypes & Types['PrismaTypes'][Name])['Where']
|
||||||
|
>;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
getWhereUnique<Name extends string & keyof Types['PrismaTypes']>(
|
||||||
|
modelName: Name,
|
||||||
|
) {
|
||||||
|
const name = `${modelName}UniqueFilter`;
|
||||||
|
|
||||||
|
return this.getRef(modelName, name, () => {
|
||||||
|
const model = getModel(modelName, this.builder);
|
||||||
|
return this.builder.prismaWhereUnique(modelName, {
|
||||||
|
name,
|
||||||
|
fields: (() => {
|
||||||
|
const fields: Record<string, InputType<Types>> = {};
|
||||||
|
|
||||||
|
model.fields
|
||||||
|
.filter(
|
||||||
|
(field) =>
|
||||||
|
field.isUnique ||
|
||||||
|
field.isId ||
|
||||||
|
model.uniqueIndexes.some((index) =>
|
||||||
|
index.fields.includes(field.name),
|
||||||
|
) ||
|
||||||
|
model.primaryKey?.fields.includes(field.name),
|
||||||
|
)
|
||||||
|
.forEach((field) => {
|
||||||
|
// biome-ignore lint/suspicious/noImplicitAnyLet: <explanation>
|
||||||
|
let type;
|
||||||
|
switch (field.kind) {
|
||||||
|
case 'scalar':
|
||||||
|
type = this.mapScalarType(field.type) as InputType<Types>;
|
||||||
|
break;
|
||||||
|
case 'enum':
|
||||||
|
type = this.getEnum(field.type);
|
||||||
|
break;
|
||||||
|
case 'object':
|
||||||
|
case 'unsupported':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown field kind ${field.kind}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fields[field.name] = type;
|
||||||
|
});
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}) as never,
|
||||||
|
}) as InputObjectRef<
|
||||||
|
Types,
|
||||||
|
(PrismaModelTypes & Types['PrismaTypes'][Name])['WhereUnique']
|
||||||
|
>;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
getOrderBy<Name extends string & keyof Types['PrismaTypes']>(
|
||||||
|
modelName: Name,
|
||||||
|
) {
|
||||||
|
const name = `${modelName}OrderBy`;
|
||||||
|
return this.getRef(modelName, name, () => {
|
||||||
|
const model = getModel(modelName, this.builder);
|
||||||
|
|
||||||
|
return this.builder.prismaOrderBy(modelName, {
|
||||||
|
name,
|
||||||
|
fields: () => {
|
||||||
|
const fields: Record<string, InputType<Types> | boolean> = {};
|
||||||
|
|
||||||
|
model.fields.forEach((field) => {
|
||||||
|
// biome-ignore lint/suspicious/noImplicitAnyLet: <explanation>
|
||||||
|
let type;
|
||||||
|
switch (field.kind) {
|
||||||
|
case 'scalar':
|
||||||
|
case 'enum':
|
||||||
|
type = true;
|
||||||
|
break;
|
||||||
|
case 'object':
|
||||||
|
type = this.getOrderBy(field.type as Name);
|
||||||
|
break;
|
||||||
|
case 'unsupported':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown field kind ${field.kind}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type) {
|
||||||
|
fields[field.name] = type;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return fields as {};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getCreateInput<Name extends string & keyof Types['PrismaTypes']>(
|
||||||
|
modelName: Name,
|
||||||
|
without?: string[],
|
||||||
|
) {
|
||||||
|
const withoutName = (without ?? [])
|
||||||
|
.map((name) => `Without${capitalize(name)}`)
|
||||||
|
.join('');
|
||||||
|
const fullName = `${modelName}Create${withoutName}Input`;
|
||||||
|
|
||||||
|
return this.getRef(modelName, fullName, () => {
|
||||||
|
const model = getModel(modelName, this.builder);
|
||||||
|
return this.builder.prismaCreate(modelName, {
|
||||||
|
name: fullName,
|
||||||
|
fields: (() => {
|
||||||
|
const fields: Record<string, InputTypeParam<Types>> = {};
|
||||||
|
const withoutFields = model.fields.filter((field) =>
|
||||||
|
without?.includes(field.name),
|
||||||
|
);
|
||||||
|
const relationIds = model.fields.flatMap(
|
||||||
|
(field) => field.relationFromFields ?? [],
|
||||||
|
);
|
||||||
|
|
||||||
|
model.fields
|
||||||
|
.filter(
|
||||||
|
(field) =>
|
||||||
|
!withoutFields.some(
|
||||||
|
(f) =>
|
||||||
|
f.name === field.name ||
|
||||||
|
f.relationFromFields?.includes(field.name),
|
||||||
|
) && !relationIds.includes(field.name),
|
||||||
|
)
|
||||||
|
.forEach((field) => {
|
||||||
|
// biome-ignore lint/suspicious/noImplicitAnyLet: <explanation>
|
||||||
|
let type;
|
||||||
|
switch (field.kind) {
|
||||||
|
case 'scalar':
|
||||||
|
type = this.mapScalarType(field.type) as InputType<Types>;
|
||||||
|
break;
|
||||||
|
case 'enum':
|
||||||
|
type = this.getEnum(field.type);
|
||||||
|
break;
|
||||||
|
case 'object':
|
||||||
|
type = this.getCreateRelationInput(modelName, field.name);
|
||||||
|
break;
|
||||||
|
case 'unsupported':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown field kind ${field.kind}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type) {
|
||||||
|
fields[field.name] = type;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}) as never,
|
||||||
|
}) as InputObjectRef<
|
||||||
|
Types,
|
||||||
|
(PrismaModelTypes & Types['PrismaTypes'][Name])['Create']
|
||||||
|
>;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getCreateRelationInput<
|
||||||
|
Name extends string & keyof Types['PrismaTypes'],
|
||||||
|
Relation extends Model['RelationName'],
|
||||||
|
Model extends
|
||||||
|
PrismaModelTypes = Types['PrismaTypes'][Name] extends PrismaModelTypes
|
||||||
|
? Types['PrismaTypes'][Name]
|
||||||
|
: never,
|
||||||
|
>(modelName: Name, relation: Relation) {
|
||||||
|
return this.getRef(
|
||||||
|
`${modelName}${capitalize(relation)}`,
|
||||||
|
'CreateRelationInput',
|
||||||
|
() => {
|
||||||
|
const model = getModel(modelName, this.builder);
|
||||||
|
return this.builder.prismaCreateRelation(modelName, relation, {
|
||||||
|
fields: () => {
|
||||||
|
const relationField = model.fields.find(
|
||||||
|
(field) => field.name === relation,
|
||||||
|
)!;
|
||||||
|
const relatedModel = getModel(relationField.type, this.builder);
|
||||||
|
const relatedFieldName = relatedModel.fields.find(
|
||||||
|
(field) => field.relationName === relationField.relationName,
|
||||||
|
)!;
|
||||||
|
|
||||||
|
return {
|
||||||
|
create: this.getCreateInput(relationField.type as Name, [
|
||||||
|
relatedFieldName.name,
|
||||||
|
]),
|
||||||
|
connect: this.getWhereUnique(relationField.type as Name),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
} as never) as InputObjectRef<
|
||||||
|
Types,
|
||||||
|
NonNullable<Model['Create'][Relation & keyof Model['Update']]>
|
||||||
|
>;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCreateManyInput<Name extends string & keyof Types['PrismaTypes']>(
|
||||||
|
modelName: Name,
|
||||||
|
without?: string[],
|
||||||
|
) {
|
||||||
|
const withoutName = (without ?? [])
|
||||||
|
.map((name) => `Without${capitalize(name)}`)
|
||||||
|
.join('');
|
||||||
|
const fullName = `${modelName}Create${withoutName}Input`;
|
||||||
|
|
||||||
|
return this.getRef(modelName, fullName, () => {
|
||||||
|
const model = getModel(modelName, this.builder);
|
||||||
|
|
||||||
|
return this.builder.prismaCreateMany(modelName, {
|
||||||
|
name: fullName,
|
||||||
|
fields: (() => {
|
||||||
|
const fields: Record<string, InputTypeParam<Types>> = {};
|
||||||
|
const withoutFields = model.fields.filter((field) =>
|
||||||
|
without?.includes(field.name),
|
||||||
|
);
|
||||||
|
const relationIds = model.fields.flatMap(
|
||||||
|
(field) => field.relationFromFields ?? [],
|
||||||
|
);
|
||||||
|
|
||||||
|
model.fields
|
||||||
|
.filter(
|
||||||
|
(field) =>
|
||||||
|
!withoutFields.some(
|
||||||
|
(f) =>
|
||||||
|
f.name === field.name ||
|
||||||
|
f.relationFromFields?.includes(field.name),
|
||||||
|
) && !relationIds.includes(field.name),
|
||||||
|
)
|
||||||
|
.forEach((field) => {
|
||||||
|
// biome-ignore lint/suspicious/noImplicitAnyLet: <explanation>
|
||||||
|
let type;
|
||||||
|
switch (field.kind) {
|
||||||
|
case 'scalar':
|
||||||
|
type = this.mapScalarType(field.type) as InputType<Types>;
|
||||||
|
break;
|
||||||
|
case 'enum':
|
||||||
|
type = this.getEnum(field.type);
|
||||||
|
break;
|
||||||
|
case 'unsupported':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown field kind ${field.kind}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type) {
|
||||||
|
fields[field.name] = type;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}) as never,
|
||||||
|
}) as InputObjectRef<
|
||||||
|
Types,
|
||||||
|
(PrismaModelTypes & Types['PrismaTypes'][Name])['Create']
|
||||||
|
>;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getUpdateInput<Name extends string & keyof Types['PrismaTypes']>(
|
||||||
|
modelName: Name,
|
||||||
|
without?: string[],
|
||||||
|
) {
|
||||||
|
const withoutName = (without ?? [])
|
||||||
|
.map((name) => `Without${capitalize(name)}`)
|
||||||
|
.join('');
|
||||||
|
const fullName = `${modelName}Update${withoutName}Input`;
|
||||||
|
|
||||||
|
return this.getRef(modelName, fullName, () => {
|
||||||
|
const model = getModel(modelName, this.builder);
|
||||||
|
return this.builder.prismaUpdate(modelName, {
|
||||||
|
name: fullName,
|
||||||
|
fields: (() => {
|
||||||
|
const fields: Record<string, InputTypeParam<Types>> = {};
|
||||||
|
const withoutFields = model.fields.filter((field) =>
|
||||||
|
without?.includes(field.name),
|
||||||
|
);
|
||||||
|
const relationIds = model.fields.flatMap(
|
||||||
|
(field) => field.relationFromFields ?? [],
|
||||||
|
);
|
||||||
|
|
||||||
|
model.fields
|
||||||
|
.filter(
|
||||||
|
(field) =>
|
||||||
|
!withoutFields.some(
|
||||||
|
(f) =>
|
||||||
|
f.name === field.name ||
|
||||||
|
f.relationFromFields?.includes(field.name),
|
||||||
|
) && !relationIds.includes(field.name),
|
||||||
|
)
|
||||||
|
.forEach((field) => {
|
||||||
|
// biome-ignore lint/suspicious/noImplicitAnyLet: <explanation>
|
||||||
|
let type;
|
||||||
|
switch (field.kind) {
|
||||||
|
case 'scalar':
|
||||||
|
type = this.mapScalarType(field.type) as InputType<Types>;
|
||||||
|
break;
|
||||||
|
case 'enum':
|
||||||
|
type = this.getEnum(field.type);
|
||||||
|
break;
|
||||||
|
case 'object':
|
||||||
|
type = this.getUpdateRelationInput(modelName, field.name);
|
||||||
|
break;
|
||||||
|
case 'unsupported':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown field kind ${field.kind}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type) {
|
||||||
|
fields[field.name] = type;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}) as never,
|
||||||
|
}) as InputObjectRef<
|
||||||
|
Types,
|
||||||
|
(PrismaModelTypes & Types['PrismaTypes'][Name])['Update']
|
||||||
|
>;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
getUpdateRelationInput<
|
||||||
|
Name extends string & keyof Types['PrismaTypes'],
|
||||||
|
Relation extends Model['RelationName'],
|
||||||
|
Model extends
|
||||||
|
PrismaModelTypes = Types['PrismaTypes'][Name] extends PrismaModelTypes
|
||||||
|
? Types['PrismaTypes'][Name]
|
||||||
|
: never,
|
||||||
|
>(modelName: Name, relation: Relation) {
|
||||||
|
return this.getRef(
|
||||||
|
`${modelName}${capitalize(relation)}`,
|
||||||
|
'UpdateRelationInput',
|
||||||
|
() => {
|
||||||
|
const model = getModel(modelName, this.builder);
|
||||||
|
return this.builder.prismaUpdateRelation(modelName, relation, {
|
||||||
|
fields: () => {
|
||||||
|
const relationField = model.fields.find(
|
||||||
|
(field) => field.name === relation,
|
||||||
|
)!;
|
||||||
|
const relatedModel = getModel(relationField.type, this.builder);
|
||||||
|
const relatedFieldName = relatedModel.fields.find(
|
||||||
|
(field) => field.relationName === relationField.relationName,
|
||||||
|
)!.name;
|
||||||
|
|
||||||
|
if (relationField.isList) {
|
||||||
|
return {
|
||||||
|
create: this.getCreateInput(relationField.type as Name, [
|
||||||
|
relatedFieldName,
|
||||||
|
]),
|
||||||
|
createMany: {
|
||||||
|
skipDuplicates: 'Boolean',
|
||||||
|
data: this.getCreateInput(relationField.type as Name, [
|
||||||
|
relatedFieldName,
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
set: this.getWhereUnique(relationField.type as Name),
|
||||||
|
disconnect: this.getWhereUnique(relationField.type as Name),
|
||||||
|
delete: this.getWhereUnique(relationField.type as Name),
|
||||||
|
connect: this.getWhereUnique(relationField.type as Name),
|
||||||
|
update: {
|
||||||
|
where: this.getWhereUnique(relationField.type as Name),
|
||||||
|
data: this.getUpdateInput(relationField.type as Name, [
|
||||||
|
relatedFieldName,
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
updateMany: {
|
||||||
|
where: this.getWhere(relationField.type as Name, [
|
||||||
|
relatedFieldName,
|
||||||
|
]),
|
||||||
|
data: this.getUpdateInput(relationField.type as Name, [
|
||||||
|
relatedFieldName,
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
deleteMany: this.getWhere(relationField.type as Name, [
|
||||||
|
relatedFieldName,
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
create: this.getCreateInput(relationField.type as Name, [
|
||||||
|
relatedFieldName,
|
||||||
|
]),
|
||||||
|
update: this.getUpdateInput(relationField.type as Name, [
|
||||||
|
relatedFieldName,
|
||||||
|
]),
|
||||||
|
connect: this.getWhereUnique(relationField.type as Name),
|
||||||
|
disconnect: relationField.isRequired ? undefined : 'Boolean',
|
||||||
|
delete: relationField.isRequired ? undefined : 'Boolean',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
} as never) as InputObjectRef<
|
||||||
|
Types,
|
||||||
|
NonNullable<Model['Update'][Relation & keyof Model['Update']]>
|
||||||
|
>;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getFilter(type: InputType<Types>) {
|
||||||
|
return this.getRef(type, `${String(type)}Filter`, () => {
|
||||||
|
const ops: FilterOps[] = [...filterOps];
|
||||||
|
|
||||||
|
if (type === 'String') {
|
||||||
|
ops.push(...stringFilterOps);
|
||||||
|
}
|
||||||
|
if (sortableTypes.includes(type as never)) {
|
||||||
|
ops.push(...sortableFilterProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.builder.prismaFilter(type, {
|
||||||
|
ops,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getScalarListFilter(type: InputType<Types>) {
|
||||||
|
return this.getRef(type, `${String(type)}ListFilter`, () =>
|
||||||
|
this.builder.prismaScalarListFilter(type, {
|
||||||
|
ops: scalarListOps,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getListFilter(type: InputType<Types>) {
|
||||||
|
return this.getRef(type, `${String(type)}ListFilter`, () =>
|
||||||
|
this.builder.prismaListFilter(type, {
|
||||||
|
ops: listOps,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getEnum(name: string) {
|
||||||
|
if (!this.enumRefs.has(name)) {
|
||||||
|
const enumRef = this.builder.enumType(
|
||||||
|
(Prisma as unknown as Record<string, BaseEnum>)[name],
|
||||||
|
{
|
||||||
|
name,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
this.enumRefs.set(name, enumRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.enumRefs.get(name)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapScalarType(type: string) {
|
||||||
|
switch (type) {
|
||||||
|
case 'String':
|
||||||
|
case 'Boolean':
|
||||||
|
case 'Int':
|
||||||
|
case 'Float':
|
||||||
|
case 'DateTime':
|
||||||
|
case 'Json':
|
||||||
|
return type;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRef<T extends InputObjectRef<Types, unknown>>(
|
||||||
|
key: InputType<Types> | string,
|
||||||
|
name: string,
|
||||||
|
create: () => T,
|
||||||
|
): T {
|
||||||
|
if (!this.refCache.has(key)) {
|
||||||
|
this.refCache.set(key, new Map());
|
||||||
|
}
|
||||||
|
const cache = this.refCache.get(key)!;
|
||||||
|
|
||||||
|
if (cache.has(name)) {
|
||||||
|
return cache.get(name)! as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ref = new InputObjectRef<Types, unknown>(name);
|
||||||
|
|
||||||
|
cache.set(name, ref);
|
||||||
|
|
||||||
|
this.builder.configStore.associateParamWithRef(ref, create());
|
||||||
|
|
||||||
|
return ref as T;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function capitalize(str: string) {
|
||||||
|
return str[0].toUpperCase() + str.slice(1);
|
||||||
|
}
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
import { ApolloDriverConfig } from '@nestjs/apollo';
|
import { ApolloDriverConfig } from '@nestjs/apollo';
|
||||||
import { MiddlewareConsumer, Module } from '@nestjs/common';
|
import { Global, MiddlewareConsumer, Module } from '@nestjs/common';
|
||||||
import { GraphQLModule } from '@nestjs/graphql';
|
import { GraphQLModule } from '@nestjs/graphql';
|
||||||
import { PothosModule } from '@smatch-corp/nestjs-pothos';
|
import { PothosModule } from '@smatch-corp/nestjs-pothos';
|
||||||
import { PothosApolloDriver } from '@smatch-corp/nestjs-pothos-apollo-driver';
|
import { PothosApolloDriver } from '@smatch-corp/nestjs-pothos-apollo-driver';
|
||||||
import { createBuilder } from './graphql.builder';
|
import { Builder } from './graphql.builder';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import { GraphQLValidationMiddleware } from 'src/middlewares/graphql.middleware';
|
import { GraphQLValidationMiddleware } from 'src/middlewares/graphql.middleware';
|
||||||
import { PrismaModule } from 'src/prisma/prisma.module';
|
import { PrismaModule } from 'src/prisma/prisma.module';
|
||||||
import { UserModule } from 'src/user/user.module';
|
import { UserModule } from 'src/user/user.module';
|
||||||
import { CenterModule } from 'src/center/center.module';
|
import { CenterModule } from 'src/center/center.module';
|
||||||
import { GraphqlService } from './graphql.service';
|
|
||||||
import { ServiceModule } from 'src/service/service.module';
|
import { ServiceModule } from 'src/service/service.module';
|
||||||
import { ChatroomModule } from 'src/chatroom/chatroom.module';
|
import { ChatroomModule } from 'src/chatroom/chatroom.module';
|
||||||
import { CenterStaffModule } from 'src/centerstaff/centerstaff.module';
|
import { CenterStaffModule } from 'src/centerstaff/centerstaff.module';
|
||||||
@@ -17,6 +16,9 @@ import { ResumeModule } from 'src/resume/resume.module';
|
|||||||
import { WorkshopModule } from 'src/workshop/workshop.module';
|
import { WorkshopModule } from 'src/workshop/workshop.module';
|
||||||
import { WorkshopOrganizationModule } from 'src/workshoporganization/workshoporganization.module';
|
import { WorkshopOrganizationModule } from 'src/workshoporganization/workshoporganization.module';
|
||||||
import { WorkshopSubscriptionModule } from 'src/workshopsubscription/workshopsubscription.module';
|
import { WorkshopSubscriptionModule } from 'src/workshopsubscription/workshopsubscription.module';
|
||||||
|
import { PrismaCrudGenerator } from './graphql.generator';
|
||||||
|
|
||||||
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
PrismaModule,
|
PrismaModule,
|
||||||
@@ -32,14 +34,26 @@ import { WorkshopSubscriptionModule } from 'src/workshopsubscription/workshopsub
|
|||||||
PothosModule.forRoot({
|
PothosModule.forRoot({
|
||||||
builder: {
|
builder: {
|
||||||
inject: [PrismaService],
|
inject: [PrismaService],
|
||||||
useFactory: (prisma: PrismaService) => createBuilder(prisma),
|
useFactory: (prisma: PrismaService) => new Builder(prisma),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
GraphQLModule.forRoot<ApolloDriverConfig>({
|
GraphQLModule.forRoot<ApolloDriverConfig>({
|
||||||
driver: PothosApolloDriver,
|
driver: PothosApolloDriver,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
providers: [GraphqlService],
|
providers: [
|
||||||
|
{
|
||||||
|
provide: Builder,
|
||||||
|
useFactory: (prisma: PrismaService) => new Builder(prisma),
|
||||||
|
inject: [PrismaService],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: PrismaCrudGenerator,
|
||||||
|
useFactory: (builder: Builder) => new PrismaCrudGenerator(builder),
|
||||||
|
inject: [Builder],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
exports: [Builder, PrismaCrudGenerator],
|
||||||
})
|
})
|
||||||
export class GraphqlModule {
|
export class GraphqlModule {
|
||||||
configure(consumer: MiddlewareConsumer) {
|
configure(consumer: MiddlewareConsumer) {
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import { NestFactory } from '@nestjs/core';
|
|||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
import { cors } from './common/utils/cors.utils';
|
import { cors } from './common/utils/cors.utils';
|
||||||
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
||||||
// Import DateTime scalar if necessary
|
|
||||||
require('./common/utils/datetime.utils');
|
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Request, Response, NextFunction } from 'express';
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class GraphQLValidationMiddleware implements NestMiddleware {
|
export class GraphQLValidationMiddleware implements NestMiddleware {
|
||||||
use(req: Request, res: Response, next: NextFunction) {
|
use(req: Request, res: Response, next: NextFunction) {
|
||||||
// Only handle POST requests
|
// handle post request
|
||||||
if (
|
if (
|
||||||
req.method === 'POST' &&
|
req.method === 'POST' &&
|
||||||
req.headers['content-type'] === 'application/json'
|
req.headers['content-type'] === 'application/json'
|
||||||
@@ -12,18 +12,14 @@ export class GraphQLValidationMiddleware implements NestMiddleware {
|
|||||||
const { query, mutation, subscription } = req.body;
|
const { query, mutation, subscription } = req.body;
|
||||||
|
|
||||||
// If none of these are present, return a custom error response
|
// If none of these are present, return a custom error response
|
||||||
if (!query && !mutation && !subscription) {
|
if (
|
||||||
return res.status(400).json({
|
!query &&
|
||||||
errors: [
|
!mutation &&
|
||||||
{
|
!subscription &&
|
||||||
message:
|
query.trim() === '' &&
|
||||||
'Must provide a valid GraphQL query, mutation, or subscription.',
|
mutation.trim() === '' &&
|
||||||
},
|
subscription.trim() === ''
|
||||||
],
|
) {
|
||||||
});
|
|
||||||
}
|
|
||||||
// handle query only contain \n
|
|
||||||
if (query.trim() === '') {
|
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
errors: [
|
errors: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,24 @@ export class PrismaService extends PrismaClient implements OnModuleInit {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
log: ['query', 'info', 'warn', 'error'],
|
log: [
|
||||||
|
{
|
||||||
|
emit: 'event',
|
||||||
|
level: 'query',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
emit: 'stdout',
|
||||||
|
level: 'error',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
emit: 'event',
|
||||||
|
level: 'info',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
emit: 'stdout',
|
||||||
|
level: 'warn',
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ export class ResumeSchema extends PothosSchema {
|
|||||||
centerId: t.exposeID('centerId'),
|
centerId: t.exposeID('centerId'),
|
||||||
status: t.exposeString('status'),
|
status: t.exposeString('status'),
|
||||||
createdAt: t.expose('createdAt', {
|
createdAt: t.expose('createdAt', {
|
||||||
type: 'Date',
|
type: 'DateTime',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
}),
|
}),
|
||||||
updatedAt: t.expose('updatedAt', {
|
updatedAt: t.expose('updatedAt', {
|
||||||
type: 'Date',
|
type: 'DateTime',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
}),
|
}),
|
||||||
center: t.relation('center'),
|
center: t.relation('center'),
|
||||||
@@ -38,13 +38,6 @@ export class ResumeSchema extends PothosSchema {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@PothosRef()
|
|
||||||
resumeStatus() {
|
|
||||||
return this.builder.enumType('ResumeStatus', {
|
|
||||||
values: ['PENDING', 'APPROVED', 'REJECTED'],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Pothos()
|
@Pothos()
|
||||||
init() {
|
init() {
|
||||||
this.builder.queryField('resumes', (t) =>
|
this.builder.queryField('resumes', (t) =>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Global, Module } from '@nestjs/common';
|
import { Global, Module } from '@nestjs/common';
|
||||||
import { ServiceSchema } from './service.schema';
|
import { ServiceSchema } from './service.schema';
|
||||||
|
import { PrismaCrudGenerator } from 'src/graphql/graphql.generator';
|
||||||
|
|
||||||
@Global()
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
providers: [ServiceSchema],
|
providers: [ServiceSchema, PrismaCrudGenerator],
|
||||||
exports: [ServiceSchema],
|
exports: [ServiceSchema],
|
||||||
})
|
})
|
||||||
export class ServiceModule {}
|
export class ServiceModule {}
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ import {
|
|||||||
PothosSchema,
|
PothosSchema,
|
||||||
SchemaBuilderToken,
|
SchemaBuilderToken,
|
||||||
} from '@smatch-corp/nestjs-pothos';
|
} from '@smatch-corp/nestjs-pothos';
|
||||||
import { Builder } from '../graphql/graphql.builder';
|
import { Builder, BuilderTypes } from '../graphql/graphql.builder';
|
||||||
import { PrismaService } from 'src/prisma/prisma.service';
|
import { PrismaService } from 'src/prisma/prisma.service';
|
||||||
|
import { PrismaCrudGenerator } from 'src/graphql/graphql.generator';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ServiceSchema extends PothosSchema {
|
export class ServiceSchema extends PothosSchema {
|
||||||
@@ -27,11 +28,11 @@ export class ServiceSchema extends PothosSchema {
|
|||||||
price: t.exposeFloat('price'),
|
price: t.exposeFloat('price'),
|
||||||
rating: t.exposeFloat('rating'),
|
rating: t.exposeFloat('rating'),
|
||||||
createdAt: t.expose('createdAt', {
|
createdAt: t.expose('createdAt', {
|
||||||
type: 'Date',
|
type: 'DateTime',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
}),
|
}),
|
||||||
updatedAt: t.expose('updatedAt', {
|
updatedAt: t.expose('updatedAt', {
|
||||||
type: 'Date',
|
type: 'DateTime',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
@@ -79,4 +80,26 @@ export class ServiceSchema extends PothosSchema {
|
|||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Pothos()
|
||||||
|
// initMutation() {
|
||||||
|
// this.builder.mutationFields((t) => ({
|
||||||
|
// createService: t.prismaField({
|
||||||
|
// type: this.service(),
|
||||||
|
// args: {
|
||||||
|
// input: t.arg({
|
||||||
|
// type: this.generator.getCreateInput('Service'),
|
||||||
|
// required: true,
|
||||||
|
// }),
|
||||||
|
// },
|
||||||
|
// resolve: async (query, root, args, ctx, info) => {
|
||||||
|
// const { input } = args;
|
||||||
|
// const service = await this.prisma.service.create({
|
||||||
|
// data: input,
|
||||||
|
// });
|
||||||
|
// return service;
|
||||||
|
// },
|
||||||
|
// }),
|
||||||
|
// }));
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
import { DateTimeResolver } from 'graphql-scalars';
|
|
||||||
@@ -1,9 +1,30 @@
|
|||||||
import { Global, Module } from '@nestjs/common';
|
import { Global, Module } from '@nestjs/common';
|
||||||
import { UserSchema } from './user.schema';
|
import { UserSchema } from './user.schema';
|
||||||
|
import { Builder, BuilderTypes } from '../graphql/graphql.builder';
|
||||||
|
import { PrismaCrudGenerator } from 'src/graphql/graphql.generator';
|
||||||
|
import { PrismaService } from 'src/prisma/prisma.service';
|
||||||
@Global()
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
providers: [UserSchema],
|
providers: [
|
||||||
|
PrismaService,
|
||||||
|
UserSchema,
|
||||||
|
{
|
||||||
|
provide: Builder,
|
||||||
|
useFactory: (prisma: PrismaService) => new Builder(prisma),
|
||||||
|
inject: [PrismaService],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: PrismaCrudGenerator,
|
||||||
|
inject: [
|
||||||
|
{
|
||||||
|
token: Builder,
|
||||||
|
optional: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
useFactory: (builder: Builder) =>
|
||||||
|
new PrismaCrudGenerator<BuilderTypes>(builder),
|
||||||
|
},
|
||||||
|
],
|
||||||
exports: [UserSchema],
|
exports: [UserSchema],
|
||||||
})
|
})
|
||||||
export class UserModule {}
|
export class UserModule {}
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ export class UserSchema extends PothosSchema {
|
|||||||
email: t.exposeString('email'),
|
email: t.exposeString('email'),
|
||||||
phoneNumber: t.exposeString('phoneNumber'),
|
phoneNumber: t.exposeString('phoneNumber'),
|
||||||
oauthToken: t.exposeString('oauthToken', { nullable: true }),
|
oauthToken: t.exposeString('oauthToken', { nullable: true }),
|
||||||
role: t.exposeString('role'),
|
// role: t.exposeString('role'),
|
||||||
createdAt: t.expose('createdAt', { type: 'Date' }),
|
createdAt: t.expose('createdAt', { type: 'DateTime' }),
|
||||||
updatedAt: t.expose('updatedAt', { type: 'Date' }),
|
updatedAt: t.expose('updatedAt', { type: 'DateTime' }),
|
||||||
center: t.relation('center'),
|
center: t.relation('center'),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -41,25 +41,12 @@ export class UserSchema extends PothosSchema {
|
|||||||
this.builder.queryFields((t) => ({
|
this.builder.queryFields((t) => ({
|
||||||
users: t.prismaField({
|
users: t.prismaField({
|
||||||
type: [this.user()],
|
type: [this.user()],
|
||||||
args: {
|
args: this.builder.generator.findManyArgs('User'),
|
||||||
skip: t.arg.int(),
|
|
||||||
take: t.arg.int(),
|
|
||||||
cursor: t.arg.string(),
|
|
||||||
where: t.arg.string(),
|
|
||||||
orderBy: t.arg.string(),
|
|
||||||
},
|
|
||||||
resolve: async (query, root, args, ctx, info) => {
|
resolve: async (query, root, args, ctx, info) => {
|
||||||
const { skip, take, cursor, where, orderBy } = args;
|
return await this.prisma.user.findMany({
|
||||||
|
...query,
|
||||||
const users = await this.prisma.user.findMany({
|
take: args.take ?? 10,
|
||||||
skip: skip || 0,
|
|
||||||
take: take || 10,
|
|
||||||
cursor: cursor ? { id: cursor } : undefined,
|
|
||||||
where: where ? JSON.parse(where) : undefined,
|
|
||||||
orderBy: orderBy ? JSON.parse(orderBy) : undefined,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return users;
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|||||||
@@ -27,13 +27,13 @@ export class WorkshopSchema extends PothosSchema {
|
|||||||
staffId: t.exposeID('staffId'),
|
staffId: t.exposeID('staffId'),
|
||||||
serviceId: t.exposeID('serviceId'),
|
serviceId: t.exposeID('serviceId'),
|
||||||
date: t.expose('date', {
|
date: t.expose('date', {
|
||||||
type: 'Date',
|
type: 'DateTime',
|
||||||
}),
|
}),
|
||||||
createdAt: t.expose('createdAt', {
|
createdAt: t.expose('createdAt', {
|
||||||
type: 'Date',
|
type: 'DateTime',
|
||||||
}),
|
}),
|
||||||
updatedAt: t.expose('updatedAt', {
|
updatedAt: t.expose('updatedAt', {
|
||||||
type: 'Date',
|
type: 'DateTime',
|
||||||
}),
|
}),
|
||||||
service: t.relation('service'),
|
service: t.relation('service'),
|
||||||
workshopOrganization: t.relation('workshopOrganization'),
|
workshopOrganization: t.relation('workshopOrganization'),
|
||||||
|
|||||||
Reference in New Issue
Block a user