Git Product home page Git Product logo

prisma-nestjs-graphql's Introduction

prisma-nestjs-graphql

Generate object types, inputs, args, etc. from prisma schema file for usage with @nestjs/graphql module.

Features

  • Generates only necessary imports
  • Combines zoo of nested/nullable filters
  • Does not generate resolvers, since it's application specific

Install

npm install --save-dev prisma-nestjs-graphql

Usage

  1. Add new generator section to schema.prisma file
generator nestgraphql {
    provider = "node node_modules/prisma-nestjs-graphql"
    // for yarn monorepos
    // provider = "prisma-nestjs-graphql"
    output = "../src/@generated"
}
  1. Run prisma generate
npx prisma generate
  1. If your models have Decimal and Json types, you need install:
npm install graphql-type-json prisma-graphql-type-decimal

Or write you own graphql scalar types, read more on docs.nestjs.com.

Generator options

output

Output folder relative to this schema file
Type: string

outputFilePattern

File path and name pattern
Type: string
Default: {model}/{name}.{type}.ts
Possible tokens:

  • {model} Model name in dashed case or 'prisma' if unknown
  • {name} Dashed-case name of model/input/arg without suffix
  • {type} Short type name (model, input, args, output)
  • {plural.type} Plural short type name (models, inputs, enums)

tsConfigFilePath

Path to tsconfig.json (absolute path or relative to current working directory)
Type: string | undefined
Default: tsconfig.json if exists, undefined otherwise

prismaClientImport

The path to use to import the Prisma Client package Type: string | undefined Default: @prisma/client

combineScalarFilters

Combine nested/nullable scalar filters to single
Type: boolean
Default: false

noAtomicOperations

Remove input types for atomic operations
Type: boolean
Default: false

reExport

Create index.ts file with re-export
Type: enum
Values:
None Default, create nothing
Directories Create index file in all root directories
Single Create single index file in output directory
All Create index file in all root directories and in output directory

Example configuration:

generator nestgraphql {
    provider = "node node_modules/prisma-nestjs-graphql"
    output = "../src/@generated"
    reExport = Directories
}

emitSingle

Generate single file with merged classes and enums.
Type: boolean
Default: false

emitCompiled

Emit compiled JavaScript and definitions instead of TypeScript sources, files will be compiled with emitDecoratorMetadata:false, because there is a problem with temporal dead zone when generating merged file.
Type: boolean
Default: false

emitBlocks

Emit only selected blocks. Be aware, that some blocks do depend on others, e.g. one can't emit models without emitting enums.
Type: ("args" | "inputs" | "outputs" | "models" | "enums")[]
Default: ["args", "inputs", "outputs", "models", "enums"]

omitModelsCount

Omit _count field from models.
Type: boolean
Default: false

purgeOutput

Delete all files in output folder.
Type: boolean
Default: false

noTypeId

Disable usage of graphql ID type and use Int/Float for fields marked as @id in schema.
Type: boolean
Default: false

requireSingleFieldsInWhereUniqueInput

When a model *WhereUniqueInput class has only a single field, mark that field as required (TypeScript) and not nullable (GraphQL).
See #58 for more details.
Type: boolean
Default: false
Note: It will break compatiblity between Prisma types and generated classes.

unsafeCompatibleWhereUniqueInput

Set TypeScript property type as non optional for all fields in *WhereUniqueInput classes. See #177 for more details.
Type: boolean
Default: false

useInputType

Since GraphQL does not support input union type, this setting map allow to choose which input type is preferable.

generator nestgraphql {
    useInputType_{typeName}_{property} = "{pattern}"
}

Where:

  • typeName Full name or partial name of the class where need to choose input type.
    Example: UserCreateInput full name, WhereInput partial name, matches UserWhereInput, PostWhereInput, etc.
  • property Property of the class for which need to choose type. Special case name ALL means any / all properties.
  • pattern Part of name (or full) of type which should be chosen, you can use wild card or negate symbols, in this case pattern should starts with match:, e.g. match:*UncheckedCreateInput see outmatch for details.

Example:

export type PostWhereInput = {
  author?: XOR<UserRelationFilter, UserWhereInput>;
};
export type UserRelationFilter = {
  is?: UserWhereInput;
  isNot?: UserWhereInput;
};

export type UserWhereInput = {
  AND?: Enumerable<UserWhereInput>;
  OR?: Enumerable<UserWhereInput>;
  NOT?: Enumerable<UserWhereInput>;
  id?: StringFilter | string;
  name?: StringFilter | string;
};

We have generated types above, by default property author will be decorated as UserRelationFilter, to set UserWhereInput need to configure generator the following way:

generator nestgraphql {
  provider = "node node_modules/prisma-nestjs-graphql"
  output = "../src/@generated"
  useInputType_WhereInput_ALL = "WhereInput"
}
@InputType()
export class PostWhereInput {
  @Field(() => UserWhereInput, { nullable: true })
  author?: UserWhereInput;
}

decorate

Allow to attach multiple decorators to any field of any type.

generator nestgraphql {
    decorate_{key}_type = "outmatch pattern"
    decorate_{key}_field = "outmatch pattern"
    decorate_{key}_from = "module specifier"
    decorate_{key}_name = "import name"
    decorate_{key}_arguments = "[argument1, argument2]"
    decorate_{key}_defaultImport = "default import name" | true
    decorate_{key}_namespaceImport = "namespace import name"
    decorate_{key}_namedImport = "import name" | true
}

Where {key} any identifier to group values (written in flatten style)

  • decorate_{key}_type - outmatch pattern to match class name
  • decorate_{key}_field - outmatch pattern to match field name
  • decorate_{key}_from - module specifier to import from (e.g class-validator)
  • decorate_{key}_name - import name or name with namespace
  • decorate_{key}_defaultImport - import as default
  • decorate_{key}_namespaceImport - use this name as import namespace
  • decorate_{key}_namedImport - named import (without namespace)
  • decorate_{key}_arguments - arguments for decorator (if decorator need to be called as function)
    Special tokens can be used:
    • {propertyType.0} - field's type (TypeScript type annotation)

Example of generated class:

@ArgsType()
export class CreateOneUserArgs {
  @Field(() => UserCreateInput, { nullable: false })
  data!: UserCreateInput;
}

To make it validateable (assuming UserCreateInput already contains validation decorators from class-validator), it is necessary to add @ValidateNested() and @Type() from class-transformer.

decorate_1_type = "CreateOneUserArgs"
decorate_1_field = data
decorate_1_name = ValidateNested
decorate_1_from = "class-validator"
decorate_1_arguments = "[]"
decorate_2_type = "CreateOneUserArgs"
decorate_2_field = data
decorate_2_from = "class-transformer"
decorate_2_arguments = "['() => {propertyType.0}']"
decorate_2_name = Type

Result:

import { ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';

@ArgsType()
export class CreateOneUserArgs {
  @Field(() => UserCreateInput, { nullable: false })
  @ValidateNested()
  @Type(() => UserCreateInput)
  data!: UserCreateInput;
}

Another example:

decorate_2_namespaceImport = "Transform"
decorate_2_name = "Transform.Type"
import * as Transform from 'class-transformer';

@Transform.Type(() => UserCreateInput)
data!: UserCreateInput;

Add @HideField() decorator to nested types:

decorate_3_type = "*CreateNestedOneWithoutUserInput"
decorate_3_field = "!(create)"
decorate_3_name = "HideField"
decorate_3_from = "@nestjs/graphql"
decorate_3_arguments = "[]"

May generate following class:

@Field(() => ProfileCreateWithoutUserInput, { nullable: true })
create?: ProfileCreateWithoutUserInput;

@HideField()
connectOrCreate?: ProfileCreateOrConnectWithoutUserInput;

@HideField()
connect?: ProfileWhereUniqueInput;

graphqlScalars

Allow to set custom graphql type for Prisma scalar type. Format:

graphqlScalars_{type}_name = "string"
graphqlScalars_{type}_specifier = "string"

where {type} is a prisma scalar type name (e.g. BigInt)

Example:

graphqlScalars_BigInt_name = "GraphQLBigInt"
graphqlScalars_BigInt_specifier = "graphql-scalars"

May generate:

import { GraphQLBigInt } from 'graphql-scalars';

export class BigIntFilter {
  @Field(() => GraphQLBigInt, { nullable: true })
  equals?: bigint | number;
}

It will affect all inputs and outputs types (including models).

Documentation and field options

Comments with triple slash will projected to typescript code comments and some @Field() decorator options

For example:

model Product {
  /// Old description
  /// @deprecated Use new name instead
  oldName String
}

May produce:

@ObjectType()
export class Product {
  /**
   * Old description
   * @deprecated Use new name instead
   */
  @Field(() => String, {
    description: 'Old description',
    deprecationReason: 'Use new name instead',
  })
  oldName: string;
}

Field Settings

Special directives in triple slash comments for more precise code generation.

@HideField()

Removes field from GraphQL schema.
Alias: @TypeGraphQL.omit(output: true)

By default (without arguments) field will be decorated for hide only in output types (type in schema).
To hide field in input types add input: true.
To hide field in specific type you can use glob pattern match: string | string[] see outmatch for details.

Examples:

  • @HideField() same as @HideField({ output: true })
  • @HideField({ input: true, output: true })
  • @HideField({ match: 'UserCreate*Input' })
model User {
    id String @id @default(cuid())
    /// @HideField()
    password String
    /// @HideField({ output: true, input: true })
    secret String
    /// @HideField({ match: '@(User|Comment)Create*Input' })
    createdAt DateTime @default(now())
}

May generate classes:

@ObjectType()
export class User {
  @HideField()
  password: string;
  @HideField()
  secret: string;
  @Field(() => Date, { nullable: false })
  createdAt: Date;
}
@InputType()
export class UserCreateInput {
  @Field()
  password: string;
  @HideField()
  secret: string;
  @HideField()
  createdAt: Date;
}

Custom Decorators

Applying custom decorators requires configuration of generator.

generator nestgraphql {
    fields_{namespace}_from = "module specifier"
    fields_{namespace}_input = true | false
    fields_{namespace}_output = true | false
    fields_{namespace}_model = true | false
    fields_{namespace}_defaultImport = "default import name" | true
    fields_{namespace}_namespaceImport = "namespace import name"
    fields_{namespace}_namedImport = true | false
}

Create configuration map in flatten style for {namespace}.
Where {namespace} is a namespace used in field triple slash comment.

fields_{namespace}_from

Required. Name of the module, which will be used in import (class-validator, graphql-scalars, etc.)
Type: string

fields_{namespace}_input

Means that it will be applied on input types (classes decorated by InputType)
Type: boolean
Default: false

fields_{namespace}_output

Means that it will be applied on output types (classes decorated by ObjectType), including models
Type: boolean
Default: false

fields_{namespace}_model

Means that it will be applied only on model types (classes decorated by ObjectType)
Type: boolean
Default: false

fields_{namespace}_defaultImport

Default import name, if module have no namespace.
Type: undefined | string | true
Default: undefined
If defined as true then import name will be same as {namespace}

fields_{namespace}_namespaceImport

Import all as this namespace from module
Type: undefined | string
Default: Equals to {namespace}

fields_{namespace}_namedImport

If imported module has internal namespace, this allow to generate named import,
imported name will be equal to {namespace}, see example of usage
Type: boolean
Default: false

Custom decorators example:

generator nestgraphql {
    fields_Validator_from = "class-validator"
    fields_Validator_input = true
}

model User {
    id Int @id
    /// @Validator.MinLength(3)
    name String
}

May generate following class:

import { InputType, Field } from '@nestjs/graphql';
import * as Validator from 'class-validator';

@InputType()
export class UserCreateInput {
  @Field(() => String, { nullable: false })
  @Validator.MinLength(3)
  name!: string;
}

Custom decorators can be applied on classes (models):

/// @NG.Directive('@extends')
/// @NG.Directive('@key(fields: "id")')
model User {
    /// @NG.Directive('@external')
    id String @id
}

generator nestgraphql {
    fields_NG_from = "@nestjs/graphql"
    fields_NG_output = false
    fields_NG_model = true
}

May generate:

import * as NG from '@nestjs/graphql';

@NG.Directive('@extends')
@NG.Directive('@key(fields: "id")')
export class User {
    @Field(() => ID, { nullable: false })
    @NG.Directive('@external')
    id!: string;

@FieldType()

Allow set custom GraphQL scalar type for field

To override scalar type in specific classes, you can use glob pattern match: string | string[] see outmatch for details.

model User {
    id Int @id
    /// @FieldType({ name: 'Scalars.GraphQLEmailAddress', from: 'graphql-scalars', input: true })
    email String
}

May generate following class:

import { InputType, Field } from '@nestjs/graphql';
import * as Scalars from 'graphql-scalars';

@InputType()
export class UserCreateInput {
  @Field(() => Scalars.GraphQLEmailAddress, { nullable: false })
  email!: string;
}

And following GraphQL schema:

scalar EmailAddress

input UserCreateInput {
    email: EmailAddress!
}

Same field type may be used in different models and it is not convenient to specify every time all options. There is a shortcut:

generator nestgraphql {
    fields_Scalars_from = "graphql-scalars"
    fields_Scalars_input = true
    fields_Scalars_output = true
}

model User {
    id Int @id
    /// @FieldType('Scalars.GraphQLEmailAddress')
    email String
}

The result will be the same. Scalars is the namespace here. Missing field options will merged from generator configuration.

@PropertyType()

Similar to @FieldType() but refer to TypeScript property (actually field too).

To override TypeScript type in specific classes, you can use glob pattern match: string | string[] see outmatch for details.

Example:

generator nestgraphql {
    fields_TF_from = "type-fest"
}

model User {
    id String @id
    /// @PropertyType('TF.JsonObject')
    data Json
}

May generate:

import * as TF from 'type-fest';

@ObjectType()
export class User {
  @Field(() => GraphQLJSON)
  data!: TF.JsonObject;
}

@Directive()

Allow attach @Directive decorator from @nestjs/graphql

GraphQL federation example:

/// @Directive({ arguments: ['@extends'] })
/// @Directive({ arguments: ['@key(fields: "id")'] })
model User {
    /// @Directive({ arguments: ['@external'] })
    id String @id
}

May generate:

@ObjectType()
@Directive('@extends')
@Directive('@key(fields: "id")')
export class User {
  @Field(() => ID, { nullable: false })
  @Directive('@external')
  id!: string;
}

@ObjectType()

Allow rename type in schema and mark as abstract.

Example 1:

// schema.prisma
/// @ObjectType({ isAbstract: true })
model User {
    id Int @id
}
@ObjectType({ isAbstract: true })
export class User {}

Example 2:

// schema.prisma
/// @ObjectType('Human', { isAbstract: true })
model User {
    id Int @id
}
@ObjectType('Human', { isAbstract: true })
export class User {}

Using library in other generators

import { generate } from 'prisma-nestjs-graphql/generate';

Similar Projects

Resources

prisma-nestjs-graphql's People

Contributors

benkroeger avatar bzhn avatar hbriese avatar hetch3t avatar labithiotis avatar sallomendo avatar semantic-release-bot avatar tminnovations avatar unlight avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

prisma-nestjs-graphql's Issues

Feature: Prisma GraphQL with import

The idea would be to copy the way @prisma/client deals to avoid importing files generated through the plugin.

We can leave the files inside a .gitignore to avoid uploading a lot of unnecessary code and calling a module that solves this import.

Example

import {User} from '@ nestjs/prisma-graphql'

@Mutation (() => User)
async user () {}

or

import {UserGraphQL} from '@prisma/client'

@Mutation (() => UserGraphQL)
async user () {}

Rather than

import {User} from '../../../prisma/user/user.model'

@Mutation (() => User)
async user () {}

@unlight

@HideField Imports

Hi there, I was using the package and used /// @HideField() to hide some of my many-to-many relations on one side of the field, but when I hide the field, on generation the type does not get imported, so I have to manually add them after generate. Any solutions?

Error using prisma 2.20

Hello, Thank you for the great package.
With the release of prisma 2.20, trying to generate files with this generator included produces the following error:

Error: 
โœ” Generated Prisma Client (2.20.0) to ./node_modules/@prisma/client in 132ms

AssertionError [ERR_ASSERTION]: Cannot find output of prisma-client-js
    at generate (/home/adriel/Documents/VSCode/nodejs/nestjs/prisma-nest-graphql/node_modules/prisma-nestjs-graphql/index.js:1216:20)
    at Object.onGenerate (/path/to/project/node_modules/prisma-nestjs-graphql/index.js:1309:11)
    at LineStream.<anonymous> (/path/to/project/node_modules/@prisma/generator-helper/dist/generatorHandler.js:13:46)
    at LineStream.emit (events.js:315:20)
    at addChunk (internal/streams/readable.js:309:12)
    at readableAddChunk (internal/streams/readable.js:284:9)
    at LineStream.Readable.push (internal/streams/readable.js:223:10)
    at LineStream.Transform.push (internal/streams/transform.js:166:32)
    at LineStream._pushBuffer (/path/to/project/node_modules/@prisma/generator-helper/dist/byline.js:108:23)
    at LineStream._transform (/path/to/project/node_modules/@prisma/generator-helper/dist/byline.js:100:10)

Only generate model

I only want to generate the model and not all different input types that I may or may not use. Is there a configuration option for that? Because I didnt find one looking at the documentation here. npx prisma generate creates a lot of types although i just want the objects so far

Furthermore, I would like to exclude some fields that are present in the prisma model from the model in typegraphql. I do not want to have the relations.

model User {
  userId             Int                  @id @default(autoincrement()) @map("user_id")
  createdAt          DateTime             @default(dbgenerated("CURRENT_DATE")) @map("created_at") @db.Date
  emailConfirmed     Boolean              @default(false) @map("email_confirmed")
  email              String               @unique @db.VarChar(255)
  ///@HideField({ input: true, output: true })
  password           String
  ///@HideField({ input: true, output: true })
  UserExercise       UserExercise[]
 
  @@map("user_info")
}

creates this user.model.ts

@ObjectType()
export class User {
    @Field(() => ID, {nullable:false})
    userId!: number;

    @Field(() => Date, {nullable:false})
    createdAt!: Date;

    @Field(() => Boolean, {nullable:false,defaultValue:false})
    emailConfirmed!: boolean;

    @Field(() => String, {nullable:false})
    email!: string;

    @HideField()
    password!: string;

    @HideField()
    UserExercise!: Array<UserExercise>;
}

but i do not want the UserExercise field in my ObjectType because if i want to specify the return type of my resolver like this

@Resolver(() => User)
export class UserResolver {
  constructor(private prisma: PrismaService) {}
  async user(): Promise<User> {
  ...
}

The user in Promise is expected to include the referenced UserExercise, which it wont have

Pagination

Hi, awesome package ๐Ÿš€

Is it possible to generate input types for paging with findMany?
Maybe this is already supported but can not find anything in the docs.

Thanks!

The automated release is failing ๐Ÿšจ

๐Ÿšจ The automated release from the master branch failed. ๐Ÿšจ

I recommend you give this issue a high priority, so other packages depending on you can benefit from your bug fixes and new features again.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. Iโ€™m sure you can fix this ๐Ÿ’ช.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here are some links that can help you:

If those donโ€™t help, or if this issue is reporting something you think isnโ€™t right, you can always ask the humans behind semantic-release.


The release 14.1.0 on branch master cannot be published as it is out of range.

Based on the releases published on other branches, only versions within the range >=14.0.1 <14.1.0 can be published from branch master.

The following commits are responsible for the invalid release:

  • ci: Fix compatibility check (97d87cf)
  • feat(custom decorators): New decorate generator setting (c5e14b7)
  • chore: Update packages (21446a2)
  • refactor: Move (d757988)
  • Update README.md (910218a)

Those commits should be moved to a valid branch with git merge or git cherry-pick and removed from branch master with git revert or git reset.

A valid branch could be next.

See the workflow configuration documentation for more details.


Good luck with your project โœจ

Your semantic-release bot ๐Ÿ“ฆ๐Ÿš€

Wrong input data type in nested relation when using `createMany`

Reproduce using the following schema.

schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

generator nestgraphql {
  provider         = "node node_modules/prisma-nestjs-graphql"
  output           = "../src/@generated/prisma-nestjs-graphql"
}

model Post {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  title     String   @db.VarChar(255)
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
}

model Profile {
  id     Int     @id @default(autoincrement())
  bio    String?
  user   User    @relation(fields: [userId], references: [id])
  userId Int     @unique
}

model User {
  id      Int      @id @default(autoincrement())
  email   String   @unique
  name    String?
  posts   Post[]
  profile Profile?
}

The problem is that the mutation input data type for createMany should be the one without the primary key.

Example of an incorrect generated input path.
UserCreateInput >
PostCreateNestedManyWithoutAuthorInput >
PostCreateManyAuthorInputEnvelope >
[PostCreateManyAuthorInput] >
Should be [PostCreateWithoutAuthorInput ] (I think?)

Thank you!

Purging for a new generation

Currently whenever you regenerate, new classes adds in, while old ones stay there, which creates a conflict, so you have to manually remove the generated folder every time.
It would be neat to have a mechanism in place that auto purges the generated folder before each regenertaion.

GroupByArgs not compatible with groupBy prisma method

Hello,
I think I found an issue, unless it works as expected.
I usually directly use the graphql args in the prisma function with no issue.
I decided to test the groupBy method but I find some issues when I try to use the GroupByArgs type const as parameter but I got errors about circular references

This is the code I used

@Mutation(() => User)
  async createUser(
    @Args() params: CreateOneUserArgs,
    @Info() info: GraphQLResolveInfo,
  ) {
    const group: UserGroupByArgs = {
      by: [UserScalarFieldEnum.name],
    };

    this.prismaService.user.groupBy(group);
    const select = new PrismaSelect(info).value;
    params = { ...params, ...select };
    return this.prismaService.user.create(params);
  }

and these are the errors printing (They also show up in the editor) .

src/users/users.resolver.ts:37:5 - error TS2615: Type of property 'AND' circularly references itself in mapped type '{ [K in keyof { AND?: UserScalarWhereWithAggregatesInput[]; OR?: UserScalarWhereWithAggregatesInput[]; NOT?: UserScalarWhereWithAggregatesInput[]; id?: IntWithAggregatesFilter; name?: StringWithAggregatesFilter; profile?: JsonWithAggregatesFilter; }]: Or<...> extends 1 ? { ...; }[K] extends infer TK ? GetHavingField...'.

37     this.prismaService.user.groupBy(group);
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

src/users/users.resolver.ts:37:5 - error TS2615: Type of property 'NOT' circularly references itself in mapped type '{ [K in keyof { AND?: UserScalarWhereWithAggregatesInput[]; OR?: UserScalarWhereWithAggregatesInput[]; NOT?: UserScalarWhereWithAggregatesInput[]; id?: IntWithAggregatesFilter; name?: StringWithAggregatesFilter; profile?: JsonWithAggregatesFilter; }]: Or<...> extends 1 ? { ...; }[K] extends infer TK ? GetHavingField...'.

37     this.prismaService.user.groupBy(group);
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

src/users/users.resolver.ts:37:5 - error TS2615: Type of property 'OR' circularly references itself in mapped type '{ [K in keyof { AND?: UserScalarWhereWithAggregatesInput[]; OR?: UserScalarWhereWithAggregatesInput[]; NOT?: UserScalarWhereWithAggregatesInput[]; id?: IntWithAggregatesFilter; name?: StringWithAggregatesFilter; profile?: JsonWithAggregatesFilter; }]: Or<...> extends 1 ? { ...; }[K] extends infer TK ? GetHavingField...'.

37     this.prismaService.user.groupBy(group);
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

src/users/users.resolver.ts:37:37 - error TS2345: Argument of type 'UserGroupByArgs' is not assignable to parameter of type '{ where?: UserWhereInput; orderBy?: UserOrderByWithAggregationInput[]; by: UserScalarFieldEnum[]; having?: UserScalarWhereWithAggregatesInput; ... 6 more ...; _max?: UserMaxAggregateInput; } & { ...; } & (`Error: Field "${any}" used in "having" needs to be provided in "by".` | [...])'.
  Type 'UserGroupByArgs' is not assignable to type '{ where?: UserWhereInput; orderBy?: UserOrderByWithAggregationInput[]; by: UserScalarFieldEnum[]; having?: UserScalarWhereWithAggregatesInput; ... 6 more ...; _max?: UserMaxAggregateInput; } & { ...; } & [...]'.
    Type 'UserGroupByArgs' is not assignable to type '{ orderBy: Enumerable<UserOrderByWithAggregationInput>; }'.
      Property 'orderBy' is optional in type 'UserGroupByArgs' but required in type '{ orderBy: Enumerable<UserOrderByWithAggregationInput>; }'.

37     this.prismaService.user.groupBy(group);
                                       ~~~~~

[00:22:13] Found 4 errors. Watching for file changes.

Environment

"@prisma/client": "^2.23.0",
"prisma": "^2.23.0",
"prisma-nestjs-graphql": "^12.0.0",
"@nestjs/common": "^7.6.17",
"@nestjs/core": "^7.6.17",
"@nestjs/graphql": "^7.10.6",

@FieldType() always appear on output type

Hello,
I am trying to make a field be an Upload in Input but a string as Output.
unfortunately, using the field output as false, I still get the Upload type on the object.
Here is my prisma schema

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["selectRelationCount", "orderByRelation", "orderByAggregateGroup"]
}

generator nestgraphql {
  provider              = "node node_modules/prisma-nestjs-graphql"
  output                = "../src/graphql"
  fields_Scalars_from   = "graphql-scalars"
  emitSingle            = true
  purgeOutput           = true
  fields_Scalars_input  = true
  fields_Scalars_output = true
  fields_Upload_from    = "graphql-upload"
  fields_Upload_input   = true
  fields_Upload_output  = false
}

model Panneau {
  id           String        @id @default(cuid())
  nom          String
  description  String
  commune      String?
  ville        String
  /// @FieldType('Upload.GraphQLUpload')
  image        String?
  /// @FieldType('Scalars.GraphQLLongitude')
  longitude    Float?
  /// @FieldType('Scalars.GraphQLLatitude')
  latitude     Float?
  /// onDelete(SET_NULL)
  reservations Reservation[]
}

Question: Which versioning system do you use?

Hi!

Thank you for doing a great job, but I would like to ask if you are aware of the SEMVER specification. I saw the version history of the package and there are many MAJOR versions every 2 weeks - 1 month, and that worries me a little.

Do you follow any specifications to define versioning? Thanks.

Roadmap / Todo

  • bug: input arrays filters are not saved to model folder
  • Datefilter should be Date | string | DateTimeFilter
  • No possible GraphQLUnionType as input type - graphql/graphql-js/issues/207
  • Config option to choose between RelationFilter and whereinput author?: XOR<UserRelationFilter, UserWhereInput> (related to GraphQLUnionType)
  • Combine zoo of nested/nullable filters
  • Aggregate API / AggregateXArgs
  • Import custom type (for toPropertyType) for TypeScript type
  • Compatibility of types
  • take default value config (wont do)
  • use case - maintain custom decorators - if decorator is not found do not add (maybe user moved class to src and extended it)
  • keep only graphql type in prop type
  • Get rid of parasite words from class names (unchecked, nested, nullable), create configurable mutate filter
  • Add suffix to class name (e.g. output) only if not found
  • Remove duplicated types
  • ignore field generation #8
  • custom scalar resolver MichalLytek/typegraphql-prisma#21 MichalLytek/typegraphql-prisma#43 prisma/prisma#3102
  • validate config create output file pattern should not contain parent modifier
  • automatic generate validators from IsNumber() IsOptional() db.varchar(30) blocked prisma/prisma#6844
  • emit compiled bundle #15
  • type ekof = keyof typeof ERole; // role type
  • allow to hide fields *count if no fields in class mark class as abstract (will not help) #130
  • bigint, json from https://github.com/urigo/graphql-scalars

v11.1 as a pre-release

Hello, I saw that the version 11.1 was a pre-release.
is there an estimated to when to expect the full release ?
Thank you for your hard work, this is a great library

Question: How should I deal with undefined and null mismatch

I have a User model with an optional(nullable) avatar field:

model User {
    id            String @id @default(cuid())
    name          String
    email         String @unique
    avatar        Bytes?
    /// @HideField()
    password      String
}

and a simple resolver method which gets an user by id:

@Query(() => User, { nullable: true })
user(@Args('id') id: string): Promise<User | null> {
    return this.prisma.user.findUnique({ where: { id } });
}

and I get this error:
image

Am i missing something here or the types are not compatible?

Abstract and renamed @ObjectType('<name>')

Please, I was looking for a option that can rename the generated @ObjectType and possibly turn it into an abstract class({isAbstract: true}).

E.g:

/// @Name: MyGeneratedModel
model MyModel{
  id         Int    @id @default(autoincrement())

Generate something like:

@ObjectType('MyGeneratedModel')
export class MyModel{ }

And I was looking for something similar for creating abstract classes, eg:

/// @IsAbstract
model MyModel{
  id         Int    @id @default(autoincrement())

Generate:

@ObjectType({isAbstract: true})
export class MyModel{ }

Idk if this where implemented, but i couldn't find on the read me.
@unlight if there are such options, please tell me ๐Ÿ™‚

thx

GraphQLError [Object]: Type MoodCount must define one or more fields.

Hi,

I think I found a bug, I'm not sure but this bug is related to a preview feature selectRelationCount.

I think this related to #26.

so I got this error in Terminal.

[
  GraphQLError [Object]: Type MoodCount must define one or more fields.
      at SchemaValidationContext.reportError (/Users/okhatib/Documents/GitHub/Memoire-LLC/backend/node_modules/graphql/type/validate.js:86:19)
      at validateFields (/Users/okhatib/Documents/GitHub/Memoire-LLC/backend/node_modules/graphql/type/validate.js:234:13)
      at validateTypes (/Users/okhatib/Documents/GitHub/Memoire-LLC/backend/node_modules/graphql/type/validate.js:207:7)
      at validateSchema (/Users/okhatib/Documents/GitHub/Memoire-LLC/backend/node_modules/graphql/type/validate.js:52:3)
      at graphqlImpl (/Users/okhatib/Documents/GitHub/Memoire-LLC/backend/node_modules/graphql/graphql.js:79:62)
      at /Users/okhatib/Documents/GitHub/Memoire-LLC/backend/node_modules/graphql/graphql.js:28:59
      at new Promise (<anonymous>)
      at Object.graphql (/Users/okhatib/Documents/GitHub/Memoire-LLC/backend/node_modules/graphql/graphql.js:26:10)
      at GraphQLSchemaFactory.<anonymous> (/Users/okhatib/Documents/GitHub/Memoire-LLC/backend/node_modules/@nestjs/graphql/dist/schema-builder/graphql-schema.factory.js:49:52)
      at Generator.next (<anonymous>)
]
(node:96606) UnhandledPromiseRejectionWarning: Error: Schema generation error (code-first approach)
    at GraphQLSchemaFactory.<anonymous> (/Users/okhatib/Documents/GitHub/Memoire-LLC/backend/node_modules/@nestjs/graphql/dist/schema-builder/graphql-schema.factory.js:51:27)
    at Generator.next (<anonymous>)
    at fulfilled (/Users/okhatib/Documents/GitHub/Memoire-LLC/backend/node_modules/tslib/tslib.js:114:62)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:96606) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 11)
(node:96606) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

my Prisma schema for testing

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["nApi", "selectRelationCount", "filterJson"]
}

generator nestgraphql {
  provider = "node node_modules/prisma-nestjs-graphql"
  output   = "../src/@generated/"
  reExport = All
}

// generator dbml {
//   provider = "prisma-dbml-generator"
// }

generator docs {
  provider = "node node_modules/prisma-docs-generator"
}

enum UserStatus {
  ACTIVE
  FUTURUSER
  INACTIVE
  INVITED
}

enum FriendshipStatus {
  REQUESTED
  ACCEPTED
  REJECTED
}

model User {
  id String @id @default(cuid())

  // Auth Fields
  /// @HideField({  input: true })
  mobileNumber String  @unique
  /// @HideField({  input: true })
  email        String? @unique
  /// @HideField({ output: true, input: true })
  pin          String?

  // Personal Information
  firstName String?
  lastName  String?
  birthday  DateTime?


  // System Data
  /// @HideField({ output: true, input: true })
  status    UserStatus @default(INACTIVE)
  /// @HideField({  input: true })
  createdAt DateTime   @default(now())
  /// @HideField({  input: true })
  updatedAt DateTime   @updatedAt

  //Associated Profile
  /// @HideField({  input: true })
  profile Profile?

  //Associated Image
  /// @HideField({  input: true })
  profileImage UserFile?


  //Friends - relations n-m
  /// @HideField({  input: true })
  friends  User[] @relation("UserFriendsUser", references: [id])
  /// @HideField({ output: true, input: true })
  friendOf User[] @relation("UserFriendsUser", references: [id])

  //FriendsRequest
  /// @HideField({  input: true })
  sentFriendsRequest     FriendRequest[] @relation("UserSendsFriendRequest")
  /// @HideField({  input: true })
  receivesFriendsRequest FriendRequest[] @relation("UserReceivesFriendRequest")

  //parent and child for FUTURE USER
  /// @HideField({ output: true, input: true })
  parent   User?   @relation("UserParentOfUser", fields: [parentId], references: [id])
  /// @HideField({  input: true })
  children User[]  @relation("UserParentOfUser")
  parentId String?

  // Associated Posts - relations 1-n
  /// @HideField({  input: true })
  posts         Post[] @relation("UserAuthorsPost")
  /// @HideField({ output: true, input: true })
  receivedPosts Post[] @relation("userReceivesPosts")

  // Comments
  /// @HideField({ output: true, input: true })
  comments Comment[]

  // created Moods
  /// @HideField({ input: true })
  moods Mood[]

}

model FriendRequest {
  user     User             @relation("UserSendsFriendRequest", fields: [userId], references: [id])
  userId   String
  friend   User             @relation("UserReceivesFriendRequest", fields: [userId], references: [id])
  friendId String
  status   FriendshipStatus

  @@id([userId, friendId])
}

model Profile {
  id String @id @default(cuid())

  // notification Settings
  notificationStatus    Boolean?  @default(true)
  notificationStartTime DateTime?
  notificationEndTme    DateTime?
  currentMode           String?

  //Extras
  /// @HideField({  input: true })
  tos       DateTime @default(now())
  /// @HideField({  input: true })
  createdAt DateTime @default(now())
  /// @HideField({  input: true })
  updatedAt DateTime @updatedAt

  // Relations
  /// @HideField({ output: true, input: true })
  user   User   @relation(fields: [userId], references: [id])
  userId String @unique

}

model Post {
  id String @id @default(cuid())

  // Type - Content
  content  String?
  location Json?
  youtube  String[]
  spotify  String[]

  // Type - Media
  /// @HideField({  input: true })
  media PostFile[]

  // Extras
  /// @HideField({  input: true })
  createdAt DateTime @default(now())
  /// @HideField({  input: true })
  updatedAt DateTime @updatedAt

  // relations with User
  /// @HideField({  input: true })
  author     User   @relation("UserAuthorsPost", references: [id], fields: [authorId])
  authorId   String
  /// @HideField({  input: true })
  receivedBy User[] @relation("userReceivesPosts", references: [id])

  // Publish Options
  receivedAt     DateTime?
  /// @HideField({  input: true })
  receivedMood   Mood?     @relation(fields: [receivedMoodId], references: [id])
  receivedMoodId String?

  // comments
  /// @HideField({  input: true })
  comments Comment[]

}

model Comment {
  id      String @id @default(cuid())
  // Type - Content
  content String


  /// @HideField({  input: true })
  createdAt DateTime @default(now())
  /// @HideField({  input: true })
  updatedAt DateTime @updatedAt


  //ParentPost
  /// @HideField({ output: true, input: true })
  post   Post   @relation(fields: [postId], references: [id])
  postId String


  // Author
  /// @HideField({  input: true })
  author   User   @relation(references: [id], fields: [authorId])
  authorId String
}

model Mood {
  id String @id @default(cuid())

  // Data
  name String

  //Extras
  /// @HideField({  input: true })
  createdAt DateTime @default(now())
  /// @HideField({  input: true })
  updatedAt DateTime @updatedAt

  /// @HideField({ output: true, input: true })
  author   User?   @relation(fields: [authorId], references: [id])
  authorId String?

  // connection to mood
  /// @HideField({ output: true, input: true })
  posts Post[]
}

model PostFile {
  id  String @id
  url String

  //Extras
  /// @HideField({  input: true })
  createdAt DateTime @default(now())
  /// @HideField({  input: true })
  updatedAt DateTime @updatedAt

  /// @HideField({ output: true, input: true })
  post   Post   @relation(fields: [postId], references: [id])
  postId String
}

model UserFile {
  id  String @id
  url String

  //Extras
  /// @HideField({  input: true })
  createdAt DateTime @default(now())
  /// @HideField({  input: true })
  updatedAt DateTime @updatedAt

  /// @HideField({ output: true, input: true })
  user   User   @relation(fields: [userId], references: [id])
  userId String @unique
}

model Notification {
  id      String  @id @default(cuid())
  content String?

}

the problem is here

model Mood {
  id String @id @default(cuid())

  // Data
  name String

  //Extras
  /// @HideField({  input: true })
  createdAt DateTime @default(now())
  /// @HideField({  input: true })
  updatedAt DateTime @updatedAt

  /// @HideField({ output: true, input: true })
  author   User?   @relation(fields: [authorId], references: [id])
  authorId String?

  // connection to mood
  /// @HideField({ output: true, input: true })
  posts Post[]
}

Because posts are hidden in both output and input, it geerate this following type.

import { Field } from '@nestjs/graphql';
import { ObjectType } from '@nestjs/graphql';
import { Int } from '@nestjs/graphql';
import { HideField } from '@nestjs/graphql';

@ObjectType()
export class MoodCount {
    @HideField()
    posts!: number;
}

Dependency on prisma client js generator?

Just added a test for this generator to prisma/e2e-tests (still WIP), and stumbled over the dependency for the prisma-client-js generator. Why does this exist? Or is this only to make sure that on runtime everything works as expected (and using the Prisma Client is possible)?

Optional one-to-many relation generates NON-nullable field

Hi there !
Thank you for this package, it is very helpful.

In my application, I have a User model, which has a relation to Team model. It is a one-to-many relation (users can have a team or not, and teams have 0 or more users) :

image

However, on the generated User GraphQL model, the team and teamId fields are marked as non-nullable :

image

This can lead to errors when querying these fields on users for which they are null.

Is this the intended behaviour ? And if so, could you explain me why ?

Thanks ! โค๏ธ

The automated release is failing ๐Ÿšจ

๐Ÿšจ The automated release from the master branch failed. ๐Ÿšจ

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. Iโ€™m sure you can resolve this ๐Ÿ’ช.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those donโ€™t help, or if this issue is reporting something you think isnโ€™t right, you can always ask the humans behind semantic-release.


The release 11.1.0 on branch master cannot be published as it is out of range.

Based on the releases published on other branches, only versions within the range >=11.0.3 <11.1.0 can be published from branch master.

The following commits are responsible for the invalid release:

  • chore: Fixed ESLint warnings (77aecd6)
  • feat: Apply custom decorators on models (34196b3)
  • chore: Regenerate with prisma 2.21 (2e920ed)
  • chore: Updated dependencies (af3bce4)
  • feat: Alternative default import configuration (4ae1b82)
  • test: Native string should not be imported (2c470f8)
  • refactor: Moved spec files to test folder (aba712c)
  • refactor: Merged get graphql type (82d944c)
  • refactor: Removed unused functions (be70dea)
  • refactor: Small optimization (8c311be)
  • fix: Custom type for output types (c9ae9e9)
  • docs: Custom decorators (d72d390)
  • feat: Custom decorators (b14f0fe)
  • ci: Changed command to more specific (70198db)
  • chore: Updated packages (e232fbb)
  • docs: Updated README (af1ae93)

Those commits should be moved to a valid branch with git merge or git cherry-pick and removed from branch master with git revert or git reset.

A valid branch could be next.

See the workflow configuration documentation for more details.


Good luck with your project โœจ

Your semantic-release bot ๐Ÿ“ฆ๐Ÿš€

The resulting .ts class files are missing the import for the enum, everything else is there ?

I am using 2.0.0 of the library and everything was working great until I tried to use enums, am I missing something or is this a bug.

model Token {
token String @id
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
owner Team @relation(fields: [ownerId], references: [id])
ownerId String
docs CredentialModel[] @relation(name: "docKey")
credentials CredentialModel[] @relation("key")
}

model CredentialModel {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
displayName String
logo String?
key Token @relation(name: "key", fields: [keyId], references: [token])
keyId String
docsKey Token? @relation(name: "docKey", fields: [docKeyId], references: [token])
docKeyId String?
scopes CredentialModelScope[]
precedents CredentialModel[] @relation(name: "precedents", references: [id])
descendants CredentialModel[] @relation(name: "precedents", references: [id])
properties ModelProps[]

owner Team @relation(fields: [ownerId], references: [id])
ownerId String
}

model CredentialModelScope {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
scope String
CredentialModel CredentialModel? @relation(fields: [credentialModelId], references: [id])
credentialModelId String?
}

enum SymanticPropTypes {
Boolean
Collection
Color
DateTime
FixedCollection
Hidden
Json
MultiOptions
Number
Options
String
}

enum EditorUITypes {
Code
}

model ModelPropsUIOptions {
id String @id @default(cuid())
show Boolean
key String
valueAsString String?
valueAsNumber Int?
valueAsBool Boolean?
valueNull Boolean @default(false)
ModelProps ModelProps? @relation(fields: [modelPropsId], references: [id])
modelPropsId String?
}

model ModelPropOptions {
id String @id @default(cuid())
key String
description String?
displayName String?
valueAsString String?
valueAsNumber Int?
valueAsProp ModelProps? @relation(name: "valueAsProp", fields: [valueAsPropId], references: [id])
valueAsPropId String?
valueAsProps ModelProps[]
}

model ModelProps {
id String @id @default(cuid())
displayName String
name String
type SymanticPropTypes
typeOptions ModelPropExtensionData? @relation(fields: [modelPropExtensionDataId], references: [id])
default Json //NodeParameterValue | INodeParameters | INodeParameters[] | NodeParameterValue[];
description String?
uiOptions ModelPropsUIOptions[]
options ModelPropOptions[]
placeholder String?
isWorkerSetting Boolean?
noDataExpression Boolean?
required Boolean?
ModelPropOptions ModelPropOptions[] @relation("valueAsProp")
modelPropExtensionDataId String?
}

model ModelPropExtensionData {
id String @id @default(cuid())
forceEditWindow Boolean?
editor EditorUITypes?
loadOptionsDependsOn String[]
loadOptionsMethod String?
maxValue Int?
minValue Int?
multipleValues Boolean?
multipleValueButtonText String?
numberPrecision Int?
numberStepSize Int?
password Boolean?
rows Int?
ex ModelPropExtensionOptions[]
ModelProps ModelProps[]
}

model ModelPropExtensionOptions {
id String @id @default(cuid())
key String
valueAsString String?
valueAsNumber Int?
valueAsBool Boolean?
valueAsEditor EditorUITypes?
valueAsStrings String[]
ModelPropExtensionData ModelPropExtensionData? @relation(fields: [modelPropExtensionDataId], references: [id])
modelPropExtensionDataId String?
}

Generated input types creates a type mismatch between prisma types and prisma-nestjs-graphql types.

First of all, thank you for creating this helpful plugin, it saves me so much time, and i really like the direction, where it only generates classes and types, with no concerns with the actual resolvers.

As for the bug, take for example this generated create input class:

@InputType()
export class orderCreateWithoutTourInput {
	@Field(() => String, {
		nullable: true,
	})
	id?: string;

	@Field(() => OrderStatusEnum, {
		nullable: true,
	})
	status?: OrderStatusEnum;

	@Field(() => Boolean, {
		nullable: true,
	})
	scheduled?: boolean;

	@Field(() => GraphQLJSON, {
		nullable: true,
	})
	meetingLocation?: object;

	@Field(() => String, {
		nullable: true,
	})
	meetingDate?: Date | string;
}

While the prisma generated types look like this:

export type orderCreateWithoutTourInput = {
    id?: string
    status?: OrderStatusEnum
    scheduled: boolean
    meetingLocation: InputJsonValue
    meetingDate: Date | string
}

The prisma generated types take into account if a field is optional or not, while prisma-nestjs-graphql presumes everything is optional, which in turn creates a type mismatch between the two generated types.

Another thing, with the generated update inputs, you can take advantage of Nestjs mapped types

FEATURE REQUEST: More options for HideField


name: FEATURE REQUEST: More options for HideField
about: "Add more options to Hide Field"


PS: I don't know if there are already a way to do this.

What problem this will Solve

Example: we can use @HideField like this

model Post {
  id        String   @id @default(cuid())
  title     String
  // @HideField({output:false,input:true})
  createdAt DateTime @default(now())
  /// @HideField({output:false,input:true})
  updatedAt DateTime @updatedAt
  body      String
}

But what if we can specify in which Input we want to add the @HideField decorator and have something like that:

model Post {
  id        String   @id @default(cuid())
  title     String
  /// @HideField({output:false,createInput:true,whereInput:false})
  createdAt DateTime @default(now())
  /// @HideField({output:false,createInput:true,whereInput:false})
  updatedAt DateTime @updatedAt
  body      String
}

Results:

\\post-create.input.ts
@InputType()
export class PostCreateInput {
    @Field(() => String, {nullable:true})
    id?: string;

    @Field(() => String, {nullable:false})
    title!: string;

    @HideField()
    createdAt?: Date | string;

    @HideField()
    updatedAt?: Date | string;

    @Field(() => String, {nullable:false})
    body!: string;
}

\\post-where.input.ts
@InputType()
export class PostWhereInput {
    @Field(() => [PostWhereInput], {nullable:true})
    AND?: Array<PostWhereInput>;

    @Field(() => [PostWhereInput], {nullable:true})
    OR?: Array<PostWhereInput>;

    @Field(() => [PostWhereInput], {nullable:true})
    NOT?: Array<PostWhereInput>;

    @Field(() => StringFilter, {nullable:true})
    id?: StringFilter;

    @Field(() => StringFilter, {nullable:true})
    title?: StringFilter;


    // @HideField()
    @Field(() => StringFilter, {nullable:true})
    createdAt?: DateTimeFilter;

    // @HideField()
    @Field(() => StringFilter, {nullable:true})
    updatedAt?: DateTimeFilter;

    @Field(() => StringFilter, {nullable:true})
    body?: StringFilter;
}

Updates with Set property

I'm not sure where to put this as it's not really an issue but a question, so sorry if this is the wrong place.

"message": "Variable \"$roleDetails\" got invalid value \"Stuff thatt should work\" at \"roleDetails.description\"; Expected type \"StringFieldUpdateOperationsInput\" to be an object.",

I recently updated to the latest version of prisma and prisma-nestjs-graphql since then I receive errors on updates where the properties are now of type StringFieldUpdateOperationsInput meaning I have to change all my update operations to have a .set property. Do you have a property to stop this happening or any advice on how to work with updates going forward. I have a not large codebase and the app isn't production ready yet but I just want to know what the advice is for how to deal with this going forward.

Thanking you kindly

It seems that not work when only enum type changes

Hello, it seems that it will not generate the updated enum files (xx.enum.ts in the prisma folder) when only changes the enum type in prisma.schema.

I've tried twice to only change the FileType:

from

enum FileType {
  IMAGE
  VIDEO
  AUDIO
  PDF
  BINARY
}

to

enum FileType {
  IMAGE
  VIDEO
  AUDIO
  DOCUMENT
  BINARY
}

and then ran npx prisma migrate dev, which did not update the file.

Screenshot 2021-08-25 at 21 07 36

file-type.enum.ts:

Screenshot 2021-08-25 at 21 07 05

Export all classes from one file

Currently all the generated classes, have their own files, so the imports can get quite messy pretty quickly, take for example this imported classes:

import { FindManyTourArgs } from 'prisma/@generated/tour/find-many-tour.args';
import { FindOneTourArgs } from 'prisma/@generated/tour/find-one-tour.args';
import { TourCreateInput } from 'prisma/@generated/tour/tour-create.input';
import { TourWhereUniqueInput } from 'prisma/@generated/tour/tour-where-unique.input';

Creating another index.ts file from the @generated folder, to export every class would make this a lot cleaner

Comments in generated types

Is it possible to emit the model descriptions/comments in the generated types?

I mean, they are there in the @Field() annotation but I would require them as pure comment as well so they can be picked up by the NestJS Swagger plugin to have them in the generated docs. Seems like this isn't working, at least not for me.

I tried different combinations of the config but apparently this is not a feature (yet)?

Or is there maybe a way to make swagger pick up the descriptions from the @Field() annotations? ๐Ÿค”

Multiple /// @Validator.** doc lines create multiple imports

Package version: 11.4.0

Reproduction example

Prisma generator:

generator nestgraphql {
  provider = "node node_modules/prisma-nestjs-graphql"
  output   = "./graphql"
  fields_Validator_from  = "class-validator"
  fields_Validator_input = true
}

Prisma model:

model PersonName {
  id         Int    @id @default(autoincrement())
  /// @Validator.MinLength(2)
  /// @Validator.MaxLength(100)
  firstName  String @db.VarChar(100)
  /// @Validator.MinLength(2)
  /// @Validator.MaxLength(100)
  lastName String @default("") @db.VarChar(100)
}

Generated faulty PersonNameCreateInput with multiple imports:

import { Field } from '@nestjs/graphql';
import { InputType } from '@nestjs/graphql';
import * as Validator from 'class-validator';
import * as Validator from 'class-validator';

@InputType()
export class PersonNameCreateInput {
    @Field(() => String, {nullable:false})
    @Validator.MinLength(2)
    @Validator.MaxLength(100)
    firstName!: string;

    @Field(() => String, {nullable:false})
    @Validator.MinLength(2)
    @Validator.MaxLength(100)
    lastName!: string;
}

Expected output in default configuration?

Just added a test for this generator to prisma/e2e-tests (still WIP), and wanted to confirm the output I am seeing (as I do not know much about NestJS):

Is it correct that using this will output 1 folder per model, and 1 prisma folder, all containing a bunch of files?

Thanks.

Emit compiled bundle

People want have single big file with generated classes instead of multiple.
Similar issues: #6 #12

Facts:

  • ts-morph allows to emit compiled file with declarations
  • classes are not hoisted and must be properly sorted to avoid fall into TDZ
  • Unable to maintain it (make manual changes, etc.)

What need to do before:

  • Decouple generation, get rid of dependency of SourceFile in different types of handlers
  • Create helper function to resort classes
  • Emit dts with errors

OrderByInput no longer generated

Prior to the recent version, I was using the generated file for [Type]OrderByInput in my application, such as

import {
  PipelineCreateInput,
  PipelineOrderByInput
} from '../@generated/prisma-graphql/pipeline'

However, now PipelineOrderByInput is no longer generated. The same is true for other types defined in my schema.

Environment

node: v14.15.4
@nestjs/graphql: v9.0.4
prisma: 3.0.2
prisma-nestjs-graphql: v14.1.0

ValidateNested() on nested objects

Hi,
For instance, I have my inputType class:

@InputType()
export class ReadingCreateInput {
  @Field(() => Int, { nullable: false })
  @IsNegative()
  reading!: number;

  @Field(() => Int, { nullable: false })
  previousReading!: number;

  @HideField()
  excessAmount!: number;

  @HideField()
  basicAmount!: number;

  @HideField()
  createdAt?: Date | string;
}

I want to validate the field reading, to do that I need that the args class associated has the decorator @ValidateNested()
Something like this:

@ArgsType()
export class CreateOneReadingArgs {
  @Field(() => ReadingCreateInput, { nullable: false })
  @ValidateNested()
  data!: ReadingCreateInput;
}

Is there a way to set the decorator @ValidateNested() to the @Args() and to any generated nested object, setting a property to the nestgraphql generator?

Include in FindManyXArgs

Hi,

I was wondering if there's a way to add the include argument in the FindManyXArgs.

Something like the one prisma autogenerates

image

Currenty this is what it generates

@ArgsType()
export class FindManyUserArgs {
    @Field(() => UserWhereInput, {nullable:true})
    where?: UserWhereInput;

    @Field(() => [UserOrderByWithRelationInput], {nullable:true})
    orderBy?: Array<UserOrderByWithRelationInput>;

    @Field(() => UserWhereUniqueInput, {nullable:true})
    cursor?: UserWhereUniqueInput;

    @Field(() => Int, {nullable:true})
    take?: number;

    @Field(() => Int, {nullable:true})
    skip?: number;

    @Field(() => [UserScalarFieldEnum], {nullable:true})
    distinct?: Array<keyof typeof UserScalarFieldEnum>;
}

I'd need something like this

@ArgsType()
export class FindManyUserArgs {
    ...
    
   @Field(() => UserIncludeInput, { nullable: true })
   include?: UserIncludeInput;
}

The reason is because I need to run queries like this

image

Thanks in advance!

Prisma generate removes custom FieldType imports

Hi !

I spotted an issue,
When running prisma generate:

  • with a custom FieldType,
  • and the generated files already exists

=> The custom FieldType is not imported

Example
schema.prisma

generator nestgraphql {
  ...
  fields_NestGraphQL_from   = "@nestjs/graphql"
  fields_NestGraphQL_input  = true
  fields_NestGraphQL_output = true
}

model User {
  /// @FieldType('NestGraphQL.Int')
  id Int @id @default(autoincrement())
  ...
}

The first prisma generate is working fine ๐Ÿ‘
A second prisma generate will remove import * as NestGraphQL from '@nestjs/graphql'; from user.model.ts

Can you reproduce this error, or am I doing something wrong ?
Also, is there a way to change a FieldType to one of the built-in @nestjs/graphql without doing all the custom imports ?

It would be nice if we could do:

/// @FieldType('Int')

Then it generates this:

@Field(() => Int, {nullable:false})

Thanks a lot for your help !

emitSingle not importing custom decorators

Hello, great work for the custom decorators feature, thank you it is very helpful.
I have encountered an issue while using the feature though.
When I set the emitSingle value to true, custom decorators are not imported in the single generated file.

Ignore field generation

Hi I want to ignore my password field from generating first, so that I don't have to copy it to my own source set and merge the generated files one by one (I set gitignore on the generated files).

In typegraphql-prisma, you can do this by setting omit:

  /// @TypeGraphQL.omit(output: true)
  password  String

I think it is not that hard to implement ๐Ÿ˜‚

Performance issues.

The project i'm working on, is fairly big, so i have so many models, and relationships.
The generation process produced by this generator takes quite a lot of time(roughly 4 min).
While the generation of prisma client takes almost no time(5s).

I'm not sure how prisma client generation works, or what they are doing differently,
if they use their rust package to generate, or the fact that they are dumping all generated classes on one file, instead of multiple files and folders, like this generator does.
But the time difference between the two is huge.

The big problem actually relies on how much ram the generation process takes, that it kills my docker instance before generating anything. So for now, i only generate and build my project locally.

Prefer use default export

Most files have only one constant (variable). Instead of having to do

import { User } from '@generated/models/user.model.ts'
It would not be preferable

import User from '@generated/models/user.model.ts'
What do you think about this?

In this case, when generating the files, it would only be necessary to add a default export.

Type mismatch: Optional field should have a '?' modifier

Hi,

First thanks for this package !
I am running into a type mismatch with generated optional fields.

Here is my schema.prisma:

model User {
  id              Int       @id @default(autoincrement())
  ...
  member          Member?
}

model Member {
  id                  Int                 @id @default(autoincrement())
  ...
  user                User                @relation(fields: [userId], references: [id])
  userId              Int
}

The generated model looks like:

@ObjectType()
export class User {
  @Field(() => ID, { nullable: false })
  id!: number;

  ...

  @Field(() => Member, { nullable: true })
  member!: Member;
}

If I use this model in a service:

async firstUser(userWhereInput: Prisma.UserWhereInput): Promise<User | null> {
  return this.prisma.user.findFirst({
    where: userWhereInput,
  });
}

I have this typescript error:

TS2739: Type 'User' is missing the following properties from type 'User': member

Shoudn't the generated field have a ? modifier ?

  @Field(() => Member, { nullable: true })
  member?: Member;

Thanks for your help

Release 10 seems to break on prisma 2.18 Release 9 does not

This builds in @9 and emits a full set of files, it takes about 4 minutes

In @10 it takes over 10 minutes and emits empty files for a number of the models

datasource db { provider = "postgresql" url = env("DATABASE_URL") }

model Tracker {
id String @id @default(cuid())
name String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
trackingId String @unique
team Team @relation(fields: [teamId], references: [id])
type TrackerType @default(JSAdHoc)
connector BridgeAppPointer? @relation(fields: [bridgeAppPointerId], references: [id])
metadata Json?
teamId String
bridgeAppPointerId String?
}

enum TrackerType {
JSAdHoc
JSRelated
}

model BridgeApp {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
BridgeAppPointer BridgeAppPointer[]
}

model Project {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

name String
lowerName String

flows Flow[]

UIs UI[]

// This should be a vector image from our library or an SVG upload
logo String?

// Owner of this project
team Team @relation(fields: [teamId], references: [id])
teamId String

pending Boolean @default(true)

@@unique([lowerName, teamId])
}

model UI {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

name String
lowerName String

logo String?

project Project @relation(fields: [projectId], references: [id])
projectId String

data Json

}

model Flow {

id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

name String
lowerName String

logo String?

owner User @relation(fields: [userId], references: [id])
userId String

project Project @relation(fields: [projectId], references: [id])
projectId String

elements Element[]

connections Connection[]

}

model Connection {

id String @id @default(cuid())

createdAt DateTime @default(now())

updatedAt DateTime @updatedAt

source Element @relation(fields: [sourceId], references: [id], name: "sourceConnection")
sourceId String

target Element @relation(fields: [targetId], references: [id], name: "targetConnection")
targetId String

flow Flow @relation(fields: [flowId], references: [id])
flowId String

Element Element? @relation(fields: [elementId], references: [id])
elementId String?
}

enum ProfileVisibility {
// The profile is indexed and visible
Indexable
// The profile is visible but has a no-robots header
Visibile
// The profile is not linked on the website but is reachable
Hidden
// The profile is visible only to members of doFlo and your team
Blocked
}

model DeveloperProgram {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String
logo String?
bio String?
slug TokenUsage? @relation(fields: [tokenUsageUsageId], references: [usageId])
visibility ProfileVisibility @default(Indexable)
BuildConnector BuildConnector[]
Team Team[] @relation("developerProgram")
tokenUsageUsageId String?
}

enum HostType {
GitHub
GitLab
AzureCI
BitBucket
}

// This is essentially source control repo provider ie. github, gitlab, azure pipelines
model BuildConnector {
appId Int
installId Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
type HostType @default(GitHub)
devProgram DeveloperProgram? @relation(fields: [developerProgramId], references: [id])
account String?
accountName String?
accountType String?
logo String?
repos Repo[]

@@id([appId, installId])
developerProgramId String?
}

model Repo {
// full repo name
id String @id
ext_id String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
namespace Namespace? @relation(fields: [namespaceId], references: [id])
actions BuildAction[]
BuildConnector BuildConnector? @relation(fields: [buildConnectorAppId, buildConnectorInstallId], references: [appId, installId])
buildConnectorAppId Int?
buildConnectorInstallId Int?
namespaceId String?
}

enum BuildStatus {

// Initial Status
Starting

Building

Publishing

// Build & Publish Completed Status - end of live life cycle = good
Completed

// Optimization step where we dump the pulsar log to S3 and future
CompressingLog

// Build & Publish Completed Status - end of live life cycle = bad
Failed

}

model BuildAction {
df_sha String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
status BuildStatus
output BuildOutput @relation(fields: [buildOutputId], references: [id])
Repo Repo? @relation(fields: [repoId], references: [id])
repoId String?
buildOutputId String
}

model BuildOutput {
id String @id @default(cuid())
annotations BuildAnnotation[]
title String?
summary String?
BuildAction BuildAction[]
}

model BuildAnnotation {
id String @id @default(cuid())
title String?
summary String?
lineNumber Int?
colStart Int?
colEnd Int?
BuildOutput BuildOutput? @relation(fields: [buildOutputId], references: [id])
buildOutputId String?
}

model PartnerProgram {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String
logo String?
bio String?
slug TokenUsage? @relation(fields: [tokenUsageUsageId], references: [usageId])
visibility ProfileVisibility @default(Indexable)
Team Team[] @relation("partnerProgram")
tokenUsageUsageId String?
}

model AffiliateProgram {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String
logo String?
bio String?
slug TokenUsage? @relation(fields: [tokenUsageUsageId], references: [usageId])
visibility ProfileVisibility @default(Indexable)
Team Team[] @relation("affiliateProgram")
tokenUsageUsageId String?
}

enum FlowSharingScheme {
// Only owners can see new flows
OwnersOnly
// Team can view
View
// Team can invoke
Invoke
// Team can edit
Edit
}

enum ProjectSharingScheme {
// Only owners can see new projects
OwnersOnly
// Team can view new project
TeamVisible
}

model Team {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String
logo String?

/// This maping does not include role information
users User[] @relation("teamMembership")

/// This is the key for the developer program
developerProgram DeveloperProgram? @relation("developerProgram", fields: [developerProgramId], references: [id])

/// This is the key for the partner program
partnerProgram PartnerProgram? @relation("partnerProgram", fields: [partnerProgramId], references: [id])

/// This is the key for the affiliate program
affiliateProgram AffiliateProgram? @relation("affiliateProgram", fields: [affiliateProgramId], references: [id])

teamSize String?

flowSharingScheme FlowSharingScheme? @default(value: OwnersOnly)

projectSharingScheme ProjectSharingScheme? @default(value: OwnersOnly)

/// Credentials owned by this team
credentials Credential[]

projects Project[]
lastUsers User[] @relation("lastTeamId")

/// Tokens Owned Directly by this team
Token Token[]

/// Models Owned by This team ( As Developers )
/// CredentialModel CredentialModel[]

/// Trackers Owned by This team ( As Users )
Trackers Tracker[]

/// Namespaces Owned by This team ( As Developers )
Namespaces Namespace[]
CredentialModel CredentialModel[]
developerProgramId String?
partnerProgramId String?
affiliateProgramId String?
}

model User {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

username String @unique

/// Profile email address of the user
email String?

/// Full name of the user
name String?

/// Last team the user selected in the UI
lastTeam Team? @relation(name: "lastTeamId", fields: [lastTeamId], references: [id])

lastTeamId String?

role String?

/// Profile picture URL
picture String?

/// Profile picture URL
remotePicture String?

credentials Credential[]

flows Flow[]

teams Team[] @relation("teamMembership")

}

/// Root Element Type (Workers / Signals)
model Element {

id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
credentials ElementPointer[]

targets Connection[] @relation("sourceConnection")

sources Connection[] @relation("targetConnection")

Flow Flow? @relation(fields: [flowId], references: [id])
flowId String?

Connection Connection[]
}

// /// Instance of a credential
model Credential {

id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

/// Credential Model
type CredentialModel? @relation(fields: [modelId], references: [id])
modelId String?

data Json?

user User? @relation(fields: [userId], references: [id])
userId String?

team Team? @relation(fields: [teamId], references: [id])
teamId String?

ElementModel ElementModel? @relation(fields: [elementModelId], references: [id])
elementModelId String?
ElementPointer ElementPointer[]
BridgeAppPointer BridgeAppPointer[]
}

enum ResourceType {

DeveloperSlug

PartnerSlug

AffiliateSlug

Namespace

}

model TokenUsage {

usageId String @id @default(cuid())

createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

token Token @relation(name: "primaryToken", fields: [token_slug], references: [token])
token_slug String

nextToken Token? @relation(name: "nextToken", fields: [next_token_slug], references: [token])
next_token_slug String?

usage ResourceType

DeveloperProgram DeveloperProgram[]
PartnerProgram PartnerProgram[]
AffiliateProgram AffiliateProgram[]
Namespace Namespace[]
}

model Namespace {

id String @id @default(uuid())

key TokenUsage? @relation(fields: [tokenUsageUsageId], references: [usageId])

createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

name String
description String?

logo String?

credentials CredentialModel[] @relation(name: "credentialKey")

elements ElementModel[] @relation(name: "elementKey")

bridgeApps BridgeAppModel[] @relation(name: "bridgeAppKey")

owner Team @relation(fields: [teamId], references: [id])

Repo Repo[]
tokenUsageUsageId String?
teamId String
}

model Token {
token String @id

createdAt DateTime @default(now())

updatedAt DateTime @updatedAt

owner Team @relation(fields: [ownerId], references: [id])

ownerId String

usages TokenUsage[] @relation(name: "primaryToken")

nextUsages TokenUsage[] @relation(name: "nextToken")

}

model BridgeAppModel {
id String @id @default(cuid())

displayName String
logo String?

/// DFRN:[namespace]/bridgeapp/[name]/latest/:[instance]
/// DFRN:[namespace]/bridgeapp/[name]/[semVer]/:[instance]?ch=stage - instance as tranlated via specific model version
/// DFRN:[namespace]/bridgeapp/[name]/[semVer]/:[instance]?ch=dev-00000000-0000-0000-0000-000000000000 == unique dev channel
/// DFRN:[namespace]/bridgeapp/[name]/[semVer]/:[instance] == prod
/// DFRN:[namespace]/bridgeapp/[name]/[semVer]/
key Namespace @relation(name: "bridgeAppKey", fields: [keyId], references: [id])
keyId String

name String

major Int @default(0)
minor Int @default(0)
patch Int @default(1)

/// Primary chanes are Prod, Stage, Adhoc Dev-{branch} are supported for message routing back to the developer
channel String

/// This is the key to the URL as well as Contentful for the purposes of help docs - this is almost always the same as the key and thus can be left blank
// docsKey TokenUsage? @relation(name: "bridgeAppDocKey", fields: [docKeyId], references: [usageId])
// docKeyId String?

/// This is the #hash target with in potentially larger documentation setups
docTarget String?
/// This is the key to the URL as well as Contentful for the purposes of help docs
// docsKey Token? @relation(name: "bridgeAppDocKey", fields: [docKeyId], references: [token])
// docKeyId String?

/// This is the #hash target with in potentially larger documentation setups
/// docTarget String?

/// Global credential instances associated to elements of this model type
/// credentialInstances Credential[]

/// Available credential types for this element type
/// credentials ModelPointer[]

/// Instances of this type
/// instances BridgeAppPointer[]

/// BridgeAppModelPointer BridgeAppModelPointer[]
BridgeAppModelPointer BridgeAppModelPointer[]
BridgeAppPointer BridgeAppPointer[]
}

model ElementModel {

id String @id @default(cuid())

displayName String
logo String?

key Namespace @relation(name: "elementKey", fields: [keyId], references: [id])
keyId String

major Int @default(0)
minor Int @default(0)
patch Int @default(1)

/// Primary chanes are Prod, Stage, Adhoc Dev-{branch} are supported for message routing back to the developer
channel String

/// This is the key to the URL as well as Contentful for the purposes of help docs
// docsKey TokenUsage? @relation(name: "elementDocKey", fields: [docKeyId], references: [usageId])
// docKeyId String?

/// This is the #hash target with in potentially larger documentation setups
docTarget String?

/// Global credential instances associated to elements of this model type
credentialInstances Credential[]

/// Available credential types for this element type
credentials ModelPointer[]

/// Instances of this type
instances ElementPointer[]

}

model ModelPointer {

id String @id @default(cuid())

credentialModel CredentialModel? @relation(fields: [credentialModelId], references: [id])
credentialModelId String?

elementModel ElementModel? @relation(fields: [elementModelId], references: [id])
elementModelId String?

required Boolean @default(false)

}

model BridgeAppModelPointer {

id String @id @default(cuid())

credentialModel CredentialModel? @relation(fields: [credentialModelId], references: [id])
credentialModelId String?

bridgeAppModel BridgeAppModel? @relation(fields: [bridgeAppModelId], references: [id])
bridgeAppModelId String?

}

model ElementPointer {

id String @id @default(cuid())

credential Credential? @relation(fields: [credentialId], references: [id])
credentialId String?

element Element? @relation(fields: [elementId], references: [id])
elementId String?

ElementModel ElementModel? @relation(fields: [elementModelId], references: [id])
elementModelId String?

selected Boolean @default(false)

}

model BridgeAppPointer {
id String @id @default(cuid())

credential Credential? @relation(fields: [credentialId], references: [id])
credentialId String?

bridgeApp BridgeApp? @relation(fields: [bridgeAppId], references: [id])
bridgeAppId String?

bridgeAppModel BridgeAppModel? @relation(fields: [bridgeAppModelId], references: [id])
bridgeAppModelId String?
Tracker Tracker[]
}

/// Model of a credential
model CredentialModel {

id String @id @default(cuid())

/// Is this credential visible in the UI
hidden Boolean

/// this is the default active credential in its channel, there can be only one per channel
latest Boolean?

/// This value is very rarely used, (in the back end admin and status pages... at least so far)
displayName String

/// URL that points to cloudinary
logo String?

/// DFRN:[token]/credentials/[name]/latest/:[instance]
/// DFRN:[token]/credentials/[name]/[semVer]/:[instance]?ch=stage - instance as tranlated via specific model version
/// DFRN:[token]/credentials/[name]/[semVer]/:[instance]?ch=dev-00000000-0000-0000-0000-000000000000 == unique dev channel
/// DFRN:[token]/credentials/[name]/[semVer]/:[instance] == prod
/// DFRN:[token]/credentials/[name]/[semVer]/
key Namespace @relation(name: "credentialKey", fields: [keyId], references: [id])
keyId String

name String

major Int @default(0)
minor Int @default(0)
patch Int @default(1)

/// Primary chanes are Prod, Stage, Adhoc Dev-{branch} are supported for message routing back to the developer
channel String

/// This is the key to the URL as well as Contentful for the purposes of help docs - this is almost always the same as the key and thus can be left blank
// docsKey TokenUsage? @relation(name: "credentialDocKey", fields: [docKeyId], references: [usageId])
// docKeyId String?

/// This is the #hash target with in potentially larger documentation setups
docTarget String?

precedents CredentialModel[] @relation(name: "precedents", references: [id])
descendants CredentialModel[] @relation(name: "precedents", references: [id])

createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

ownerTeam Team @relation(fields: [ownerTeamId], references: [id])
ownerTeamId String

/// Model of the credential
model Json

/// Available Elements
elements ModelPointer[]

/// Available Bridge Apps
bridgeApps BridgeAppModelPointer[]

/// Derived Credentials
credentials Credential[]

@@unique([keyId, name, channel, major, minor, patch])
@@unique([keyId, name, channel, latest])
}

Generate `ArgsTypes` without foreign relations in an input?

Take this generated ArgsTypes class as an example.

@ArgsType()
export class CreateOneTagArgs {
@Field(() => TagCreateInput, { nullable: false })
data!: TagCreateInput;
}

Here the TagCreateInput type permits creation of articles, which may be undesirable. Unfortunately there doesn't seem to be a class generated that would use TagCreateWithoutArticlesInput class:

@InputType()
export class TagCreateWithoutArticlesInput {
@Field(() => String, { nullable: true })
id?: string;
@Field(() => String, { nullable: false })
name!: string;
}

Would it be possible to add generation of such ArgsTypes classes for Create and Update cases respectively?

P.S. Ideally, a class TagCreateWithoutIdAndArticlesInput would be generated for such purpose, because it might be undesirable to allow updating of id fields.

Merge multiple imports

Hello,

the autogenerated files seem to have seperated imports from the same package, which violets the eslint rule, though it's not a big issue with just format on save to organize imports. But it will be better to be organized by default as unlikely to edit these files.

Screenshot 2021-08-15 at 21 09 28

Screenshot 2021-08-15 at 21 15 29

Validator not used in emitSingle when imported

Hello again,
thanks for the quick fix.
The import are now done, however the decorators do not use the imported namespace above the fields.
By that I mean the decorators are @IsEmail() instead of @Validator.IsEmail()

import * as Scalars from 'graphql-scalars';
import * as Validator from 'class-validator';

@InputType()
export class UserUncheckedCreateInput {
  @Field(() => String, { nullable: true })
  id?: string;
  @Field(() => String, { nullable: false })
  name!: string;
  @Field(() => Scalars.GraphQLEmailAddress, { nullable: false })
  @IsEmail()
  email!: string;
}

instead of

import * as Scalars from 'graphql-scalars';
import * as Validator from 'class-validator';

@InputType()
export class UserUncheckedCreateInput {
  @Field(() => String, { nullable: true })
  id?: string;
  @Field(() => String, { nullable: false })
  name!: string;
  @Field(() => Scalars.GraphQLEmailAddress, { nullable: false })
  @Validator.IsEmail()
  email!: string;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.