Skip to content

Commit

Permalink
Support adding decorators for input types and args type classes
Browse files Browse the repository at this point in the history
  • Loading branch information
MichalLytek committed Feb 10, 2021
1 parent dd60ace commit 036c399
Show file tree
Hide file tree
Showing 7 changed files with 347 additions and 36 deletions.
22 changes: 22 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,28 @@ applyOutputTypeEnhanceMap({
});
```

If you want to add decorators for input types or args classes, you can leverage `applyArgsTypesEnhanceMap` and `applyInputTypesEnhanceMap` functions and use `ArgsTypesEnhanceMap`, `ArgConfig<TArgsType>`, `InputTypesEnhanceMap`, `InputTypeConfig<TInput>` types if you want to split the definitions:

```ts
applyArgsTypesEnhanceMap({
CreateProblemArgs: {
fields: {
data: [ValidateNested()],
},
},
});

applyInputTypesEnhanceMap({
ProblemCreateInput: {
fields: {
problemText: [MinLength(10)],
},
},
});
```

Be aware that in case of `class-validator` you need to add `@ValidateNested` decorator to the args classes to trigger validation of the proper input types.

#### Adding fields to model type

If you want to add a field to the generated type like `User`, you have to add a proper `@FieldResolver` for that:
Expand Down
27 changes: 23 additions & 4 deletions experiments/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from "type-graphql";
import { ApolloServer } from "apollo-server";
import path from "path";
import { MinLength, ValidateNested } from "class-validator";

import {
Client,
Expand Down Expand Up @@ -46,6 +47,8 @@ import {
OutputTypeConfig,
GroupByCategoryResolver,
GroupByPostResolver,
applyInputTypesEnhanceMap,
applyArgsTypesEnhanceMap,
} from "./prisma/generated/type-graphql";
import { PrismaClient } from "./prisma/generated/client";
import * as Prisma from "./prisma/generated/client";
Expand Down Expand Up @@ -82,14 +85,30 @@ applyOutputTypesEnhanceMap({
},
});

const problemActionsConfig: ResolverActionsConfig<"Problem"> = {
createProblem: [Authorized()],
applyArgsTypesEnhanceMap({
CreateProblemArgs: {
fields: {
data: [ValidateNested()],
},
},
});

applyInputTypesEnhanceMap({
ProblemCreateInput: {
fields: {
problemText: [MinLength(10)],
},
},
});

const directorActionsConfig: ResolverActionsConfig<"Director"> = {
createDirector: [Authorized()],
};
const resolversEnhanceMap: ResolversEnhanceMap = {
Category: {
categories: [Authorized()],
},
Problem: problemActionsConfig,
Director: directorActionsConfig,
};
applyResolversEnhanceMap(resolversEnhanceMap);

Expand Down Expand Up @@ -160,7 +179,7 @@ async function main() {
GroupByCategoryResolver,
GroupByPostResolver,
],
validate: false,
validate: true,
emitSchemaFile: path.resolve(__dirname, "./generated-schema.graphql"),
authChecker: ({ info }) => {
console.log(
Expand Down
62 changes: 58 additions & 4 deletions experiments/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions experiments/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"devDependencies": {
"@types/graphql-type-json": "^0.3.2",
"@types/node": "^14.14.22",
"class-validator": "^0.13.1",
"prisma": "~2.16.0",
"ts-node": "^9.1.1",
"typescript": "~4.1.3"
Expand Down
84 changes: 76 additions & 8 deletions experiments/prisma/generated/type-graphql/enhance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import * as crudResolvers from "./resolvers/crud/resolvers-crud.index";
import * as actionResolvers from "./resolvers/crud/resolvers-actions.index";
import * as models from "./models";
import * as outputTypes from "./resolvers/outputs";
import * as inputTypes from "./resolvers/inputs";
import * as argsTypes from "./resolvers/crud/args.index";

const crudResolversMap = {
Client: crudResolvers.ClientCrudResolver,
Expand Down Expand Up @@ -183,7 +185,7 @@ type FieldsConfig<TTypeKeys extends string = string> = Partial<
Record<TTypeKeys, PropertyDecorator[]>
>;

export function applyTypeClassEnhanceConfig<
function applyTypeClassEnhanceConfig<
TEnhanceConfig extends TypeConfig,
TType extends object
>(
Expand Down Expand Up @@ -241,22 +243,22 @@ export function applyModelsEnhanceMap(modelsEnhanceMap: ModelsEnhanceMap) {

type OutputTypesNames = keyof typeof outputTypes;

type OutputTypeFieldNames<TModel extends OutputTypesNames> = Exclude<
keyof typeof outputTypes[TModel]["prototype"],
type OutputTypeFieldNames<TOutput extends OutputTypesNames> = Exclude<
keyof typeof outputTypes[TOutput]["prototype"],
number | symbol
>;

export type OutputTypeFieldsConfig<
TModel extends OutputTypesNames
> = FieldsConfig<OutputTypeFieldNames<TModel>>;
TOutput extends OutputTypesNames
> = FieldsConfig<OutputTypeFieldNames<TOutput>>;

export type OutputTypeConfig<TModel extends OutputTypesNames> = {
export type OutputTypeConfig<TOutput extends OutputTypesNames> = {
class?: ClassDecorator[];
fields?: OutputTypeFieldsConfig<TModel>;
fields?: OutputTypeFieldsConfig<TOutput>;
};

export type OutputTypesEnhanceMap = {
[TModel in OutputTypesNames]?: OutputTypeConfig<TModel>;
[TOutput in OutputTypesNames]?: OutputTypeConfig<TOutput>;
};

export function applyOutputTypesEnhanceMap(
Expand All @@ -271,6 +273,72 @@ export function applyOutputTypesEnhanceMap(
}
}

type InputTypesNames = keyof typeof inputTypes;

type InputTypeFieldNames<TInput extends InputTypesNames> = Exclude<
keyof typeof inputTypes[TInput]["prototype"],
number | symbol
>;

export type InputTypeFieldsConfig<
TInput extends InputTypesNames
> = FieldsConfig<InputTypeFieldNames<TInput>>;

export type InputTypeConfig<TInput extends InputTypesNames> = {
class?: ClassDecorator[];
fields?: InputTypeFieldsConfig<TInput>;
};

export type InputTypesEnhanceMap = {
[TInput in InputTypesNames]?: InputTypeConfig<TInput>;
};

export function applyInputTypesEnhanceMap(
inputTypesEnhanceMap: InputTypesEnhanceMap,
) {
for (const inputTypeEnhanceMapKey of Object.keys(inputTypesEnhanceMap)) {
const inputTypeName = inputTypeEnhanceMapKey as keyof typeof inputTypesEnhanceMap;
const typeConfig = inputTypesEnhanceMap[inputTypeName]!;
const typeClass = inputTypes[inputTypeName];
const typeTarget = typeClass.prototype;
applyTypeClassEnhanceConfig(typeConfig, typeClass, typeTarget);
}
}

type ArgsTypesNames = keyof typeof argsTypes;

type ArgFieldNames<TArgsType extends ArgsTypesNames> = Exclude<
keyof typeof argsTypes[TArgsType]["prototype"],
number | symbol
>;

type ArgFieldsConfig<
TArgsType extends ArgsTypesNames
> = FieldsConfig<ArgFieldNames<TArgsType>>;

export type ArgConfig<TArgsType extends ArgsTypesNames> = {
class?: ClassDecorator[];
fields?: ArgFieldsConfig<TArgsType>;
};

export type ArgsTypesEnhanceMap = {
[TArgsType in ArgsTypesNames]?: ArgConfig<TArgsType>;
};

export function applyArgsTypesEnhanceMap(
argsTypesEnhanceMap: ArgsTypesEnhanceMap,
) {
for (const argsTypesEnhanceMapKey of Object.keys(argsTypesEnhanceMap)) {
const argsTypeName = argsTypesEnhanceMapKey as keyof typeof argsTypesEnhanceMap;
const typeConfig = argsTypesEnhanceMap[argsTypeName]!;
const typeClass = argsTypes[argsTypeName];
const typeTarget = typeClass.prototype;
applyTypeClassEnhanceConfig(typeConfig, typeClass, typeTarget);
}
}






Loading

0 comments on commit 036c399

Please sign in to comment.