@nest-arch/tui 0.4.6 → 0.5.1

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 (55) hide show
  1. package/README.md +31 -0
  2. package/dist/cli.js +2 -1
  3. package/dist/constants-CUTbfu9C.js +1 -0
  4. package/dist/index.js +6 -405
  5. package/dist/nonInteractive-C1KZ0b_6.js +5 -0
  6. package/dist/nonInteractiveOptions-CIaoLAWg.js +24 -0
  7. package/dist/projectGeneratorService-CeWJK-HA.js +420 -0
  8. package/dist/projectName-CcE90t2V.js +1 -0
  9. package/dist/templates/addons/husky/pre-commit.hbs +1 -1
  10. package/dist/templates/base/.env.example.hbs +30 -2
  11. package/dist/templates/base/.env.hbs +7 -2
  12. package/dist/templates/base/README.md.hbs +11 -2
  13. package/dist/templates/base/pnpm-workspace.yaml.hbs +9 -4
  14. package/dist/templates/base/prisma.config.ts.hbs +6 -1
  15. package/dist/templates/base/src/app.controller.spec.ts.hbs +6 -0
  16. package/dist/templates/base/src/app.module.ts.hbs +6 -23
  17. package/dist/templates/base/src/database/adapters/interfaces/db-adapter.interface.ts.hbs +5 -5
  18. package/dist/templates/base/src/database/adapters/mongo/raw-mongo.adapter.ts.hbs +6 -4
  19. package/dist/templates/base/src/database/adapters/mongo/typeorm-mongo.adapter.ts.hbs +27 -0
  20. package/dist/templates/base/src/database/db.module.ts.hbs +33 -13
  21. package/dist/templates/base/src/database/db.service.ts.hbs +12 -4
  22. package/dist/templates/base/src/database/entities/todo.entity.ts.hbs +17 -5
  23. package/dist/templates/base/src/database/index.ts.hbs +2 -0
  24. package/dist/templates/base/src/database/orm/drizzle/schema.ts.hbs +80 -20
  25. package/dist/templates/base/src/database/orm/typeorm/data-source.ts.hbs +34 -12
  26. package/dist/templates/base/src/libs/middlewares/graphql-throttler.guard.ts.hbs +22 -0
  27. package/dist/templates/base/src/libs/middlewares/rate-limit.trpc.middleware.ts.hbs +2 -1
  28. package/dist/templates/base/src/libs/trpc/inner.context.ts.hbs +2 -2
  29. package/dist/templates/base/src/main.ts.hbs +2 -2
  30. package/dist/templates/base/test/app.e2e-spec.ts.hbs +378 -202
  31. package/dist/templates/extras/docker/Dockerfile.hbs +9 -2
  32. package/dist/templates/extras/health/src/health/health.controller.ts.hbs +12 -1
  33. package/dist/templates/extras/swagger/create-docs.ts.hbs +6 -1
  34. package/dist/templates/feature/graphql/src/graphql/models/todo.model.ts.hbs +1 -1
  35. package/dist/templates/feature/graphql/src/graphql/resolvers/todo.resolver.ts.hbs +1 -1
  36. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.controller.ts.hbs +80 -7
  37. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.router.ts.hbs +4 -4
  38. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.service.ts.hbs +314 -34
  39. package/dist/templates/monorepo/apps/api-gateway/src/main.ts.hbs +2 -2
  40. package/dist/templates/monorepo/root/README.md.hbs +8 -13
  41. package/dist/templates/single-project/architecture/nest-api/.env.hbs +6 -2
  42. package/dist/templates/single-project/architecture/nest-api/pnpm-workspace.yaml.hbs +6 -0
  43. package/dist/templates/single-project/architecture/nest-api/src/main.ts.hbs +2 -2
  44. package/dist/templates/single-project/architecture/nest-gateway/src/main.ts.hbs +2 -2
  45. package/dist/templates/single-project/architecture/nest-microservice/.env.hbs +30 -1
  46. package/dist/templates/single-project/architecture/nest-microservice/proto/app.proto.hbs +13 -0
  47. package/dist/templates/single-project/architecture/nest-microservice/src/app.controller.ts.hbs +26 -2
  48. package/dist/templates/single-project/architecture/nest-microservice/src/app.module.ts.hbs +61 -1
  49. package/dist/templates/single-project/architecture/nest-microservice/src/app.service.ts.hbs +16 -4
  50. package/dist/templates/single-project/architecture/nest-microservice/src/http-throttler.guard.ts.hbs +13 -0
  51. package/dist/templates/single-project/architecture/nest-microservice/src/main.ts.hbs +26 -7
  52. package/dist/templates/single-project/architecture/nest-microservice/test/microservice.e2e-spec.ts.hbs +7 -87
  53. package/dist/templates/single-project/shared/config/env.ts.hbs +14 -14
  54. package/package.json +6 -5
  55. package/dist/constants-DVhgS48N.js +0 -1
@@ -1,39 +1,148 @@
1
+ {{#if (and hasMongodb useTypeorm)}}
2
+ import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
3
+ import { ObjectId } from "mongodb";
4
+ import type { Document, WithId } from "mongodb";
5
+
6
+ import { DbService } from "../../database/db.service.js";
7
+ import { CreateTodoDto } from "./dto/create-todo.dto.js";
8
+ import { UpdateTodoDto } from "./dto/update-todo.dto.js";
9
+
10
+ interface TodoDocument extends Document {
11
+ completed: boolean;
12
+ createdAt: Date;
13
+ description?: string;
14
+ title: string;
15
+ updatedAt: Date;
16
+ }
17
+
18
+ const serialize = ({ _id, ...todo }: WithId<TodoDocument>) => ({
19
+ ...todo,
20
+ id: _id.toHexString(),
21
+ });
22
+
23
+ function objectId(id: string): ObjectId {
24
+ if (!/^[a-f0-9]{24}$/iu.test(id)) {
25
+ throw new BadRequestException("Invalid todo identifier");
26
+ }
27
+ return new ObjectId(id);
28
+ }
29
+
30
+ @Injectable()
31
+ export class TodoService {
32
+ constructor(private readonly db: DbService) {}
33
+
34
+ private get todos() {
35
+ return this.db.mongo.collection<TodoDocument>("todos");
36
+ }
37
+
38
+ async findAll() {
39
+ const todos = await this.todos.find().sort({ _id: 1 }).limit(100).toArray();
40
+ return todos.map(serialize);
41
+ }
42
+
43
+ async create(input: CreateTodoDto) {
44
+ const now = new Date();
45
+ const todo = {
46
+ completed: input.completed ?? false,
47
+ createdAt: now,
48
+ ...(input.description === undefined ? {} : { description: input.description }),
49
+ title: input.title,
50
+ updatedAt: now,
51
+ };
52
+ const result = await this.todos.insertOne(todo);
53
+ return { ...todo, id: result.insertedId.toHexString() };
54
+ }
55
+
56
+ async update(id: string, input: UpdateTodoDto) {
57
+ const _id = objectId(id);
58
+ await this.todos.updateOne({ _id }, { $set: { ...input, updatedAt: new Date() } });
59
+ const todo = await this.todos.findOne({ _id });
60
+ if (!todo) {
61
+ throw new NotFoundException("Todo not found");
62
+ }
63
+ return serialize(todo);
64
+ }
65
+
66
+ async delete(id: string) {
67
+ const result = await this.todos.deleteOne({ _id: objectId(id) });
68
+ if (result.deletedCount === 0) {
69
+ throw new NotFoundException("Todo not found");
70
+ }
71
+ return { message: "Todo deleted successfully" };
72
+ }
73
+ }
74
+ {{else}}
1
75
  {{#if (and hasMongodb useRawSql)}}
2
76
  import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
3
- import { ObjectId, type WithId } from "mongodb";
77
+ import { ObjectId } from "mongodb";
78
+ import type { Document, WithId } from "mongodb";
79
+
4
80
  import { DbService } from "../../database/db.service.js";
5
81
  import { CreateTodoDto } from "./dto/create-todo.dto.js";
6
82
  import { UpdateTodoDto } from "./dto/update-todo.dto.js";
7
- interface TodoDocument { title: string; completed: boolean; description?: string; }
8
- const serialize = ({ _id, ...todo }: WithId<TodoDocument>) => ({ ...todo, id: _id.toHexString() });
83
+
84
+ interface TodoDocument extends Document {
85
+ completed: boolean;
86
+ description?: string;
87
+ title: string;
88
+ }
89
+
90
+ const serialize = ({ _id, ...todo }: WithId<TodoDocument>) => ({
91
+ ...todo,
92
+ id: _id.toHexString(),
93
+ });
94
+
9
95
  function objectId(id: string): ObjectId {
10
- if (!/^[a-f0-9]{24}$/iu.test(id)) throw new BadRequestException("Invalid todo identifier");
96
+ if (!/^[a-f0-9]{24}$/iu.test(id)) {
97
+ throw new BadRequestException("Invalid todo identifier");
98
+ }
11
99
  return new ObjectId(id);
12
100
  }
101
+
13
102
  @Injectable()
14
103
  export class TodoService {
15
104
  constructor(private readonly db: DbService) {}
16
- private get todos() { return this.db.raw.mongo.collection<TodoDocument>("todos"); }
17
- async findAll() { return (await this.todos.find().sort({ _id: 1 }).limit(100).toArray()).map(serialize); }
105
+
106
+ private get todos() {
107
+ return this.db.raw.mongo.collection<TodoDocument>("todos");
108
+ }
109
+
110
+ async findAll() {
111
+ const todos = await this.todos.find().sort({ _id: 1 }).limit(100).toArray();
112
+ return todos.map(serialize);
113
+ }
114
+
18
115
  async create(input: CreateTodoDto) {
19
- const todo = { title: input.title, completed: input.completed ?? false, ...(input.description === undefined ? {} : { description: input.description }) };
116
+ const todo = {
117
+ completed: input.completed ?? false,
118
+ ...(input.description === undefined ? {} : { description: input.description }),
119
+ title: input.title,
120
+ };
20
121
  const result = await this.todos.insertOne(todo);
21
122
  return { ...todo, id: result.insertedId.toHexString() };
22
123
  }
124
+ {{#if isPrisma8}}
125
+ update(id: string, input: UpdateTodoDto) {
126
+ {{else}}
23
127
  async update(id: string, input: UpdateTodoDto) {
128
+ {{/if}}
24
129
  const todo = await this.todos.findOneAndUpdate({ _id: objectId(id) }, { $set: input }, { returnDocument: "after" });
25
- if (!todo) throw new NotFoundException("Todo not found");
130
+ if (!todo) {
131
+ throw new NotFoundException("Todo not found");
132
+ }
26
133
  return serialize(todo);
27
134
  }
28
135
  async delete(id: string) {
29
136
  const result = await this.todos.deleteOne({ _id: objectId(id) });
30
- if (result.deletedCount === 0) throw new NotFoundException("Todo not found");
137
+ if (result.deletedCount === 0) {
138
+ throw new NotFoundException("Todo not found");
139
+ }
31
140
  return { message: "Todo deleted successfully" };
32
141
  }
33
142
  }
34
143
  {{else}}
35
- {{#if (and hasDatabase hasAuth)}}
36
- import { Injectable, NotFoundException } from "@nestjs/common";
144
+ {{#if (or (and hasTodoExample (not hasDatabase)) hasAuth isPrisma8 (and hasDatabase useTypeorm) (and hasDatabase useDrizzle (or hasMysql hasSqlserver)) (and hasMongodb usePrisma))}}
145
+ import { {{#if (and hasMongodb usePrisma (not isPrisma8))}}BadRequestException, {{/if}}Injectable, NotFoundException{{#if (and hasAuth hasPostgres useRawSql)}}, type OnModuleInit{{/if}} } from "@nestjs/common";
37
146
  {{else}}
38
147
  import { Injectable } from "@nestjs/common";
39
148
  {{/if}}
@@ -51,34 +160,84 @@ import { and, eq } from "drizzle-orm";
51
160
  import { eq } from "drizzle-orm";
52
161
  {{/if}}
53
162
  {{/if}}
54
- {{#if useTypeorm}}
163
+ {{#if (and useTypeorm (not hasMongodb))}}
55
164
  import { Todo } from "../../database/entities/todo.entity.js";
56
165
  {{/if}}
166
+ {{#if (and hasAuth hasPostgres useRawSql)}}
167
+ import type { Pool } from "pg";
168
+ {{/if}}
57
169
  {{/if}}
58
170
  import { CreateTodoDto } from "./dto/create-todo.dto.js";
59
171
  import { UpdateTodoDto } from "./dto/update-todo.dto.js";
172
+ {{#if isPrisma8}}
173
+ import type { Models } from "../../prisma/contract.js";
174
+
175
+ type Todo = Models.public_Todo;
176
+ {{/if}}
60
177
 
61
178
  @Injectable()
179
+ {{#if (and hasAuth hasPostgres useRawSql)}}
180
+ export class TodoService implements OnModuleInit {
181
+ {{else}}
62
182
  export class TodoService {
183
+ {{/if}}
184
+ {{#if (and hasMongodb usePrisma (not isPrisma8))}}
185
+ private assertMongoId(id: string): void {
186
+ if (!/^[a-f0-9]{24}$/iu.test(id)) {
187
+ throw new BadRequestException("Invalid todo identifier");
188
+ }
189
+ }
190
+ {{/if}}
63
191
  {{#if hasDatabase}}
64
192
  constructor(private readonly db: DbService) {}
65
193
  {{else}}
66
- private todos: Array<{
194
+ private todos: {
195
+ {{#if hasAuth}}
196
+ authorId: string;
197
+ {{/if}}
67
198
  completed: boolean;
68
199
  description?: string;
69
200
  id: string;
70
201
  title: string;
71
- }> = [];
202
+ }[] = [];
72
203
  private nextId = 1;
73
204
  {{/if}}
74
205
 
206
+ {{#if (and hasAuth hasPostgres useRawSql)}}
207
+ async onModuleInit(): Promise<void> {
208
+ const pool = this.db.raw.sql as Pool;
209
+ await pool.query(`CREATE TABLE IF NOT EXISTS todos (
210
+ id SERIAL PRIMARY KEY,
211
+ title TEXT NOT NULL,
212
+ completed BOOLEAN NOT NULL DEFAULT FALSE,
213
+ description TEXT,
214
+ author_id TEXT NOT NULL,
215
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
216
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
217
+ )`);
218
+ }
219
+
220
+ {{/if}}
75
221
  {{#if hasDatabase}}
76
222
  {{#if hasAuth}}
223
+ {{#if isPrisma8}}
224
+ async findAll(authorId: string): Promise<Todo[]> {
225
+ {{else if (and hasPostgres useRawSql)}}
226
+ async findAll(authorId: string) {
227
+ {{else}}
77
228
  findAll(authorId: string) {
229
+ {{/if}}
78
230
  {{#if isPrisma8}}
79
- return ((this.db.prisma.orm.public as any).Todo).where({ authorId }).all();
231
+ return await this.db.prisma.orm.public.Todo.where({ authorId }).all();
80
232
  {{else if usePrisma}}
81
233
  return this.db.prisma.todo.findMany({ where: { authorId } });
234
+ {{else if (and hasPostgres useRawSql)}}
235
+ const pool = this.db.raw.sql as Pool;
236
+ const result = await pool.query(
237
+ 'SELECT id, title, completed, description, author_id AS "authorId" FROM todos WHERE author_id = $1 ORDER BY id',
238
+ [authorId]
239
+ );
240
+ return result.rows;
82
241
  {{else if useTypeorm}}
83
242
  return this.db.typeorm.getRepository(Todo).find({ where: { authorId } });
84
243
  {{else if useDrizzle}}
@@ -86,16 +245,32 @@ export class TodoService {
86
245
  {{/if}}
87
246
  }
88
247
 
248
+ {{#if isPrisma8}}
249
+ async create(input: CreateTodoDto, authorId: string): Promise<Todo> {
250
+ {{else}}
89
251
  async create(input: CreateTodoDto, authorId: string) {
252
+ {{/if}}
90
253
  {{#if isPrisma8}}
91
- return ((this.db.prisma.orm.public as any).Todo).create({ ...input, authorId });
254
+ return await this.db.prisma.orm.public.Todo.create({ ...input, authorId });
92
255
  {{else if usePrisma}}
93
256
  const todo = await this.db.prisma.todo.create({ data: { ...input, authorId } });
94
257
  return todo;
258
+ {{else if (and hasPostgres useRawSql)}}
259
+ const pool = this.db.raw.sql as Pool;
260
+ const result = await pool.query(
261
+ 'INSERT INTO todos (title, completed, description, author_id) VALUES ($1, $2, $3, $4) RETURNING id, title, completed, description, author_id AS "authorId"',
262
+ [input.title, input.completed ?? false, input.description ?? null, authorId]
263
+ );
264
+ const [todo] = result.rows;
265
+ return todo;
95
266
  {{else if useTypeorm}}
96
267
  const todo = await this.db.typeorm.getRepository(Todo).save(this.db.typeorm.getRepository(Todo).create({ ...input, authorId }));
97
268
  return todo;
98
269
  {{else if useDrizzle}}
270
+ {{#if hasSqlserver}}
271
+ const [todo] = await this.db.drizzle.insert(schema.todos).output().values({ ...input, authorId });
272
+ return todo;
273
+ {{else}}
99
274
  {{#if hasMysql}}
100
275
  const [inserted] = await this.db.drizzle.insert(schema.todos).values({ ...input, authorId }).$returningId();
101
276
  if (!inserted) {
@@ -107,12 +282,13 @@ export class TodoService {
107
282
  const [todo] = await this.db.drizzle.insert(schema.todos).values({ ...input, authorId }).returning();
108
283
  return todo;
109
284
  {{/if}}
285
+ {{/if}}
110
286
  {{/if}}
111
287
  }
112
288
 
113
289
  async update(id: string, input: UpdateTodoDto, authorId: string) {
114
290
  {{#if isPrisma8}}
115
- const result = await ((this.db.prisma.orm.public as any).Todo).where({ authorId, id }).update(input);
291
+ const result = await this.db.prisma.orm.public.Todo.where({ authorId, id: Number(id) }).update(input);
116
292
  if (!result) {
117
293
  throw new NotFoundException("Todo not found");
118
294
  }
@@ -123,6 +299,17 @@ export class TodoService {
123
299
  throw new NotFoundException("Todo not found");
124
300
  }
125
301
  return this.db.prisma.todo.update({ data: input, where: { id } });
302
+ {{else if (and hasPostgres useRawSql)}}
303
+ const pool = this.db.raw.sql as Pool;
304
+ const result = await pool.query(
305
+ 'UPDATE todos SET title = COALESCE($1, title), completed = COALESCE($2, completed), description = COALESCE($3, description), updated_at = NOW() WHERE id = $4 AND author_id = $5 RETURNING id, title, completed, description, author_id AS "authorId"',
306
+ [input.title ?? null, input.completed ?? null, input.description ?? null, id, authorId]
307
+ );
308
+ const [todo] = result.rows;
309
+ if (!todo) {
310
+ throw new NotFoundException("Todo not found");
311
+ }
312
+ return todo;
126
313
  {{else if useTypeorm}}
127
314
  const repository = this.db.typeorm.getRepository(Todo);
128
315
  const result = await repository.update({ authorId, id }, input);
@@ -138,6 +325,8 @@ export class TodoService {
138
325
  {{#if hasMysql}}
139
326
  await this.db.drizzle.update(schema.todos).set(input).where(and(eq(schema.todos.authorId, authorId), eq(schema.todos.id, Number(id))));
140
327
  const [todo] = await this.db.drizzle.select().from(schema.todos).where(and(eq(schema.todos.authorId, authorId), eq(schema.todos.id, Number(id))));
328
+ {{else if hasSqlserver}}
329
+ const [todo] = await this.db.drizzle.update(schema.todos).set(input).output().where(and(eq(schema.todos.authorId, authorId), eq(schema.todos.id, Number(id))));
141
330
  {{else}}
142
331
  const [todo] = await this.db.drizzle.update(schema.todos).set(input).where(and(eq(schema.todos.authorId, authorId), eq(schema.todos.id, Number(id)))).returning();
143
332
  {{/if}}
@@ -150,7 +339,7 @@ export class TodoService {
150
339
 
151
340
  async delete(id: string, authorId: string) {
152
341
  {{#if isPrisma8}}
153
- const count = await ((this.db.prisma.orm.public as any).Todo).where({ authorId, id }).delete();
342
+ const count = await this.db.prisma.orm.public.Todo.where({ authorId, id }).delete();
154
343
  if (count === 0) {
155
344
  throw new NotFoundException("Todo not found");
156
345
  }
@@ -159,6 +348,16 @@ export class TodoService {
159
348
  if (result.count === 0) {
160
349
  throw new NotFoundException("Todo not found");
161
350
  }
351
+ {{else if (and hasPostgres useRawSql)}}
352
+ const pool = this.db.raw.sql as Pool;
353
+ const result = await pool.query(
354
+ 'DELETE FROM todos WHERE id = $1 AND author_id = $2 RETURNING id',
355
+ [id, authorId]
356
+ );
357
+ const [todo] = result.rows;
358
+ if (!todo) {
359
+ throw new NotFoundException("Todo not found");
360
+ }
162
361
  {{else if useTypeorm}}
163
362
  const result = await this.db.typeorm.getRepository(Todo).delete({ authorId, id });
164
363
  if (result.affected === 0) {
@@ -171,6 +370,11 @@ export class TodoService {
171
370
  throw new NotFoundException("Todo not found");
172
371
  }
173
372
  await this.db.drizzle.delete(schema.todos).where(and(eq(schema.todos.authorId, authorId), eq(schema.todos.id, Number(id))));
373
+ {{else if hasSqlserver}}
374
+ const [todo] = await this.db.drizzle.delete(schema.todos).output().where(and(eq(schema.todos.authorId, authorId), eq(schema.todos.id, Number(id))));
375
+ if (!todo) {
376
+ throw new NotFoundException("Todo not found");
377
+ }
174
378
  {{else}}
175
379
  const [todo] = await this.db.drizzle.delete(schema.todos).where(and(eq(schema.todos.authorId, authorId), eq(schema.todos.id, Number(id)))).returning();
176
380
  if (!todo) {
@@ -180,10 +384,14 @@ export class TodoService {
180
384
  {{/if}}
181
385
  return { message: "Todo deleted successfully" };
182
386
  }
387
+ {{else}}
388
+ {{#if isPrisma8}}
389
+ async findAll(): Promise<Todo[]> {
183
390
  {{else}}
184
391
  findAll() {
392
+ {{/if}}
185
393
  {{#if isPrisma8}}
186
- return ((this.db.prisma.orm.public as any).Todo).all();
394
+ return await this.db.prisma.orm.public.Todo.all();
187
395
  {{else if usePrisma}}
188
396
  return this.db.prisma.todo.findMany();
189
397
  {{else if useTypeorm}}
@@ -193,9 +401,13 @@ export class TodoService {
193
401
  {{/if}}
194
402
  }
195
403
 
404
+ {{#if isPrisma8}}
405
+ async create(input: CreateTodoDto): Promise<Todo> {
406
+ {{else}}
196
407
  async create(input: CreateTodoDto) {
408
+ {{/if}}
197
409
  {{#if isPrisma8}}
198
- return ((this.db.prisma.orm.public as any).Todo).create(input);
410
+ return await this.db.prisma.orm.public.Todo.create(input);
199
411
  {{else if usePrisma}}
200
412
  const todo = await this.db.prisma.todo.create({ data: input });
201
413
  return todo;
@@ -203,67 +415,135 @@ export class TodoService {
203
415
  const todo = await this.db.typeorm.getRepository(Todo).save(this.db.typeorm.getRepository(Todo).create(input));
204
416
  return todo;
205
417
  {{else if useDrizzle}}
418
+ {{#if hasSqlserver}}
419
+ const [todo] = await this.db.drizzle.insert(schema.todos).output().values(input);
420
+ {{else if hasMysql}}
421
+ const [inserted] = await this.db.drizzle.insert(schema.todos).values(input).$returningId();
422
+ if (!inserted) {
423
+ throw new NotFoundException("Todo not found");
424
+ }
425
+ const [todo] = await this.db.drizzle.select().from(schema.todos).where(eq(schema.todos.id, inserted.id));
426
+ {{else}}
206
427
  const [todo] = await this.db.drizzle.insert(schema.todos).values(input).returning();
428
+ {{/if}}
207
429
  return todo;
208
430
  {{/if}}
209
431
  }
210
432
 
433
+ {{#if isPrisma8}}
434
+ async update(id: string, input: UpdateTodoDto): Promise<Todo> {
435
+ {{else}}
211
436
  async update(id: string, input: UpdateTodoDto) {
437
+ {{/if}}
212
438
  {{#if isPrisma8}}
213
- return ((this.db.prisma.orm.public as any).Todo).where({ id }).update(input);
439
+ const todo = await this.db.prisma.orm.public.Todo.where({ id: Number(id) }).update(input);
440
+ if (!todo) {
441
+ throw new NotFoundException("Todo not found");
442
+ }
443
+ return todo;
214
444
  {{else if usePrisma}}
445
+ {{#if (and hasMongodb (not isPrisma8))}}
446
+ this.assertMongoId(id);
447
+ const existingTodo = await this.db.prisma.todo.findUnique({ where: { id } });
448
+ if (!existingTodo) {
449
+ throw new NotFoundException("Todo not found");
450
+ }
451
+ {{/if}}
215
452
  const result = await this.db.prisma.todo.update({ data: input, where: { id } });
216
453
  return result;
217
454
  {{else if useTypeorm}}
218
- const result = await this.db.typeorm.getRepository(Todo).update(id, input);
219
- return result;
455
+ const repository = this.db.typeorm.getRepository(Todo);
456
+ const result = await repository.update(id, input);
457
+ if (result.affected === 0) {
458
+ throw new NotFoundException("Todo not found");
459
+ }
460
+ const todo = await repository.findOneBy({ id });
461
+ if (!todo) {
462
+ throw new NotFoundException("Todo not found");
463
+ }
464
+ return todo;
220
465
  {{else if useDrizzle}}
466
+ {{#if hasSqlserver}}
467
+ const [todo] = await this.db.drizzle.update(schema.todos).set(input).output().where(eq(schema.todos.id, Number(id)));
468
+ if (!todo) {
469
+ throw new NotFoundException("Todo not found");
470
+ }
471
+ {{else if hasMysql}}
472
+ await this.db.drizzle.update(schema.todos).set(input).where(eq(schema.todos.id, Number(id)));
473
+ const [todo] = await this.db.drizzle.select().from(schema.todos).where(eq(schema.todos.id, Number(id)));
474
+ if (!todo) {
475
+ throw new NotFoundException("Todo not found");
476
+ }
477
+ {{else}}
221
478
  const [todo] = await this.db.drizzle.update(schema.todos).set(input).where(eq(schema.todos.id, Number(id))).returning();
479
+ {{/if}}
222
480
  return todo;
223
481
  {{/if}}
224
482
  }
225
483
 
226
484
  async delete(id: string) {
227
485
  {{#if isPrisma8}}
228
- await ((this.db.prisma.orm.public as any).Todo).where({ id }).delete();
486
+ await this.db.prisma.orm.public.Todo.where({ id: Number(id) }).delete();
229
487
  {{else if usePrisma}}
488
+ {{#if (and hasMongodb (not isPrisma8))}}
489
+ this.assertMongoId(id);
490
+ const existingTodo = await this.db.prisma.todo.findUnique({ where: { id } });
491
+ if (!existingTodo) {
492
+ throw new NotFoundException("Todo not found");
493
+ }
494
+ {{/if}}
230
495
  await this.db.prisma.todo.delete({ where: { id } });
231
496
  {{else if useTypeorm}}
232
497
  await this.db.typeorm.getRepository(Todo).delete(id);
233
498
  {{else if useDrizzle}}
499
+ {{#if hasSqlserver}}
500
+ const [todo] = await this.db.drizzle.delete(schema.todos).output().where(eq(schema.todos.id, Number(id)));
501
+ if (!todo) {
502
+ throw new NotFoundException("Todo not found");
503
+ }
504
+ {{else}}
234
505
  await this.db.drizzle.delete(schema.todos).where(eq(schema.todos.id, Number(id)));
506
+ {{/if}}
235
507
  {{/if}}
236
508
  return { message: "Todo deleted successfully" };
237
509
  }
238
510
  {{/if}}
239
511
  {{else}}
240
- findAll() {
512
+ findAll({{#if hasAuth}}authorId: string{{/if}}) {
513
+ {{#if hasAuth}}
514
+ return this.todos.filter((todo) => todo.authorId === authorId);
515
+ {{else}}
241
516
  return [...this.todos];
517
+ {{/if}}
242
518
  }
243
519
 
244
- create(input: CreateTodoDto) {
245
- const todo = { id: String(this.nextId++), ...input };
520
+ create(input: CreateTodoDto{{#if hasAuth}}, authorId: string{{/if}}) {
521
+ const id = String(this.nextId);
522
+ this.nextId += 1;
523
+ const todo = { id, ...input{{#if hasAuth}}, authorId{{/if}} };
246
524
  this.todos.push(todo);
247
525
  return todo;
248
526
  }
249
527
 
250
- update(id: string, input: UpdateTodoDto) {
251
- const todo = this.todos.find((t) => t.id === id);
528
+ update(id: string, input: UpdateTodoDto{{#if hasAuth}}, authorId: string{{/if}}) {
529
+ const todo = this.todos.find((item) => item.id === id{{#if hasAuth}} && item.authorId === authorId{{/if}});
252
530
  if (!todo) {
253
- return { message: "Todo not found" };
531
+ throw new NotFoundException("Todo not found");
254
532
  }
255
533
  Object.assign(todo, input);
256
534
  return todo;
257
535
  }
258
536
 
259
- async delete(id: string) {
260
- const index = this.todos.findIndex((t) => t.id === id);
261
- if (index >= 0) {
262
- this.todos.splice(index, 1);
537
+ delete(id: string{{#if hasAuth}}, authorId: string{{/if}}) {
538
+ const index = this.todos.findIndex((item) => item.id === id{{#if hasAuth}} && item.authorId === authorId{{/if}});
539
+ if (index === -1) {
540
+ throw new NotFoundException("Todo not found");
263
541
  }
542
+ this.todos.splice(index, 1);
264
543
  return { message: "Todo deleted successfully" };
265
544
  }
266
545
  {{/if}}
267
546
  }
268
547
 
269
548
  {{/if}}
549
+ {{/if}}
@@ -51,7 +51,7 @@ async function bootstrap() {
51
51
  {{/if}}
52
52
  {{#if (includes apis "trpc")}}
53
53
  trpc: {
54
- routerFilePath: "./src/libs/trpc/@generated/server.ts",
54
+ routerFilePath: "./{{trpcGeneratePath}}/server.ts",
55
55
  pathPrefix: "/trpc",
56
56
  },
57
57
  {{/if}}
@@ -79,7 +79,7 @@ async function bootstrap() {
79
79
  {{/if}}
80
80
  {{#if (includes apis "trpc")}}
81
81
  trpc: {
82
- routerFilePath: "./src/trpc/router.ts",
82
+ routerFilePath: "./{{trpcGeneratePath}}/server.ts",
83
83
  pathPrefix: "/trpc",
84
84
  },
85
85
  {{/if}}
@@ -4,10 +4,14 @@
4
4
 
5
5
  ## Setup
6
6
 
7
+ {{#if setupInstructions}}
8
+ {{{setupInstructions}}}
9
+ {{else}}
7
10
  ```bash
8
11
  # Install dependencies
9
12
  {{#if isPnpm}}pnpm install{{else if isYarn}}yarn install{{else if isBun}}bun install{{else}}npm install{{/if}}
10
13
  ```
14
+ {{/if}}
11
15
 
12
16
  ## Running the App
13
17
 
@@ -35,20 +39,11 @@
35
39
  {{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
36
40
  ## Auth Setup
37
41
 
38
- This project uses **Better Auth**. Generate the database schema by running:
39
-
40
- ```bash
41
- {{#if isPnpm}}pnpm dlx auth@latest generate --config src/auth/auth.ts --output src/database/orm/prisma/schema.prisma -y && pnpm run prisma:format{{else if isYarn}}yarn dlx auth@latest generate --config src/auth/auth.ts --output src/database/orm/prisma/schema.prisma -y && yarn run prisma:format && pnpm run prisma:format{{else if isBun}}bun x auth@latest generate --config src/auth/auth.ts --output src/database/orm/prisma/schema.prisma -y && bun run prisma:format{{else}}npx auth@latest generate --config src/auth/auth.ts --output src/database/orm/prisma/schema.prisma -y && npm run prisma:format{{/if}}
42
- ```
43
-
44
- {{#if useDrizzle}}Then run Drizzle migrations:
45
-
46
- ```bash
47
- {{#if isPnpm}}pnpm drizzle-kit generate && pnpm drizzle-kit migrate{{else if isYarn}}yarn drizzle-kit generate && yarn drizzle-kit migrate{{else}}npx drizzle-kit generate && npx drizzle-kit migrate{{/if}}
48
- ```
49
-
42
+ {{#if (eq auth "better-auth:stateless")}}
43
+ Configure the Better Auth secret, URL and external OIDC provider settings. Register the callback URL with your provider. Stateless auth requires no authentication schema generation or database migration.
44
+ {{else}}
45
+ Follow the ordered steps in Setup. Run the generated `auth:generate` script in `apps/api-gateway` before applying the database schema and regenerating Prisma Client in `packages/db`. The script uses the installed CLI version and preserves application-owned models.
50
46
  {{/if}}
51
- See https://better-auth.com/docs/adapters/prisma for more details.
52
47
 
53
48
  ### Usage
54
49
 
@@ -1,4 +1,4 @@
1
- CORS_ORIGIN=http://localhost:3001
1
+ CORS_ORIGIN=http://localhost:3000
2
2
  PORT=3000
3
3
  {{#if hasGraphql}}
4
4
  GRAPHQL_PLAYGROUND=true
@@ -25,7 +25,11 @@ SQLSERVER_TRUST_SERVER_CERTIFICATE=true
25
25
  {{#if hasMongodb}}
26
26
  MONGODB_URL=mongodb://localhost:27017/{{projectNameKebab}}_db
27
27
  {{/if}}
28
- {{#if (eq auth "passport")}}
28
+ {{#if (and (eq auth "passport") (not hasDatabase))}}
29
+ OIDC_JWKS_URI=https://identity.example.com/.well-known/jwks.json
30
+ OIDC_ISSUER=https://identity.example.com/
31
+ OIDC_AUDIENCE=generated-resource-server
32
+ {{else if (eq auth "passport")}}
29
33
  JWT_ACCESS_SECRET=change-me-to-a-random-secret-at-least-32-characters-long
30
34
  {{#if hasDatabase}}
31
35
  JWT_REFRESH_SECRET=change-me-to-a-different-random-secret-at-least-32-characters
@@ -12,5 +12,11 @@ allowBuilds:
12
12
  {{#if hasSqlite}}
13
13
  better-sqlite3: true
14
14
  {{/if}}
15
+ {{#if hasTrpc}}
16
+ peerDependencyRules:
17
+ allowedVersions:
18
+ "nestjs-trpc>@nestjs/common": "^12.0.0"
19
+ "nestjs-trpc>@nestjs/core": "^12.0.0"
20
+ {{/if}}
15
21
  catalog:
16
22
  dotenv: ^17.2.2
@@ -71,8 +71,8 @@ async function bootstrap() {
71
71
  {{/if}}
72
72
  {{#if (includes apis "trpc")}}
73
73
  trpc: {
74
- routerFilePath: "./src/trpc/router.ts",
75
74
  pathPrefix: "/trpc",
75
+ routerFilePath: "./{{trpcGeneratePath}}/server.ts",
76
76
  },
77
77
  {{/if}}
78
78
  zod: {
@@ -99,8 +99,8 @@ async function bootstrap() {
99
99
  {{/if}}
100
100
  {{#if (includes apis "trpc")}}
101
101
  trpc: {
102
- routerFilePath: "./src/trpc/router.ts",
103
102
  pathPrefix: "/trpc",
103
+ routerFilePath: "./{{trpcGeneratePath}}/server.ts",
104
104
  },
105
105
  {{/if}}
106
106
  zod: {
@@ -43,7 +43,7 @@ async function bootstrap() {
43
43
  {{/if}}
44
44
  {{#if (includes apis "trpc")}}
45
45
  trpc: {
46
- routerFilePath: "./src/trpc/router.ts",
46
+ routerFilePath: "./{{trpcGeneratePath}}/server.ts",
47
47
  pathPrefix: "/trpc",
48
48
  },
49
49
  {{/if}}
@@ -71,7 +71,7 @@ async function bootstrap() {
71
71
  {{/if}}
72
72
  {{#if (includes apis "trpc")}}
73
73
  trpc: {
74
- routerFilePath: "./src/trpc/router.ts",
74
+ routerFilePath: "./{{trpcGeneratePath}}/server.ts",
75
75
  pathPrefix: "/trpc",
76
76
  },
77
77
  {{/if}}