@nest-arch/tui 0.2.8 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +20 -42
  2. package/dist/cli.js +1 -1
  3. package/dist/constants-B5MuV-iH.js +1 -0
  4. package/dist/index.js +365 -98
  5. package/dist/templates/addons/husky/pre-commit.hbs +11 -26
  6. package/dist/templates/base/.env.example.hbs +13 -2
  7. package/dist/templates/base/.env.hbs +11 -2
  8. package/dist/templates/base/.gitignore.hbs +2 -1
  9. package/dist/templates/base/.yarnrc.yml.hbs +0 -5
  10. package/dist/templates/base/README.md.hbs +49 -5
  11. package/dist/templates/base/nest-cli.json.hbs +2 -1
  12. package/dist/templates/base/pnpm-workspace.yaml.hbs +15 -0
  13. package/dist/templates/base/prisma.config.ts.hbs +32 -6
  14. package/dist/templates/base/src/app.controller.spec.ts.hbs +3 -11
  15. package/dist/templates/base/src/app.controller.ts.hbs +2 -2
  16. package/dist/templates/base/src/app.module.ts.hbs +76 -5
  17. package/dist/templates/base/src/app.router.ts.hbs +3 -4
  18. package/dist/templates/base/src/database/adapters/interfaces/db-adapter.interface.ts.hbs +7 -0
  19. package/dist/templates/base/src/database/adapters/mongo/prisma-mongo.adapter.ts.hbs +36 -4
  20. package/dist/templates/base/src/database/adapters/mongo/raw-mongo.adapter.ts.hbs +17 -12
  21. package/dist/templates/base/src/database/adapters/sql/drizzle-sql.adapter.ts.hbs +9 -0
  22. package/dist/templates/base/src/database/adapters/sql/prisma-sql.adapter.ts.hbs +8 -5
  23. package/dist/templates/base/src/database/adapters/sql/raw-sql.adapter.ts.hbs +37 -0
  24. package/dist/templates/base/src/database/adapters/sql/typeorm-sql.adapter.ts.hbs +8 -3
  25. package/dist/templates/base/src/database/db.module.ts.hbs +55 -42
  26. package/dist/templates/base/src/database/db.service.ts.hbs +60 -6
  27. package/dist/templates/base/src/database/entities/app.entity.ts.hbs +25 -0
  28. package/dist/templates/base/src/database/entities/todo.entity.ts.hbs +12 -7
  29. package/dist/templates/base/src/database/index.ts.hbs +20 -0
  30. package/dist/templates/base/src/database/orm/drizzle/schema.ts.hbs +80 -7
  31. package/dist/templates/base/src/database/orm/typeorm/data-source.ts.hbs +23 -4
  32. package/dist/templates/base/src/libs/middlewares/auth.trpc.middleware.ts.hbs +47 -0
  33. package/dist/templates/base/src/libs/middlewares/rate-limit.trpc.middleware.ts.hbs +43 -0
  34. package/dist/templates/base/src/libs/trpc/error.handler.ts.hbs +1 -1
  35. package/dist/templates/base/src/libs/trpc/inner.context.ts.hbs +6 -3
  36. package/dist/templates/base/src/main.ts.hbs +34 -10
  37. package/dist/templates/base/src/modules/users/entities/user.entity.ts.hbs +22 -0
  38. package/dist/templates/base/test/app.e2e-spec.ts.hbs +841 -6
  39. package/dist/templates/base/test/bootstrap.e2e-spec.ts.hbs +84 -0
  40. package/dist/templates/base/tsconfig.build.json.hbs +2 -0
  41. package/dist/templates/base/vitest.config.e2e.ts.hbs +4 -3
  42. package/dist/templates/base/vitest.config.ts.hbs +4 -3
  43. package/dist/templates/base/yarn.lock.hbs +1 -0
  44. package/dist/templates/extras/docker/.dockerignore.hbs +8 -1
  45. package/dist/templates/extras/docker/Dockerfile.hbs +11 -10
  46. package/dist/templates/extras/health/src/health/health.controller.ts.hbs +54 -0
  47. package/dist/templates/extras/health/src/health/health.module.ts.hbs +9 -0
  48. package/dist/templates/extras/swagger/create-docs.ts.hbs +13 -22
  49. package/dist/templates/feature/graphql/src/graphql/graphql.module.ts.hbs +6 -10
  50. package/dist/templates/feature/graphql/src/graphql/models/todo.model.ts.hbs +4 -0
  51. package/dist/templates/feature/graphql/src/graphql/orm/drizzle/drizzle-graphql.module.ts.hbs +6 -4
  52. package/dist/templates/feature/graphql/src/graphql/resolvers/health.resolver.ts.hbs +14 -0
  53. package/dist/templates/feature/graphql/src/graphql/resolvers/todo.resolver.ts.hbs +210 -47
  54. package/dist/templates/feature/rest/todo-example/src/api/todo/dto/create-todo.dto.ts.hbs +12 -0
  55. package/dist/templates/feature/rest/todo-example/src/api/todo/dto/update-todo.dto.ts.hbs +12 -0
  56. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.controller.ts.hbs +21 -9
  57. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.module.ts.hbs +1 -3
  58. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.router.ts.hbs +41 -13
  59. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.service.ts.hbs +157 -33
  60. package/dist/templates/monorepo/apps/api-gateway/package.json.hbs +2 -3
  61. package/dist/templates/monorepo/apps/api-gateway/src/app.controller.spec.ts.hbs +6 -1
  62. package/dist/templates/monorepo/apps/api-gateway/src/app.controller.ts.hbs +6 -0
  63. package/dist/templates/monorepo/apps/api-gateway/src/app.module.ts.hbs +32 -1
  64. package/dist/templates/monorepo/apps/api-gateway/src/app.service.ts.hbs +1 -1
  65. package/dist/templates/monorepo/apps/api-gateway/src/main.ts.hbs +13 -4
  66. package/dist/templates/monorepo/apps/api-gateway/test/app.e2e-spec.ts.hbs +45 -1
  67. package/dist/templates/monorepo/apps/api-gateway/tsconfig.build.json.hbs +2 -1
  68. package/dist/templates/monorepo/apps/api-gateway/vitest.config.e2e.ts.hbs +3 -2
  69. package/dist/templates/monorepo/apps/api-gateway/vitest.config.ts.hbs +3 -2
  70. package/dist/templates/monorepo/feature/graphql/src/graphql/graphql.module.ts.hbs +6 -10
  71. package/dist/templates/monorepo/feature/graphql/src/graphql/resolvers/health.resolver.ts.hbs +14 -0
  72. package/dist/templates/monorepo/feature/graphql/src/graphql/resolvers/todo.resolver.ts.hbs +151 -42
  73. package/dist/templates/monorepo/packages/env/src/api-gateway.ts.hbs +16 -3
  74. package/dist/templates/monorepo/packages/shared/package.json.hbs +1 -0
  75. package/dist/templates/monorepo/packages/shared/src/auth.ts.hbs +6 -0
  76. package/dist/templates/monorepo/root/.gitignore.hbs +1 -0
  77. package/dist/templates/monorepo/root/pnpm-workspace.yaml.hbs +19 -2
  78. package/dist/templates/monorepo/root/tsconfig.json.hbs +1 -1
  79. package/dist/templates/monorepo/root/turbo.json.hbs +2 -0
  80. package/dist/templates/single-project/architecture/nest-api/.env.hbs +9 -1
  81. package/dist/templates/single-project/architecture/nest-api/package.json.hbs +1 -2
  82. package/dist/templates/single-project/architecture/nest-api/src/main.ts.hbs +33 -9
  83. package/dist/templates/single-project/architecture/nest-gateway/src/main.ts.hbs +3 -3
  84. package/dist/templates/single-project/architecture/nest-microservice/.env.hbs +18 -0
  85. package/dist/templates/single-project/architecture/nest-microservice/proto/app.proto.hbs +26 -0
  86. package/dist/templates/single-project/architecture/nest-microservice/src/app.controller.ts.hbs +23 -4
  87. package/dist/templates/single-project/architecture/nest-microservice/src/app.service.ts.hbs +6 -2
  88. package/dist/templates/single-project/architecture/nest-microservice/src/main.ts.hbs +16 -5
  89. package/dist/templates/single-project/architecture/nest-microservice/test/microservice.e2e-spec.ts.hbs +70 -0
  90. package/dist/templates/single-project/shared/config/env.ts.hbs +38 -3
  91. package/package.json +5 -2
  92. package/dist/constants-Cgtoxhmd.js +0 -1
@@ -1,32 +1,76 @@
1
- {{#if (and hasAuth hasDatabase)}}
2
- import { UseGuards } from "@nestjs/common";
3
- {{/if}}
1
+ {{#if (and usePrisma (eq auth "none"))}}
2
+ import { BadRequestException, NotFoundException } from "@nestjs/common";
4
3
  import { Args, Mutation, Query, Resolver } from "@nestjs/graphql";
4
+ import { DbService } from "../../database/db.service.js";
5
+ import { CreateTodoInput } from "../dto/create-todo.input.js";
6
+ import { UpdateTodoInput } from "../dto/update-todo.input.js";
7
+ import { Todo } from "../models/todo.model.js";
8
+
9
+ @Resolver(() => Todo)
10
+ export class TodoResolver {
11
+ constructor(private readonly db: DbService) {}
12
+
13
+ @Query(() => [Todo])
14
+ todos() {
15
+ return this.db.prisma.todo.findMany({ orderBy: { createdAt: "asc" }, take: 100 });
16
+ }
17
+
18
+ @Mutation(() => Todo)
19
+ createTodo(@Args("input") input: CreateTodoInput) {
20
+ if (!input.title.trim()) throw new BadRequestException("Title must not be empty");
21
+ return this.db.prisma.todo.create({ data: input });
22
+ }
23
+
24
+ @Mutation(() => Todo)
25
+ async updateTodo(@Args("input") input: UpdateTodoInput) {
26
+ const { id, ...data } = input;
27
+ if (data.title !== undefined && !data.title.trim()) throw new BadRequestException("Title must not be empty");
28
+ const result = await this.db.prisma.todo.updateManyAndReturn({ where: { id }, data });
29
+ if (!result[0]) throw new NotFoundException("Todo not found");
30
+ return result[0];
31
+ }
32
+
33
+ @Mutation(() => Boolean)
34
+ async deleteTodo(@Args("id") id: string): Promise<boolean> {
35
+ const result = await this.db.prisma.todo.deleteMany({ where: { id } });
36
+ if (result.count === 0) throw new NotFoundException("Todo not found");
37
+ return true;
38
+ }
39
+ }
40
+ {{else}}
5
41
  {{#if (and hasAuth hasDatabase)}}
42
+ import { BadRequestException, NotFoundException, UseGuards } from "@nestjs/common";
6
43
  import { UserEntity } from "../../auth/decorators/index.js";
7
44
  import { GqlAuthGuard } from "../../auth/guards/gql-auth.guard.js";
45
+ {{else}}
46
+ import { BadRequestException, NotFoundException } from "@nestjs/common";
47
+ {{/if}}
48
+ import { Args, Mutation, Query, Resolver } from "@nestjs/graphql";
49
+ {{#if (and hasDatabase useTypeorm)}}
50
+ import { GraphQLResolveInfo } from "graphql";
51
+ import { GraphRelationBuilder } from "typeorm-relations-graphql";
52
+ import { Todo as TodoEntity } from "../../database/entities/todo.entity.js";
53
+ {{/if}}
54
+ {{#if (and hasDatabase useDrizzle)}}
55
+ import { and, eq } from "drizzle-orm";
56
+ import * as schema from "../../database/orm/drizzle/schema.js";
8
57
  {{/if}}
58
+ {{#if hasDatabase}}
9
59
  {{#if isMonorepo}}
10
60
  import { DbService } from "@repo/db";
11
61
  {{else}}
12
62
  import { DbService } from "../../database/db.service.js";
13
63
  {{/if}}
64
+ {{/if}}
14
65
  import { CreateTodoInput } from "../dto/create-todo.input.js";
15
66
  import { UpdateTodoInput } from "../dto/update-todo.input.js";
16
- {{#if useTypeorm}}
17
- import { GraphRelationBuilder } from "typeorm-relations-graphql";
18
- import { GraphQLResolveInfo } from "graphql";
19
- {{/if}}
20
- {{#if useDrizzle}}
21
- import * as schema from "../../database/orm/drizzle/schema.js";
22
- {{/if}}
23
- {{#if (and hasAuth hasDatabase)}}
24
67
  import { Todo } from "../models/todo.model.js";
25
- {{/if}}
26
68
 
27
69
  @Resolver(() => Todo)
28
70
  export class TodoResolver {
71
+ {{#if hasDatabase}}
29
72
  constructor(private readonly db: DbService) {}
73
+ {{/if}}
30
74
 
31
75
  @Query(() => String)
32
76
  hello(): string {
@@ -34,87 +78,206 @@ export class TodoResolver {
34
78
  }{{#if hasDatabase}}
35
79
 
36
80
  @Query(() => [Todo])
37
- todos({{#if useTypeorm}}info: GraphQLResolveInfo{{/if}}) {
81
+ {{#if hasAuth}}
82
+ @UseGuards(GqlAuthGuard)
83
+ {{/if}}
84
+ todos({{#if useTypeorm}}info: GraphQLResolveInfo, {{/if}}{{#if hasAuth}}@UserEntity() user: { id: string }{{/if}}) {
38
85
  {{#if useTypeorm}}
39
- const builder = new GraphRelationBuilder(this.db.getDataSource());
86
+ const builder = new GraphRelationBuilder(this.db.typeorm);
40
87
  const relations = builder.buildForQuery(Todo, info, "todos");
41
- return this.db.getRepository(Todo).find({ relations });
88
+ {{#if hasAuth}}
89
+ return this.db.typeorm.getRepository(TodoEntity).find({ relations, where: { authorId: user.id } });
90
+ {{else}}
91
+ return this.db.typeorm.getRepository(TodoEntity).find({ relations });
92
+ {{/if}}
93
+ {{else if isPrisma8}}
94
+ {{#if hasAuth}}
95
+ return ((this.db.prisma.orm.public as any).Todo).where({ authorId: user.id }).all();
96
+ {{else}}
97
+ return ((this.db.prisma.orm.public as any).Todo).all();
98
+ {{/if}}
42
99
  {{else if usePrisma}}
100
+ {{#if hasAuth}}
101
+ return this.db.prisma.todo.findMany({ where: { authorId: user.id } });
102
+ {{else}}
43
103
  return this.db.prisma.todo.findMany();
104
+ {{/if}}
44
105
  {{else if useDrizzle}}
45
- return this.db.select().from(schema.todos);
106
+ {{#if hasAuth}}
107
+ return this.db.drizzle.select().from(schema.todos).where(eq(schema.todos.authorId, user.id));
108
+ {{else}}
109
+ return this.db.drizzle.select().from(schema.todos);
110
+ {{/if}}
46
111
  {{else}}
47
112
  return [];
48
113
  {{/if}}
49
114
  }
50
115
 
116
+ {{#if hasAuth}}
51
117
  @UseGuards(GqlAuthGuard)
118
+ {{/if}}
52
119
  @Mutation(() => Todo)
53
- createTodo(
120
+ async createTodo(
121
+ {{#if hasAuth}}
54
122
  @UserEntity() user: { id: string },
123
+ {{/if}}
55
124
  @Args("input") input: CreateTodoInput{{#if useTypeorm}}, info: GraphQLResolveInfo{{/if}}
56
125
  ) {
57
- {{#if useTypeorm}}
58
- const entity = this.db.getRepository(Todo).create(input);
59
- const saved = await this.db.getRepository(Todo).save(entity);
60
- const builder = new GraphRelationBuilder(this.db.getDataSource());
126
+ if (!input.title.trim()) throw new BadRequestException("Title must not be empty");
127
+ {{#if isPrisma8}}
128
+ {{#if hasAuth}}
129
+ return ((this.db.prisma.orm.public as any).Todo).create({ ...input, authorId: user.id });
130
+ {{else}}
131
+ return ((this.db.prisma.orm.public as any).Todo).create(input);
132
+ {{/if}}
133
+ {{else if usePrisma}}
134
+ {{#if hasAuth}}
135
+ const todo = await this.db.prisma.todo.create({ data: { ...input, authorId: user.id } });
136
+ {{else}}
137
+ const todo = await this.db.prisma.todo.create({ data: input });
138
+ {{/if}}
139
+ return todo;
140
+ {{else if useTypeorm}}
141
+ {{#if hasAuth}}
142
+ const entity = this.db.typeorm.getRepository(TodoEntity).create({ ...input, authorId: user.id });
143
+ {{else}}
144
+ const entity = this.db.typeorm.getRepository(TodoEntity).create(input);
145
+ {{/if}}
146
+ const saved = await this.db.typeorm.getRepository(TodoEntity).save(entity);
147
+ const builder = new GraphRelationBuilder(this.db.typeorm);
61
148
  const relations = builder.buildForQuery(Todo, info, "createTodo");
62
- return this.db.getRepository(Todo).findOneOrFail({
63
- where: { id: saved.id },
149
+ return this.db.typeorm.getRepository(TodoEntity).findOneOrFail({
64
150
  relations,
65
- });
66
- {{else if usePrisma}}
67
- return this.db.prisma.todo.create({
68
- data: { ...input, authorId: user.id },
151
+ where: { id: saved.id },
69
152
  });
70
153
  {{else if useDrizzle}}
71
- const [todo] = await this.db.insert(schema.todos).values(input).returning();
154
+ {{#if hasMysql}}
155
+ const [inserted] = await this.db.drizzle.insert(schema.todos).values({{#if hasAuth}}{ ...input, authorId: user.id }{{else}}input{{/if}}).$returningId();
156
+ if (!inserted) throw new NotFoundException("Todo not found");
157
+ const [todo] = await this.db.drizzle.select().from(schema.todos).where({{#if hasAuth}}and(eq(schema.todos.authorId, user.id), eq(schema.todos.id, inserted.id)){{else}}eq(schema.todos.id, inserted.id){{/if}});
158
+ if (!todo) throw new NotFoundException("Todo not found");
72
159
  return todo;
73
160
  {{else}}
161
+ {{#if hasAuth}}
162
+ const [todo] = await this.db.drizzle.insert(schema.todos).values({ ...input, authorId: user.id }).returning();
163
+ {{else}}
164
+ const [todo] = await this.db.drizzle.insert(schema.todos).values(input).returning();
165
+ {{/if}}
166
+ if (!todo) throw new NotFoundException("Todo not found");
167
+ return todo;
168
+ {{/if}}
169
+ {{else}}
74
170
  return { id: "1", ...input };
75
171
  {{/if}}
76
172
  }
77
173
 
174
+ {{#if hasAuth}}
78
175
  @UseGuards(GqlAuthGuard)
176
+ {{/if}}
79
177
  @Mutation(() => Todo)
80
- updateTodo(@Args("input") input: UpdateTodoInput{{#if useTypeorm}}, info: GraphQLResolveInfo{{/if}}) {
178
+ async updateTodo(
179
+ {{#if hasAuth}}
180
+ @UserEntity() user: { id: string },
181
+ {{/if}}
182
+ @Args("input") input: UpdateTodoInput{{#if useTypeorm}}, info: GraphQLResolveInfo{{/if}}
183
+ ) {
81
184
  const { id, ...data } = input;
82
- {{#if useTypeorm}}
83
- await this.db.getRepository(Todo).update(id, data);
84
- const builder = new GraphRelationBuilder(this.db.getDataSource());
185
+ if (data.title !== undefined && !data.title.trim()) throw new BadRequestException("Title must not be empty");
186
+ {{#if isPrisma8}}
187
+ {{#if hasAuth}}
188
+ return ((this.db.prisma.orm.public as any).Todo).where({ authorId: user.id, id }).update(data);
189
+ {{else}}
190
+ return ((this.db.prisma.orm.public as any).Todo).where({ id }).update(data);
191
+ {{/if}}
192
+ {{else if usePrisma}}
193
+ {{#if hasAuth}}
194
+ const result = await this.db.prisma.todo.update({ data, where: { authorId: user.id, id } });
195
+ {{else}}
196
+ const result = await this.db.prisma.todo.update({ data, where: { id } });
197
+ {{/if}}
198
+ return result;
199
+ {{else if useTypeorm}}
200
+ {{#if hasAuth}}
201
+ const updateResult = await this.db.typeorm.getRepository(TodoEntity).update({ authorId: user.id, id }, data);
202
+ {{else}}
203
+ const updateResult = await this.db.typeorm.getRepository(TodoEntity).update(id, data);
204
+ {{/if}}
205
+ if ((updateResult.affected ?? 0) === 0) throw new NotFoundException("Todo not found");
206
+ const builder = new GraphRelationBuilder(this.db.typeorm);
85
207
  const relations = builder.buildForQuery(Todo, info, "updateTodo");
86
- return this.db.getRepository(Todo).findOneOrFail({
87
- where: { id },
208
+ return this.db.typeorm.getRepository(TodoEntity).findOneOrFail({
88
209
  relations,
210
+ where: { id },
89
211
  });
90
- {{else if usePrisma}}
91
- return this.db.prisma.todo.update({ where: { id }, data });
92
212
  {{else if useDrizzle}}
93
- const [todo] = await this.db
94
- .update(schema.todos)
95
- .set(data)
96
- .where(eq(schema.todos.id, id))
97
- .returning();
213
+ {{#if hasMysql}}
214
+ await this.db.drizzle.update(schema.todos).set(data).where({{#if hasAuth}}and(eq(schema.todos.authorId, user.id), eq(schema.todos.id, Number(id))){{else}}eq(schema.todos.id, Number(id)){{/if}});
215
+ const [todo] = await this.db.drizzle.select().from(schema.todos).where({{#if hasAuth}}and(eq(schema.todos.authorId, user.id), eq(schema.todos.id, Number(id))){{else}}eq(schema.todos.id, Number(id)){{/if}});
216
+ {{else}}
217
+ {{#if hasAuth}}
218
+ const [todo] = await this.db.drizzle.update(schema.todos).set(data).where(and(eq(schema.todos.authorId, user.id), eq(schema.todos.id, Number(id)))).returning();
219
+ {{else}}
220
+ const [todo] = await this.db.drizzle.update(schema.todos).set(data).where(eq(schema.todos.id, Number(id))).returning();
221
+ {{/if}}
222
+ {{/if}}
223
+ if (!todo) throw new NotFoundException("Todo not found");
98
224
  return todo;
99
225
  {{else}}
100
226
  return { id, ...data };
101
227
  {{/if}}
102
228
  }
103
229
 
230
+ {{#if hasAuth}}
104
231
  @UseGuards(GqlAuthGuard)
232
+ {{/if}}
105
233
  @Mutation(() => Boolean)
106
- async deleteTodo(@Args("id") id: string): Promise<boolean> {
107
- {{#if useTypeorm}}
108
- const result = await this.db.getRepository(Todo).delete(id);
109
- return (result.affected ?? 0) > 0;
234
+ async deleteTodo(
235
+ {{#if hasAuth}}
236
+ @UserEntity() user: { id: string },
237
+ {{/if}}
238
+ @Args("id") id: string
239
+ ): Promise<boolean> {
240
+ {{#if isPrisma8}}
241
+ {{#if hasAuth}}
242
+ await ((this.db.prisma.orm.public as any).Todo).where({ authorId: user.id, id }).delete();
243
+ {{else}}
244
+ await ((this.db.prisma.orm.public as any).Todo).where({ id }).delete();
245
+ {{/if}}
246
+ return true;
110
247
  {{else if usePrisma}}
111
- await this.db.prisma.todo.delete({ where: { id } });
248
+ {{#if hasAuth}}
249
+ const result = await this.db.prisma.todo.deleteMany({ where: { authorId: user.id, id } });
250
+ {{else}}
251
+ const result = await this.db.prisma.todo.deleteMany({ where: { id } });
252
+ {{/if}}
253
+ if (result.count === 0) throw new NotFoundException("Todo not found");
254
+ return true;
255
+ {{else if useTypeorm}}
256
+ {{#if hasAuth}}
257
+ const result = await this.db.typeorm.getRepository(TodoEntity).delete({ authorId: user.id, id });
258
+ {{else}}
259
+ const result = await this.db.typeorm.getRepository(TodoEntity).delete(id);
260
+ {{/if}}
261
+ if ((result.affected ?? 0) === 0) throw new NotFoundException("Todo not found");
112
262
  return true;
113
263
  {{else if useDrizzle}}
114
- await this.db.delete(schema.todos).where(eq(schema.todos.id, id));
264
+ {{#if hasMysql}}
265
+ const [existing] = await this.db.drizzle.select().from(schema.todos).where({{#if hasAuth}}and(eq(schema.todos.authorId, user.id), eq(schema.todos.id, Number(id))){{else}}eq(schema.todos.id, Number(id)){{/if}});
266
+ if (!existing) throw new NotFoundException("Todo not found");
267
+ await this.db.drizzle.delete(schema.todos).where({{#if hasAuth}}and(eq(schema.todos.authorId, user.id), eq(schema.todos.id, Number(id))){{else}}eq(schema.todos.id, Number(id)){{/if}});
268
+ {{else}}
269
+ {{#if hasAuth}}
270
+ const deleted = await this.db.drizzle.delete(schema.todos).where(and(eq(schema.todos.authorId, user.id), eq(schema.todos.id, Number(id)))).returning();
271
+ {{else}}
272
+ const deleted = await this.db.drizzle.delete(schema.todos).where(eq(schema.todos.id, Number(id))).returning();
273
+ {{/if}}
274
+ if (deleted.length === 0) throw new NotFoundException("Todo not found");
275
+ {{/if}}
115
276
  return true;
116
277
  {{else}}
117
278
  return true;
118
279
  {{/if}}
119
280
  }{{/if}}
120
281
  }
282
+
283
+ {{/if}}
@@ -1,5 +1,16 @@
1
1
  import { z } from "zod";
2
2
 
3
+ {{#if (includes addons "nestjs-zod")}}
4
+ import { createZodDto } from "nestjs-zod";
5
+
6
+ const createTodoSchema = z.object({
7
+ completed: z.boolean().default(false),
8
+ description: z.string().optional(),
9
+ title: z.string().min(1),
10
+ });
11
+
12
+ export class CreateTodoDto extends createZodDto(createTodoSchema) {}
13
+ {{else}}
3
14
  export class CreateTodoDto {
4
15
  static schema = z.object({
5
16
  completed: z.boolean().default(false),
@@ -11,3 +22,4 @@ export class CreateTodoDto {
11
22
  description?: string;
12
23
  completed: boolean;
13
24
  }
25
+ {{/if}}
@@ -1,5 +1,16 @@
1
1
  import { z } from "zod";
2
2
 
3
+ {{#if (includes addons "nestjs-zod")}}
4
+ import { createZodDto } from "nestjs-zod";
5
+
6
+ const updateTodoSchema = z.object({
7
+ completed: z.boolean().optional(),
8
+ description: z.string().optional(),
9
+ title: z.string().min(1).optional(),
10
+ });
11
+
12
+ export class UpdateTodoDto extends createZodDto(updateTodoSchema) {}
13
+ {{else}}
3
14
  export class UpdateTodoDto {
4
15
  static schema = z.object({
5
16
  completed: z.boolean().optional(),
@@ -11,3 +22,4 @@ export class UpdateTodoDto {
11
22
  description?: string;
12
23
  completed?: boolean;
13
24
  }
25
+ {{/if}}
@@ -9,6 +9,9 @@ import {
9
9
  {{#if (and isPassportAuth hasDatabase)}}
10
10
  UseGuards,
11
11
  {{/if}}
12
+ {{#if (and isBetterAuth hasDatabase hasGraphql)}}
13
+ UseGuards,
14
+ {{/if}}
12
15
  } from "@nestjs/common";
13
16
  {{#if swagger}}
14
17
  import {
@@ -16,10 +19,12 @@ import {
16
19
  ApiOkResponse,
17
20
  ApiOperation,
18
21
  ApiTags,
22
+ {{#if (or isPassportAuth isBetterAuth)}}
19
23
  ApiUnauthorizedResponse,
24
+ {{/if}}
20
25
  } from "@nestjs/swagger";
21
26
  {{/if}}
22
- {{#if isPassportAuth}}
27
+ {{#if (and isPassportAuth swagger)}}
23
28
  import {
24
29
  ApiBearerAuth,
25
30
  } from "@nestjs/swagger";
@@ -32,6 +37,9 @@ import type { UserSession } from "../../auth/auth.js";
32
37
  import { RestAuthGuard } from "../../auth/guards/rest-auth.guard.js";
33
38
  import { CurrentUser } from "../../auth/decorators/current-user.decorator.js";
34
39
  {{/if}}
40
+ {{#if (and isBetterAuth hasDatabase hasGraphql)}}
41
+ import { RestAuthGuard } from "../../auth/guards/rest-auth.guard.js";
42
+ {{/if}}
35
43
  import { TodoService } from "./todo.service.js";
36
44
  import { CreateTodoDto } from "./dto/create-todo.dto.js";
37
45
  import { UpdateTodoDto } from "./dto/update-todo.dto.js";
@@ -40,7 +48,7 @@ import { UpdateTodoDto } from "./dto/update-todo.dto.js";
40
48
  @ApiTags("Todos")
41
49
  {{/if}}
42
50
  @Controller("todos")
43
- {{#if (and isPassportAuth hasDatabase)}}
51
+ {{#if (or (and isPassportAuth hasDatabase) (and isBetterAuth hasDatabase hasGraphql))}}
44
52
  @UseGuards(RestAuthGuard)
45
53
  {{/if}}
46
54
  export class TodoController {
@@ -62,7 +70,11 @@ export class TodoController {
62
70
  return this.todoService.findAll(user.id);
63
71
  }
64
72
  {{else if (and isBetterAuth hasDatabase)}}
73
+ {{#if (and isMonorepo usePrisma)}}
74
+ findAll(@Session() session: UserSession): ReturnType<TodoService["findAll"]> {
75
+ {{else}}
65
76
  findAll(@Session() session: UserSession) {
77
+ {{/if}}
66
78
  return this.todoService.findAll(session.user.id);
67
79
  }
68
80
  {{else}}
@@ -84,20 +96,20 @@ export class TodoController {
84
96
  {{/if}}
85
97
  {{#if (and isPassportAuth hasDatabase)}}
86
98
  create(
87
- @Body({ schema: CreateTodoDto.schema }) input: CreateTodoDto,
99
+ @Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: CreateTodoDto.schema }){{/if}} input: CreateTodoDto,
88
100
  @CurrentUser() user: { id: string }
89
101
  ) {
90
102
  return this.todoService.create(input, user.id);
91
103
  }
92
104
  {{else if (and isBetterAuth hasDatabase)}}
93
105
  create(
94
- @Body({ schema: CreateTodoDto.schema }) input: CreateTodoDto,
106
+ @Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: CreateTodoDto.schema }){{/if}} input: CreateTodoDto,
95
107
  @Session() session: UserSession
96
108
  ) {
97
109
  return this.todoService.create(input, session.user.id);
98
110
  }
99
111
  {{else}}
100
- create(@Body({ schema: CreateTodoDto.schema }) input: CreateTodoDto) {
112
+ create(@Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: CreateTodoDto.schema }){{/if}} input: CreateTodoDto) {
101
113
  return this.todoService.create(input);
102
114
  }
103
115
  {{/if}}
@@ -116,7 +128,7 @@ export class TodoController {
116
128
  {{#if (and isPassportAuth hasDatabase)}}
117
129
  update(
118
130
  @Param("id") id: string,
119
- @Body({ schema: UpdateTodoDto.schema }) input: UpdateTodoDto,
131
+ @Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: UpdateTodoDto.schema }){{/if}} input: UpdateTodoDto,
120
132
  @CurrentUser() user: { id: string }
121
133
  ) {
122
134
  return this.todoService.update(id, input, user.id);
@@ -124,7 +136,7 @@ export class TodoController {
124
136
  {{else if (and isBetterAuth hasDatabase)}}
125
137
  update(
126
138
  @Param("id") id: string,
127
- @Body({ schema: UpdateTodoDto.schema }) input: UpdateTodoDto,
139
+ @Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: UpdateTodoDto.schema }){{/if}} input: UpdateTodoDto,
128
140
  @Session() session: UserSession
129
141
  ) {
130
142
  return this.todoService.update(id, input, session.user.id);
@@ -132,7 +144,7 @@ export class TodoController {
132
144
  {{else}}
133
145
  update(
134
146
  @Param("id") id: string,
135
- @Body({ schema: UpdateTodoDto.schema }) input: UpdateTodoDto
147
+ @Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: UpdateTodoDto.schema }){{/if}} input: UpdateTodoDto
136
148
  ) {
137
149
  return this.todoService.update(id, input);
138
150
  }
@@ -164,7 +176,7 @@ export class TodoController {
164
176
  return this.todoService.delete(id, session.user.id);
165
177
  }
166
178
  {{else}}
167
- async delete(@Param("id") id: string) {
179
+ delete(@Param("id") id: string) {
168
180
  return this.todoService.delete(id);
169
181
  }
170
182
  {{/if}}
@@ -11,14 +11,12 @@ import { TodoRouter } from "./todo.router.js";
11
11
  {{#if hasRest}}
12
12
  controllers: [TodoController],
13
13
  {{/if}}
14
+ exports: [TodoService],
14
15
  providers: [
15
16
  TodoService,
16
17
  {{#unless hasRest}}
17
18
  TodoRouter,
18
19
  {{/unless}}
19
20
  ],
20
- {{#if hasRest}}
21
- exports: [TodoService],
22
- {{/if}}
23
21
  })
24
22
  export class TodoModule {}
@@ -1,8 +1,12 @@
1
1
  {{#if hasTrpc}}
2
- import { Router, Query, Mutation, Ctx, Input } from "nestjs-trpc";
2
+ import { Router, Query, Mutation, Ctx, Input{{#if hasTrpcAndAuth}}, UseMiddlewares{{/if}} } from "nestjs-trpc";
3
+ import { NotFoundException } from "@nestjs/common";
4
+ import { TRPCError } from "@trpc/server";
3
5
  import z from "zod";
4
- {{#if hasTrpcAndAuth}}
6
+ {{#if (and hasTrpcAndAuth isBetterAuth)}}
5
7
  import type { UserSession } from "../../auth/auth.js";
8
+ {{/if}}
9
+ {{#if hasTrpcAndAuth}}
6
10
  import { AuthTRPCMiddleware } from "../../libs/middlewares/auth.trpc.middleware.js";
7
11
  import type { InnerContext } from "../../libs/trpc/inner.context.js";
8
12
  {{/if}}
@@ -11,7 +15,7 @@ import { CreateTodoDto } from "./dto/create-todo.dto.js";
11
15
  import { UpdateTodoDto } from "./dto/update-todo.dto.js";
12
16
 
13
17
  const todoSchema = z.object({
14
- id: z.string(),
18
+ id: z.union([z.string(), z.number()]),
15
19
  title: z.string(),
16
20
  description: z.string().nullable().optional(),
17
21
  completed: z.boolean(),
@@ -19,7 +23,7 @@ const todoSchema = z.object({
19
23
  });
20
24
 
21
25
  const updateTodoInput = z.object({
22
- id: z.string(),
26
+ id: z.union([z.string(), z.number()]),
23
27
  data: UpdateTodoDto.schema,
24
28
  });
25
29
 
@@ -42,14 +46,26 @@ export class TodoRouter {
42
46
 
43
47
  @Mutation({ input: updateTodoInput, output: todoSchema })
44
48
  @UseMiddlewares(AuthTRPCMiddleware)
45
- update(@Ctx() ctx: InnerContext, @Input() input: { id: string; data: UpdateTodoDto }) {
46
- return this.todoService.update(input.id, input.data, ctx.session!.user.id);
49
+ update(@Ctx() ctx: InnerContext, @Input() input: { id: string | number; data: UpdateTodoDto }) {
50
+ return this.todoService.update(String(input.id), input.data, ctx.session!.user.id)
51
+ .catch((error: unknown) => {
52
+ if (error instanceof NotFoundException) {
53
+ throw new TRPCError({ code: "NOT_FOUND", message: error.message });
54
+ }
55
+ throw error;
56
+ });
47
57
  }
48
58
 
49
- @Mutation({ input: z.object({ id: z.string() }) })
59
+ @Mutation({ input: z.object({ id: z.union([z.string(), z.number()]) }) })
50
60
  @UseMiddlewares(AuthTRPCMiddleware)
51
- delete(@Ctx() ctx: InnerContext, @Input() input: { id: string }) {
52
- return this.todoService.delete(input.id, ctx.session!.user.id);
61
+ delete(@Ctx() ctx: InnerContext, @Input() input: { id: string | number }) {
62
+ return this.todoService.delete(String(input.id), ctx.session!.user.id)
63
+ .catch((error: unknown) => {
64
+ if (error instanceof NotFoundException) {
65
+ throw new TRPCError({ code: "NOT_FOUND", message: error.message });
66
+ }
67
+ throw error;
68
+ });
53
69
  }
54
70
  {{else}}
55
71
  @Query({ output: z.array(todoSchema) })
@@ -64,12 +80,24 @@ export class TodoRouter {
64
80
 
65
81
  @Mutation({ input: updateTodoInput, output: todoSchema })
66
82
  update(@Input() input: { id: string; data: UpdateTodoDto }) {
67
- return this.todoService.update(input.id, input.data);
83
+ return this.todoService.update(input.id, input.data)
84
+ .catch((error: unknown) => {
85
+ if (error instanceof NotFoundException) {
86
+ throw new TRPCError({ code: "NOT_FOUND", message: error.message });
87
+ }
88
+ throw error;
89
+ });
68
90
  }
69
91
 
70
- @Mutation({ input: z.object({ id: z.string() }) })
71
- delete(@Input() input: { id: string }) {
72
- return this.todoService.delete(input.id);
92
+ @Mutation({ input: z.object({ id: z.union([z.string(), z.number()]) }) })
93
+ delete(@Input() input: { id: string | number }) {
94
+ return this.todoService.delete(String(input.id))
95
+ .catch((error: unknown) => {
96
+ if (error instanceof NotFoundException) {
97
+ throw new TRPCError({ code: "NOT_FOUND", message: error.message });
98
+ }
99
+ throw error;
100
+ });
73
101
  }
74
102
  {{/if}}
75
103
  }