Skip to content

Commit

Permalink
Fix handling multiple attribute comments on a single field
Browse files Browse the repository at this point in the history
  • Loading branch information
MichalLytek committed Feb 28, 2024
1 parent a86cef5 commit fc2cd18
Show file tree
Hide file tree
Showing 12 changed files with 121 additions and 54 deletions.
6 changes: 3 additions & 3 deletions experiments/postgres/prisma/generated/client/edge.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions experiments/postgres/prisma/generated/client/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3223,6 +3223,7 @@ export namespace Prisma {
updatedAt: Date
/**
* @TypeGraphQL.omit(input: true)
* @TypeGraphQL.field(name: "isPublished")
*/
published: boolean
title: string
Expand Down
6 changes: 3 additions & 3 deletions experiments/postgres/prisma/generated/client/index.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions experiments/postgres/prisma/generated/client/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ model post {
/// @TypeGraphQL.omit(input: ["create", "update"])
updatedAt DateTime @updatedAt
/// @TypeGraphQL.omit(input: true)
/// @TypeGraphQL.field(name: "isPublished")
published Boolean @default(false)
title String
/// @TypeGraphQL.omit(output: true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@
"default": false,
"isGenerated": false,
"isUpdatedAt": false,
"documentation": "@TypeGraphQL.omit(input: true)"
"documentation": "@TypeGraphQL.omit(input: true)\n@TypeGraphQL.field(name: \"isPublished\")"
},
{
"name": "title",
Expand Down
40 changes: 20 additions & 20 deletions experiments/postgres/prisma/generated/type-graphql/enhance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ function applyTypeClassEnhanceConfig<

const modelsInfo = {
MainUser: ["id", "email", "firstName", "age", "accountBalance", "amount", "role", "grades", "aliases"],
Post: ["uuid", "createdAt", "updatedAt", "published", "title", "content", "authorId", "kind", "metadata"],
Post: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "content", "authorId", "kind", "metadata"],
Category: ["name", "slug", "number"],
Patient: ["firstName", "lastName", "email"],
Movie: ["directorFirstName", "directorLastName", "title"],
Expand Down Expand Up @@ -727,11 +727,11 @@ const inputsInfo = {
MainUserWhereUniqueInput: ["id", "email", "AND", "OR", "NOT", "firstName", "age", "accountBalance", "amount", "role", "grades", "aliases", "clientPosts", "editorPosts"],
MainUserOrderByWithAggregationInput: ["id", "email", "firstName", "age", "accountBalance", "amount", "role", "grades", "aliases", "_count", "_avg", "_max", "_min", "_sum"],
MainUserScalarWhereWithAggregatesInput: ["AND", "OR", "NOT", "id", "email", "firstName", "age", "accountBalance", "amount", "role", "grades", "aliases"],
PostWhereInput: ["AND", "OR", "NOT", "uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata", "author", "editor"],
PostOrderByWithRelationAndSearchRelevanceInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata", "author", "editor", "_relevance"],
PostWhereUniqueInput: ["uuid", "AND", "OR", "NOT", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata", "author", "editor"],
PostOrderByWithAggregationInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata", "_count", "_avg", "_max", "_min", "_sum"],
PostScalarWhereWithAggregatesInput: ["AND", "OR", "NOT", "uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata"],
PostWhereInput: ["AND", "OR", "NOT", "uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata", "author", "editor"],
PostOrderByWithRelationAndSearchRelevanceInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata", "author", "editor", "_relevance"],
PostWhereUniqueInput: ["uuid", "AND", "OR", "NOT", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata", "author", "editor"],
PostOrderByWithAggregationInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata", "_count", "_avg", "_max", "_min", "_sum"],
PostScalarWhereWithAggregatesInput: ["AND", "OR", "NOT", "uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata"],
CategoryWhereInput: ["AND", "OR", "NOT", "name", "slug", "number"],
CategoryOrderByWithRelationAndSearchRelevanceInput: ["name", "slug", "number", "_relevance"],
CategoryWhereUniqueInput: ["categoryCompoundUnique", "AND", "OR", "NOT", "name", "slug", "number"],
Expand Down Expand Up @@ -781,10 +781,10 @@ const inputsInfo = {
MainUserUpdateInput: ["email", "firstName", "age", "accountBalance", "amount", "role", "grades", "aliases", "clientPosts", "editorPosts"],
MainUserCreateManyInput: ["id", "email", "firstName", "age", "accountBalance", "amount", "role", "grades", "aliases"],
MainUserUpdateManyMutationInput: ["email", "firstName", "age", "accountBalance", "amount", "role", "grades", "aliases"],
PostCreateInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "kind", "metadata", "author", "editor"],
PostUpdateInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "kind", "metadata", "author", "editor"],
PostCreateManyInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata"],
PostUpdateManyMutationInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "kind", "metadata"],
PostCreateInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "kind", "metadata", "author", "editor"],
PostUpdateInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "kind", "metadata", "author", "editor"],
PostCreateManyInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata"],
PostUpdateManyMutationInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "kind", "metadata"],
CategoryCreateInput: ["name", "slug", "number"],
CategoryUpdateInput: ["name", "slug", "number"],
CategoryCreateManyInput: ["name", "slug", "number"],
Expand Down Expand Up @@ -850,10 +850,10 @@ const inputsInfo = {
MainUserRelationFilter: ["is", "isNot"],
UserNullableRelationFilter: ["is", "isNot"],
PostOrderByRelevanceInput: ["fields", "sort", "search"],
PostCountOrderByAggregateInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata"],
PostCountOrderByAggregateInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata"],
PostAvgOrderByAggregateInput: ["authorId", "editorId"],
PostMaxOrderByAggregateInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "authorId", "editorId", "kind"],
PostMinOrderByAggregateInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "authorId", "editorId", "kind"],
PostMaxOrderByAggregateInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "authorId", "editorId", "kind"],
PostMinOrderByAggregateInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "authorId", "editorId", "kind"],
PostSumOrderByAggregateInput: ["authorId", "editorId"],
DateTimeWithAggregatesFilter: ["equals", "in", "notIn", "lt", "lte", "gt", "gte", "not", "_count", "_min", "_max"],
BoolWithAggregatesFilter: ["equals", "not", "_count", "_min", "_max"],
Expand Down Expand Up @@ -983,16 +983,16 @@ const inputsInfo = {
NestedBigIntNullableWithAggregatesFilter: ["equals", "in", "notIn", "lt", "lte", "gt", "gte", "not", "_count", "_avg", "_sum", "_min", "_max"],
NestedBytesNullableWithAggregatesFilter: ["equals", "in", "notIn", "not", "_count", "_min", "_max"],
NestedDecimalNullableWithAggregatesFilter: ["equals", "in", "notIn", "lt", "lte", "gt", "gte", "not", "_count", "_avg", "_sum", "_min", "_max"],
PostCreateWithoutAuthorInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "kind", "metadata", "editor"],
PostCreateWithoutAuthorInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "kind", "metadata", "editor"],
PostCreateOrConnectWithoutAuthorInput: ["where", "create"],
PostCreateManyAuthorInputEnvelope: ["data", "skipDuplicates"],
PostCreateWithoutEditorInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "kind", "metadata", "author"],
PostCreateWithoutEditorInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "kind", "metadata", "author"],
PostCreateOrConnectWithoutEditorInput: ["where", "create"],
PostCreateManyEditorInputEnvelope: ["data", "skipDuplicates"],
PostUpsertWithWhereUniqueWithoutAuthorInput: ["where", "update", "create"],
PostUpdateWithWhereUniqueWithoutAuthorInput: ["where", "data"],
PostUpdateManyWithWhereWithoutAuthorInput: ["where", "data"],
PostScalarWhereInput: ["AND", "OR", "NOT", "uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata"],
PostScalarWhereInput: ["AND", "OR", "NOT", "uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "authorId", "editorId", "kind", "metadata"],
PostUpsertWithWhereUniqueWithoutEditorInput: ["where", "update", "create"],
PostUpdateWithWhereUniqueWithoutEditorInput: ["where", "data"],
PostUpdateManyWithWhereWithoutEditorInput: ["where", "data"],
Expand Down Expand Up @@ -1041,10 +1041,10 @@ const inputsInfo = {
ProblemUpsertWithWhereUniqueWithoutCreatorInput: ["where", "update", "create"],
ProblemUpdateWithWhereUniqueWithoutCreatorInput: ["where", "data"],
ProblemUpdateManyWithWhereWithoutCreatorInput: ["where", "data"],
PostCreateManyAuthorInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "editorId", "kind", "metadata"],
PostCreateManyEditorInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "authorId", "kind", "metadata"],
PostUpdateWithoutAuthorInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "kind", "metadata", "editor"],
PostUpdateWithoutEditorInput: ["uuid", "createdAt", "updatedAt", "published", "title", "subtitle", "content", "kind", "metadata", "author"],
PostCreateManyAuthorInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "editorId", "kind", "metadata"],
PostCreateManyEditorInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "authorId", "kind", "metadata"],
PostUpdateWithoutAuthorInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "kind", "metadata", "editor"],
PostUpdateWithoutEditorInput: ["uuid", "createdAt", "updatedAt", "isPublished", "title", "subtitle", "content", "kind", "metadata", "author"],
MovieCreateManyDirectorInput: ["title"],
MovieUpdateWithoutDirectorInput: ["title"],
CreatorUpdateWithoutLikesInput: ["name", "problems"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ export class Post {
})
updatedAt!: Date;

@TypeGraphQL.Field(_type => Boolean, {
nullable: false
})
published!: boolean;

@TypeGraphQL.Field(_type => String, {
Expand Down Expand Up @@ -65,4 +62,11 @@ export class Post {
nullable: false
})
metadata!: Prisma.JsonValue;

@TypeGraphQL.Field(_type => Boolean, {
nullable: false
})
get isPublished(): boolean {
return this.published;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@
"default": false,
"isGenerated": false,
"isUpdatedAt": false,
"documentation": "@TypeGraphQL.omit(input: true)"
"documentation": "@TypeGraphQL.omit(input: true)\n@TypeGraphQL.field(name: \"isPublished\")"
},
{
"name": "title",
Expand Down
1 change: 1 addition & 0 deletions experiments/postgres/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ model post {
/// @TypeGraphQL.omit(input: ["create", "update"])
updatedAt DateTime @updatedAt
/// @TypeGraphQL.omit(input: true)
/// @TypeGraphQL.field(name: "isPublished")
published Boolean @default(false)
title String
/// @TypeGraphQL.omit(output: true)
Expand Down
53 changes: 30 additions & 23 deletions src/generator/dmmf/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const modelAttributeRegex = /(@@TypeGraphQL\.)+([A-z])+(\()+(.+)+(\))+/;
export const fieldAttributeRegex = /(@TypeGraphQL\.)+([A-z])+(\()+(.+)+(\))+/;
export const modelAttributeRegex = /(@@TypeGraphQL\.)+([A-z])+(\()+(.+)+(\))+/g;
export const fieldAttributeRegex = /(@TypeGraphQL\.)+([A-z])+(\()+(.+)+(\))+/g;
export const attributeNameRegex = /(?:\.)+([A-Za-z])+(?:\()+/;
export const attributeArgsRegex = /(?:\()+([A-Za-z])+\:+(.+)+(?:\))+/;

Expand All @@ -12,28 +12,35 @@ export function parseDocumentationAttributes<TData extends object = object>(
expectedAttributeKind === "model"
? modelAttributeRegex
: fieldAttributeRegex;
const attribute = documentation?.match(attributeRegex)?.[0];
const attributeName = attribute?.match(attributeNameRegex)?.[0]?.slice(1, -1);
if (attributeName !== expectedAttributeName) {
return {};
}
const rawAttributeArgs = attribute
?.match(attributeArgsRegex)?.[0]
?.slice(1, -1);
const parsedAttributeArgs: Record<string, unknown> = {};
if (rawAttributeArgs) {
const rawAttributeArgsParts = rawAttributeArgs
.split(":")
.map(it => it.trim())
.map(part => (part.startsWith("[") ? part : part.split(",")))
.flat()
.map(it => it.trim());
const matchResults = documentation?.matchAll(attributeRegex) ?? [];

for (const [attribute] of matchResults) {
const attributeName = attribute
?.match(attributeNameRegex)?.[0]
?.slice(1, -1);
if (attributeName !== expectedAttributeName) {
continue;
}
const rawAttributeArgs = attribute
?.match(attributeArgsRegex)?.[0]
?.slice(1, -1);
const parsedAttributeArgs: Record<string, unknown> = {};
if (rawAttributeArgs) {
const rawAttributeArgsParts = rawAttributeArgs
.split(":")
.map(it => it.trim())
.map(part => (part.startsWith("[") ? part : part.split(",")))
.flat()
.map(it => it.trim());

for (let i = 0; i < rawAttributeArgsParts.length; i += 2) {
const key = rawAttributeArgsParts[i];
const value = rawAttributeArgsParts[i + 1];
parsedAttributeArgs[key] = JSON.parse(value);
for (let i = 0; i < rawAttributeArgsParts.length; i += 2) {
const key = rawAttributeArgsParts[i];
const value = rawAttributeArgsParts[i + 1];
parsedAttributeArgs[key] = JSON.parse(value);
}
}
return parsedAttributeArgs as Partial<TData>;
}
return parsedAttributeArgs as Partial<TData>;

return {};
}
35 changes: 35 additions & 0 deletions tests/regression/__snapshots__/models.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,41 @@ export class User {
"
`;

exports[`models should properly generate object type class for prisma model with multiple attribute comments: User 1`] = `
"import * as TypeGraphQL from \\"type-graphql\\";
import * as GraphQLScalars from \\"graphql-scalars\\";
import { Prisma } from \\"../../../helpers/prisma-client-mock\\";
import { DecimalJSScalar } from \\"../scalars\\";
@TypeGraphQL.ObjectType(\\"User\\", {})
export class User {
@TypeGraphQL.Field(_type => TypeGraphQL.Int, {
nullable: false
})
id!: number;
@TypeGraphQL.Field(_type => Date, {
nullable: false
})
dateOfBirth!: Date;
@TypeGraphQL.Field(_type => String, {
nullable: false
})
name!: string;
balance!: number | null;
@TypeGraphQL.Field(_type => TypeGraphQL.Float, {
nullable: true
})
get accountBalance(): number | null {
return this.balance ?? null;
}
}
"
`;

exports[`models should properly generate object type class for prisma model with native types: NativeTypeModel 1`] = `
"import * as TypeGraphQL from \\"type-graphql\\";
import * as GraphQLScalars from \\"graphql-scalars\\";
Expand Down
18 changes: 18 additions & 0 deletions tests/regression/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,24 @@ describe("models", () => {
expect(userModelTSFile).toMatchSnapshot("User");
});

it("should properly generate object type class for prisma model with multiple attribute comments", async () => {
const schema = /* prisma */ `
model User {
id Int @id @default(autoincrement())
dateOfBirth DateTime
name String
/// @TypeGraphQL.omit(input: true)
/// @TypeGraphQL.field(name: "accountBalance")
balance Float?
}
`;

await generateCodeFromSchema(schema, { outputDirPath });
const userModelTSFile = await readGeneratedFile("/models/User.ts");

expect(userModelTSFile).toMatchSnapshot("User");
});

it("should properly generate object type class for prisma model when simpleResolvers option is enabled", async () => {
const schema = /* prisma */ `
model User {
Expand Down

0 comments on commit fc2cd18

Please sign in to comment.