@nest-arch/tui 0.4.6 → 0.5.0

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 (42) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/constants-DX5wiqrq.js +1 -0
  3. package/dist/index.js +145 -133
  4. package/dist/templates/addons/husky/pre-commit.hbs +1 -1
  5. package/dist/templates/base/.env.example.hbs +7 -2
  6. package/dist/templates/base/.env.hbs +7 -2
  7. package/dist/templates/base/README.md.hbs +11 -2
  8. package/dist/templates/base/pnpm-workspace.yaml.hbs +9 -4
  9. package/dist/templates/base/prisma.config.ts.hbs +5 -0
  10. package/dist/templates/base/src/app.module.ts.hbs +5 -22
  11. package/dist/templates/base/src/database/adapters/mongo/raw-mongo.adapter.ts.hbs +4 -2
  12. package/dist/templates/base/src/database/db.module.ts.hbs +15 -1
  13. package/dist/templates/base/src/database/db.service.ts.hbs +6 -3
  14. package/dist/templates/base/src/database/entities/todo.entity.ts.hbs +2 -2
  15. package/dist/templates/base/src/database/index.ts.hbs +2 -0
  16. package/dist/templates/base/src/database/orm/drizzle/schema.ts.hbs +48 -12
  17. package/dist/templates/base/src/database/orm/typeorm/data-source.ts.hbs +26 -10
  18. package/dist/templates/base/src/libs/middlewares/graphql-throttler.guard.ts.hbs +22 -0
  19. package/dist/templates/base/src/libs/trpc/inner.context.ts.hbs +2 -2
  20. package/dist/templates/base/src/main.ts.hbs +2 -2
  21. package/dist/templates/base/test/app.e2e-spec.ts.hbs +368 -196
  22. package/dist/templates/extras/docker/Dockerfile.hbs +8 -1
  23. package/dist/templates/extras/health/src/health/health.controller.ts.hbs +7 -1
  24. package/dist/templates/extras/swagger/create-docs.ts.hbs +6 -1
  25. package/dist/templates/feature/graphql/src/graphql/models/todo.model.ts.hbs +1 -1
  26. package/dist/templates/feature/graphql/src/graphql/resolvers/todo.resolver.ts.hbs +1 -1
  27. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.controller.ts.hbs +80 -7
  28. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.service.ts.hbs +181 -25
  29. package/dist/templates/monorepo/apps/api-gateway/src/main.ts.hbs +2 -2
  30. package/dist/templates/monorepo/root/README.md.hbs +8 -13
  31. package/dist/templates/single-project/architecture/nest-api/.env.hbs +6 -2
  32. package/dist/templates/single-project/architecture/nest-api/pnpm-workspace.yaml.hbs +6 -0
  33. package/dist/templates/single-project/architecture/nest-api/src/main.ts.hbs +2 -2
  34. package/dist/templates/single-project/architecture/nest-gateway/src/main.ts.hbs +2 -2
  35. package/dist/templates/single-project/architecture/nest-microservice/.env.hbs +6 -0
  36. package/dist/templates/single-project/architecture/nest-microservice/src/app.controller.ts.hbs +2 -2
  37. package/dist/templates/single-project/architecture/nest-microservice/src/app.module.ts.hbs +28 -1
  38. package/dist/templates/single-project/architecture/nest-microservice/src/http-throttler.guard.ts.hbs +13 -0
  39. package/dist/templates/single-project/architecture/nest-microservice/src/main.ts.hbs +2 -2
  40. package/dist/templates/single-project/architecture/nest-microservice/test/microservice.e2e-spec.ts.hbs +35 -0
  41. package/package.json +5 -5
  42. package/dist/constants-DVhgS48N.js +0 -1
@@ -1,5 +1,9 @@
1
1
  FROM node:22-alpine
2
2
 
3
+ {{#if hasSqlite}}
4
+ RUN apk add --no-cache python3 make g++
5
+ {{/if}}
6
+
3
7
  WORKDIR /app
4
8
 
5
9
  {{#if (eq packageManager "pnpm")}}
@@ -10,7 +14,10 @@ RUN corepack enable
10
14
  {{/if}}
11
15
 
12
16
  COPY . .
13
- RUN POSTGRES_URL=postgresql://postgres:postgres@postgres:5432/build_db MYSQL_URL=mysql://root:mysql@mysql:3306/build_db MONGODB_URL=mongodb://mongodb:27017/build_db {{#if hasSqlserver}}SQLSERVER_HOST=localhost SQLSERVER_PORT=1433 SQLSERVER_DATABASE=build_db SQLSERVER_USER=sa SQLSERVER_PASSWORD=Build_only_Password_2026!X9 SQLSERVER_ENCRYPT=true SQLSERVER_TRUST_SERVER_CERTIFICATE=true {{/if}}{{#if (eq auth "passport")}}JWT_ACCESS_SECRET=build-only-access-secret-that-is-long-enough JWT_REFRESH_SECRET=build-only-refresh-secret-that-is-long-enough {{/if}}{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}BETTER_AUTH_SECRET=build-only-better-auth-secret-that-is-long-enough BETTER_AUTH_URL=http://localhost:{{#if (eq httpProvider "fastify")}}3001{{else}}3000{{/if}} {{/if}}{{#if (eq packageManager "pnpm")}}pnpm install --no-lockfile{{else if (eq packageManager "yarn")}}yarn install{{else if (eq packageManager "bun")}}bun install{{/if}}
17
+ RUN POSTGRES_URL=postgresql://postgres:postgres@postgres:5432/build_db MYSQL_URL=mysql://root:mysql@mysql:3306/build_db MONGODB_URL=mongodb://mongodb:27017/build_db {{#if hasSqlserver}}SQLSERVER_HOST=localhost SQLSERVER_PORT=1433 SQLSERVER_DATABASE=build_db SQLSERVER_USER=sa SQLSERVER_PASSWORD=Build_only_Password_2026!X9 SQLSERVER_ENCRYPT=true SQLSERVER_TRUST_SERVER_CERTIFICATE=true {{/if}}{{#if (eq auth "passport")}}JWT_ACCESS_SECRET=build-only-access-secret-that-is-long-enough JWT_REFRESH_SECRET=build-only-refresh-secret-that-is-long-enough {{/if}}{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}BETTER_AUTH_SECRET=build-only-better-auth-secret-that-is-long-enough BETTER_AUTH_URL=http://localhost:{{#if (eq httpProvider "fastify")}}3001{{else}}3000{{/if}} {{#if (eq auth "better-auth:stateless")}}OIDC_PROVIDER_ID=build-only OIDC_CLIENT_ID=build-only OIDC_CLIENT_SECRET=build-only OIDC_DISCOVERY_URL=https://example.invalid/.well-known/openid-configuration {{/if}}{{/if}}{{#if (eq packageManager "pnpm")}}pnpm install --no-lockfile{{else if (eq packageManager "yarn")}}yarn install{{else if (eq packageManager "bun")}}bun install{{/if}}
18
+ {{#each dockerBuildSetupCommands}}
19
+ RUN POSTGRES_URL=postgresql://postgres:postgres@postgres:5432/build_db MYSQL_URL=mysql://root:mysql@mysql:3306/build_db MONGODB_URL=mongodb://mongodb:27017/build_db SQLITE_PATH=/tmp/build.db {{#if (eq ../auth "passport")}}JWT_ACCESS_SECRET=build-only-access-secret-that-is-long-enough JWT_REFRESH_SECRET=build-only-refresh-secret-that-is-long-enough {{/if}}{{#if (or (eq ../auth "better-auth") (eq ../auth "better-auth:stateless"))}}BETTER_AUTH_SECRET=build-only-better-auth-secret-that-is-long-enough BETTER_AUTH_URL=http://localhost:{{#if (eq ../httpProvider "fastify")}}3001{{else}}3000{{/if}} {{#if (eq ../auth "better-auth:stateless")}}OIDC_PROVIDER_ID=build-only OIDC_CLIENT_ID=build-only OIDC_CLIENT_SECRET=build-only OIDC_DISCOVERY_URL=https://example.invalid/.well-known/openid-configuration {{/if}}{{/if}}{{this}}
20
+ {{/each}}
14
21
  RUN {{#if (eq packageManager "pnpm")}}pnpm run{{else if (eq packageManager "yarn")}}yarn{{else if (eq packageManager "bun")}}bun run{{else}}npm run{{/if}} build
15
22
 
16
23
  ENV NODE_ENV=production
@@ -34,7 +34,13 @@ export class HealthController {
34
34
  {{else}}
35
35
  await this.db.raw.mongo.command({ ping: 1 });
36
36
  {{/if}}
37
- {{else if (or usePrisma isPrisma8)}}
37
+ {{else if isPrisma8}}
38
+ {{#if hasTodoExample}}
39
+ await this.db.prisma.orm.public.Todo.all();
40
+ {{else}}
41
+ await this.db.prisma.connect();
42
+ {{/if}}
43
+ {{else if usePrisma}}
38
44
  await this.db.prisma.$queryRaw`SELECT 1`;
39
45
  {{else if useDrizzle}}
40
46
  {{#if hasSqlite}}
@@ -1,5 +1,6 @@
1
1
 
2
2
  import type { INestApplication } from "@nestjs/common";
3
+ import { Logger } from "@nestjs/common";
3
4
  import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
4
5
  import type { OpenAPIObject } from "@nestjs/swagger";
5
6
 
@@ -168,7 +169,11 @@ async function applyTrpcSpec(options?: NonNullable<DocsIntegrations["trpc"]>) {
168
169
  }
169
170
 
170
171
  return trpcSpec;
171
- } catch {
172
+ } catch (error) {
173
+ Logger.warn(
174
+ `Could not generate tRPC documentation from ${options.routerFilePath}: ${error instanceof Error ? error.message : String(error)}`,
175
+ "SwaggerDocs"
176
+ );
172
177
  return null;
173
178
  }
174
179
  }
@@ -1,4 +1,4 @@
1
- import { Field, ID, ObjectType } from "@nestjs/graphql";
1
+ import { Field{{#if hasAuth}}, ID{{/if}}, ObjectType } from "@nestjs/graphql";
2
2
 
3
3
  import { BaseModel } from "./base.model.js";
4
4
  {{#if hasAuth}}
@@ -52,7 +52,7 @@ import { GraphRelationBuilder } from "typeorm-relations-graphql";
52
52
  import { Todo as TodoEntity } from "../../database/entities/todo.entity.js";
53
53
  {{/if}}
54
54
  {{#if (and hasDatabase useDrizzle)}}
55
- import { and, eq } from "drizzle-orm";
55
+ import { {{#if hasAuth}}and, {{/if}}eq } from "drizzle-orm";
56
56
  import * as schema from "../../database/orm/drizzle/schema.js";
57
57
  {{/if}}
58
58
  {{#if hasDatabase}}
@@ -6,7 +6,10 @@ import {
6
6
  Param,
7
7
  Post,
8
8
  Put,
9
- {{#if (and isPassportAuth hasDatabase)}}
9
+ {{#if (eq auth "better-auth:stateless")}}
10
+ UnauthorizedException,
11
+ {{/if}}
12
+ {{#if isPassportAuth}}
10
13
  UseGuards,
11
14
  {{/if}}
12
15
  {{#if (and isBetterAuth hasDatabase hasGraphql)}}
@@ -31,7 +34,11 @@ import {
31
34
  import { Session } from "@thallesp/nestjs-better-auth";
32
35
  import type { UserSession } from "../../auth/auth.js";
33
36
  {{/if}}
34
- {{#if (and isPassportAuth hasDatabase)}}
37
+ {{#if (and isBetterAuth (not hasDatabase))}}
38
+ import { Session } from "@thallesp/nestjs-better-auth";
39
+ import type { UserSession } from "../../auth/auth.js";
40
+ {{/if}}
41
+ {{#if isPassportAuth}}
35
42
  import { RestAuthGuard } from "../../auth/guards/rest-auth.guard.js";
36
43
  import { CurrentUser } from "../../auth/decorators/current-user.decorator.js";
37
44
  {{/if}}
@@ -41,16 +48,29 @@ import { RestAuthGuard } from "../../auth/guards/rest-auth.guard.js";
41
48
  import { TodoService } from "./todo.service.js";
42
49
  import { CreateTodoDto } from "./dto/create-todo.dto.js";
43
50
  import { UpdateTodoDto } from "./dto/update-todo.dto.js";
51
+ {{#if isPrisma8}}
52
+ import type { Models } from "../../prisma/contract.js";
53
+
54
+ type Todo = Models.public_Todo;
55
+ {{/if}}
44
56
 
45
57
  {{#if swagger}}
46
58
  @ApiTags("Todos")
47
59
  {{/if}}
48
60
  @Controller("todos")
49
- {{#if (or (and isPassportAuth hasDatabase) (and isBetterAuth hasDatabase hasGraphql))}}
61
+ {{#if (or isPassportAuth (and isBetterAuth hasDatabase hasGraphql))}}
50
62
  @UseGuards(RestAuthGuard)
51
63
  {{/if}}
52
64
  export class TodoController {
53
65
  constructor(private readonly todoService: TodoService) {}
66
+ {{#if (eq auth "better-auth:stateless")}}
67
+ private requireUserId(session: UserSession | null | undefined): string {
68
+ if (!session?.user?.id) {
69
+ throw new UnauthorizedException("Authentication required");
70
+ }
71
+ return session.user.id;
72
+ }
73
+ {{/if}}
54
74
 
55
75
  @Get()
56
76
  {{#if swagger}}
@@ -63,7 +83,7 @@ export class TodoController {
63
83
  @ApiUnauthorizedResponse({ description: "Unauthorized" })
64
84
  {{/if}}
65
85
  {{/if}}
66
- {{#if (and isPassportAuth hasDatabase)}}
86
+ {{#if isPassportAuth}}
67
87
  findAll(@CurrentUser() user: { id: string }) {
68
88
  return this.todoService.findAll(user.id);
69
89
  }
@@ -75,10 +95,20 @@ export class TodoController {
75
95
  {{/if}}
76
96
  return this.todoService.findAll(session.user.id);
77
97
  }
98
+ {{else if isBetterAuth}}
99
+ findAll(@Session() session: UserSession | null) {
100
+ return this.todoService.findAll(this.requireUserId(session));
101
+ }
102
+ {{else}}
103
+ {{#if isPrisma8}}
104
+ async findAll(): Promise<Todo[]> {
105
+ return await this.todoService.findAll();
106
+ }
78
107
  {{else}}
79
108
  findAll() {
80
109
  return this.todoService.findAll();
81
110
  }
111
+ {{/if}}
82
112
  {{/if}}
83
113
 
84
114
  @Post()
@@ -92,7 +122,7 @@ export class TodoController {
92
122
  @ApiUnauthorizedResponse({ description: "Unauthorized" })
93
123
  {{/if}}
94
124
  {{/if}}
95
- {{#if (and isPassportAuth hasDatabase)}}
125
+ {{#if isPassportAuth}}
96
126
  create(
97
127
  @Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: CreateTodoDto.schema }){{/if}} input: CreateTodoDto,
98
128
  @CurrentUser() user: { id: string }
@@ -106,10 +136,23 @@ export class TodoController {
106
136
  ) {
107
137
  return this.todoService.create(input, session.user.id);
108
138
  }
139
+ {{else if isBetterAuth}}
140
+ create(
141
+ @Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: CreateTodoDto.schema }){{/if}} input: CreateTodoDto,
142
+ @Session() session: UserSession | null
143
+ ) {
144
+ return this.todoService.create(input, this.requireUserId(session));
145
+ }
146
+ {{else}}
147
+ {{#if isPrisma8}}
148
+ async create(@Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: CreateTodoDto.schema }){{/if}} input: CreateTodoDto): Promise<Todo> {
149
+ return await this.todoService.create(input);
150
+ }
109
151
  {{else}}
110
152
  create(@Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: CreateTodoDto.schema }){{/if}} input: CreateTodoDto) {
111
153
  return this.todoService.create(input);
112
154
  }
155
+ {{/if}}
113
156
  {{/if}}
114
157
 
115
158
  @Put(":id")
@@ -123,7 +166,7 @@ export class TodoController {
123
166
  @ApiUnauthorizedResponse({ description: "Unauthorized" })
124
167
  {{/if}}
125
168
  {{/if}}
126
- {{#if (and isPassportAuth hasDatabase)}}
169
+ {{#if isPassportAuth}}
127
170
  update(
128
171
  @Param("id") id: string,
129
172
  @Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: UpdateTodoDto.schema }){{/if}} input: UpdateTodoDto,
@@ -139,6 +182,22 @@ export class TodoController {
139
182
  ) {
140
183
  return this.todoService.update(id, input, session.user.id);
141
184
  }
185
+ {{else if isBetterAuth}}
186
+ update(
187
+ @Param("id") id: string,
188
+ @Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: UpdateTodoDto.schema }){{/if}} input: UpdateTodoDto,
189
+ @Session() session: UserSession | null
190
+ ) {
191
+ return this.todoService.update(id, input, this.requireUserId(session));
192
+ }
193
+ {{else}}
194
+ {{#if isPrisma8}}
195
+ async update(
196
+ @Param("id") id: string,
197
+ @Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: UpdateTodoDto.schema }){{/if}} input: UpdateTodoDto
198
+ ): Promise<Todo> {
199
+ return await this.todoService.update(id, input);
200
+ }
142
201
  {{else}}
143
202
  update(
144
203
  @Param("id") id: string,
@@ -146,6 +205,7 @@ export class TodoController {
146
205
  ) {
147
206
  return this.todoService.update(id, input);
148
207
  }
208
+ {{/if}}
149
209
  {{/if}}
150
210
 
151
211
  @Delete(":id")
@@ -159,7 +219,7 @@ export class TodoController {
159
219
  @ApiUnauthorizedResponse({ description: "Unauthorized" })
160
220
  {{/if}}
161
221
  {{/if}}
162
- {{#if (and isPassportAuth hasDatabase)}}
222
+ {{#if isPassportAuth}}
163
223
  delete(
164
224
  @Param("id") id: string,
165
225
  @CurrentUser() user: { id: string }
@@ -173,9 +233,22 @@ export class TodoController {
173
233
  ) {
174
234
  return this.todoService.delete(id, session.user.id);
175
235
  }
236
+ {{else if isBetterAuth}}
237
+ delete(
238
+ @Param("id") id: string,
239
+ @Session() session: UserSession | null
240
+ ) {
241
+ return this.todoService.delete(id, this.requireUserId(session));
242
+ }
243
+ {{else}}
244
+ {{#if isPrisma8}}
245
+ async delete(@Param("id") id: string): Promise<{ message: string }> {
246
+ return await this.todoService.delete(id);
247
+ }
176
248
  {{else}}
177
249
  delete(@Param("id") id: string) {
178
250
  return this.todoService.delete(id);
179
251
  }
180
252
  {{/if}}
253
+ {{/if}}
181
254
  }
@@ -14,13 +14,20 @@ function objectId(id: string): ObjectId {
14
14
  export class TodoService {
15
15
  constructor(private readonly db: DbService) {}
16
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); }
17
+ async findAll() {
18
+ const todos = await this.todos.find().sort({ _id: 1 }).limit(100).toArray();
19
+ return todos.map(serialize);
20
+ }
18
21
  async create(input: CreateTodoDto) {
19
22
  const todo = { title: input.title, completed: input.completed ?? false, ...(input.description === undefined ? {} : { description: input.description }) };
20
23
  const result = await this.todos.insertOne(todo);
21
24
  return { ...todo, id: result.insertedId.toHexString() };
22
25
  }
26
+ {{#if isPrisma8}}
27
+ update(id: string, input: UpdateTodoDto) {
28
+ {{else}}
23
29
  async update(id: string, input: UpdateTodoDto) {
30
+ {{/if}}
24
31
  const todo = await this.todos.findOneAndUpdate({ _id: objectId(id) }, { $set: input }, { returnDocument: "after" });
25
32
  if (!todo) throw new NotFoundException("Todo not found");
26
33
  return serialize(todo);
@@ -32,8 +39,8 @@ export class TodoService {
32
39
  }
33
40
  }
34
41
  {{else}}
35
- {{#if (and hasDatabase hasAuth)}}
36
- import { Injectable, NotFoundException } from "@nestjs/common";
42
+ {{#if (or hasTodoExample hasAuth isPrisma8 (and hasDatabase useTypeorm) (and hasDatabase useDrizzle hasMysql))}}
43
+ import { Injectable, NotFoundException{{#if (and hasAuth hasPostgres useRawSql)}}, type OnModuleInit{{/if}} } from "@nestjs/common";
37
44
  {{else}}
38
45
  import { Injectable } from "@nestjs/common";
39
46
  {{/if}}
@@ -54,31 +61,74 @@ import { eq } from "drizzle-orm";
54
61
  {{#if useTypeorm}}
55
62
  import { Todo } from "../../database/entities/todo.entity.js";
56
63
  {{/if}}
64
+ {{#if (and hasAuth hasPostgres useRawSql)}}
65
+ import type { Pool } from "pg";
66
+ {{/if}}
57
67
  {{/if}}
58
68
  import { CreateTodoDto } from "./dto/create-todo.dto.js";
59
69
  import { UpdateTodoDto } from "./dto/update-todo.dto.js";
70
+ {{#if isPrisma8}}
71
+ import type { Models } from "../../prisma/contract.js";
72
+
73
+ type Todo = Models.public_Todo;
74
+ {{/if}}
60
75
 
61
76
  @Injectable()
77
+ {{#if (and hasAuth hasPostgres useRawSql)}}
78
+ export class TodoService implements OnModuleInit {
79
+ {{else}}
62
80
  export class TodoService {
81
+ {{/if}}
63
82
  {{#if hasDatabase}}
64
83
  constructor(private readonly db: DbService) {}
65
84
  {{else}}
66
- private todos: Array<{
85
+ private todos: {
86
+ {{#if hasAuth}}
87
+ authorId: string;
88
+ {{/if}}
67
89
  completed: boolean;
68
90
  description?: string;
69
91
  id: string;
70
92
  title: string;
71
- }> = [];
93
+ }[] = [];
72
94
  private nextId = 1;
73
95
  {{/if}}
74
96
 
97
+ {{#if (and hasAuth hasPostgres useRawSql)}}
98
+ async onModuleInit(): Promise<void> {
99
+ const pool = this.db.raw.sql as Pool;
100
+ await pool.query(`CREATE TABLE IF NOT EXISTS todos (
101
+ id SERIAL PRIMARY KEY,
102
+ title TEXT NOT NULL,
103
+ completed BOOLEAN NOT NULL DEFAULT FALSE,
104
+ description TEXT,
105
+ author_id TEXT NOT NULL,
106
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
107
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
108
+ )`);
109
+ }
110
+
111
+ {{/if}}
75
112
  {{#if hasDatabase}}
76
113
  {{#if hasAuth}}
114
+ {{#if isPrisma8}}
115
+ async findAll(authorId: string): Promise<Todo[]> {
116
+ {{else if (and hasPostgres useRawSql)}}
117
+ async findAll(authorId: string) {
118
+ {{else}}
77
119
  findAll(authorId: string) {
120
+ {{/if}}
78
121
  {{#if isPrisma8}}
79
- return ((this.db.prisma.orm.public as any).Todo).where({ authorId }).all();
122
+ return await this.db.prisma.orm.public.Todo.where({ authorId }).all();
80
123
  {{else if usePrisma}}
81
124
  return this.db.prisma.todo.findMany({ where: { authorId } });
125
+ {{else if (and hasPostgres useRawSql)}}
126
+ const pool = this.db.raw.sql as Pool;
127
+ const result = await pool.query(
128
+ 'SELECT id, title, completed, description, author_id AS "authorId" FROM todos WHERE author_id = $1 ORDER BY id',
129
+ [authorId]
130
+ );
131
+ return result.rows;
82
132
  {{else if useTypeorm}}
83
133
  return this.db.typeorm.getRepository(Todo).find({ where: { authorId } });
84
134
  {{else if useDrizzle}}
@@ -86,16 +136,32 @@ export class TodoService {
86
136
  {{/if}}
87
137
  }
88
138
 
139
+ {{#if isPrisma8}}
140
+ async create(input: CreateTodoDto, authorId: string): Promise<Todo> {
141
+ {{else}}
89
142
  async create(input: CreateTodoDto, authorId: string) {
143
+ {{/if}}
90
144
  {{#if isPrisma8}}
91
- return ((this.db.prisma.orm.public as any).Todo).create({ ...input, authorId });
145
+ return await this.db.prisma.orm.public.Todo.create({ ...input, authorId });
92
146
  {{else if usePrisma}}
93
147
  const todo = await this.db.prisma.todo.create({ data: { ...input, authorId } });
94
148
  return todo;
149
+ {{else if (and hasPostgres useRawSql)}}
150
+ const pool = this.db.raw.sql as Pool;
151
+ const result = await pool.query(
152
+ 'INSERT INTO todos (title, completed, description, author_id) VALUES ($1, $2, $3, $4) RETURNING id, title, completed, description, author_id AS "authorId"',
153
+ [input.title, input.completed ?? false, input.description ?? null, authorId]
154
+ );
155
+ const [todo] = result.rows;
156
+ return todo;
95
157
  {{else if useTypeorm}}
96
158
  const todo = await this.db.typeorm.getRepository(Todo).save(this.db.typeorm.getRepository(Todo).create({ ...input, authorId }));
97
159
  return todo;
98
160
  {{else if useDrizzle}}
161
+ {{#if hasSqlserver}}
162
+ const [todo] = await this.db.drizzle.insert(schema.todos).output().values({ ...input, authorId });
163
+ return todo;
164
+ {{else}}
99
165
  {{#if hasMysql}}
100
166
  const [inserted] = await this.db.drizzle.insert(schema.todos).values({ ...input, authorId }).$returningId();
101
167
  if (!inserted) {
@@ -107,12 +173,13 @@ export class TodoService {
107
173
  const [todo] = await this.db.drizzle.insert(schema.todos).values({ ...input, authorId }).returning();
108
174
  return todo;
109
175
  {{/if}}
176
+ {{/if}}
110
177
  {{/if}}
111
178
  }
112
179
 
113
180
  async update(id: string, input: UpdateTodoDto, authorId: string) {
114
181
  {{#if isPrisma8}}
115
- const result = await ((this.db.prisma.orm.public as any).Todo).where({ authorId, id }).update(input);
182
+ const result = await this.db.prisma.orm.public.Todo.where({ authorId, id: Number(id) }).update(input);
116
183
  if (!result) {
117
184
  throw new NotFoundException("Todo not found");
118
185
  }
@@ -123,6 +190,17 @@ export class TodoService {
123
190
  throw new NotFoundException("Todo not found");
124
191
  }
125
192
  return this.db.prisma.todo.update({ data: input, where: { id } });
193
+ {{else if (and hasPostgres useRawSql)}}
194
+ const pool = this.db.raw.sql as Pool;
195
+ const result = await pool.query(
196
+ '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"',
197
+ [input.title ?? null, input.completed ?? null, input.description ?? null, id, authorId]
198
+ );
199
+ const [todo] = result.rows;
200
+ if (!todo) {
201
+ throw new NotFoundException("Todo not found");
202
+ }
203
+ return todo;
126
204
  {{else if useTypeorm}}
127
205
  const repository = this.db.typeorm.getRepository(Todo);
128
206
  const result = await repository.update({ authorId, id }, input);
@@ -138,6 +216,8 @@ export class TodoService {
138
216
  {{#if hasMysql}}
139
217
  await this.db.drizzle.update(schema.todos).set(input).where(and(eq(schema.todos.authorId, authorId), eq(schema.todos.id, Number(id))));
140
218
  const [todo] = await this.db.drizzle.select().from(schema.todos).where(and(eq(schema.todos.authorId, authorId), eq(schema.todos.id, Number(id))));
219
+ {{else if hasSqlserver}}
220
+ 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
221
  {{else}}
142
222
  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
223
  {{/if}}
@@ -150,7 +230,7 @@ export class TodoService {
150
230
 
151
231
  async delete(id: string, authorId: string) {
152
232
  {{#if isPrisma8}}
153
- const count = await ((this.db.prisma.orm.public as any).Todo).where({ authorId, id }).delete();
233
+ const count = await this.db.prisma.orm.public.Todo.where({ authorId, id }).delete();
154
234
  if (count === 0) {
155
235
  throw new NotFoundException("Todo not found");
156
236
  }
@@ -159,6 +239,16 @@ export class TodoService {
159
239
  if (result.count === 0) {
160
240
  throw new NotFoundException("Todo not found");
161
241
  }
242
+ {{else if (and hasPostgres useRawSql)}}
243
+ const pool = this.db.raw.sql as Pool;
244
+ const result = await pool.query(
245
+ 'DELETE FROM todos WHERE id = $1 AND author_id = $2 RETURNING id',
246
+ [id, authorId]
247
+ );
248
+ const [todo] = result.rows;
249
+ if (!todo) {
250
+ throw new NotFoundException("Todo not found");
251
+ }
162
252
  {{else if useTypeorm}}
163
253
  const result = await this.db.typeorm.getRepository(Todo).delete({ authorId, id });
164
254
  if (result.affected === 0) {
@@ -171,6 +261,11 @@ export class TodoService {
171
261
  throw new NotFoundException("Todo not found");
172
262
  }
173
263
  await this.db.drizzle.delete(schema.todos).where(and(eq(schema.todos.authorId, authorId), eq(schema.todos.id, Number(id))));
264
+ {{else if hasSqlserver}}
265
+ const [todo] = await this.db.drizzle.delete(schema.todos).output().where(and(eq(schema.todos.authorId, authorId), eq(schema.todos.id, Number(id))));
266
+ if (!todo) {
267
+ throw new NotFoundException("Todo not found");
268
+ }
174
269
  {{else}}
175
270
  const [todo] = await this.db.drizzle.delete(schema.todos).where(and(eq(schema.todos.authorId, authorId), eq(schema.todos.id, Number(id)))).returning();
176
271
  if (!todo) {
@@ -180,10 +275,14 @@ export class TodoService {
180
275
  {{/if}}
181
276
  return { message: "Todo deleted successfully" };
182
277
  }
278
+ {{else}}
279
+ {{#if isPrisma8}}
280
+ async findAll(): Promise<Todo[]> {
183
281
  {{else}}
184
282
  findAll() {
283
+ {{/if}}
185
284
  {{#if isPrisma8}}
186
- return ((this.db.prisma.orm.public as any).Todo).all();
285
+ return await this.db.prisma.orm.public.Todo.all();
187
286
  {{else if usePrisma}}
188
287
  return this.db.prisma.todo.findMany();
189
288
  {{else if useTypeorm}}
@@ -193,9 +292,13 @@ export class TodoService {
193
292
  {{/if}}
194
293
  }
195
294
 
295
+ {{#if isPrisma8}}
296
+ async create(input: CreateTodoDto): Promise<Todo> {
297
+ {{else}}
196
298
  async create(input: CreateTodoDto) {
299
+ {{/if}}
197
300
  {{#if isPrisma8}}
198
- return ((this.db.prisma.orm.public as any).Todo).create(input);
301
+ return await this.db.prisma.orm.public.Todo.create(input);
199
302
  {{else if usePrisma}}
200
303
  const todo = await this.db.prisma.todo.create({ data: input });
201
304
  return todo;
@@ -203,64 +306,117 @@ export class TodoService {
203
306
  const todo = await this.db.typeorm.getRepository(Todo).save(this.db.typeorm.getRepository(Todo).create(input));
204
307
  return todo;
205
308
  {{else if useDrizzle}}
309
+ {{#if hasSqlserver}}
310
+ const [todo] = await this.db.drizzle.insert(schema.todos).output().values(input);
311
+ {{else if hasMysql}}
312
+ const [inserted] = await this.db.drizzle.insert(schema.todos).values(input).$returningId();
313
+ if (!inserted) {
314
+ throw new NotFoundException("Todo not found");
315
+ }
316
+ const [todo] = await this.db.drizzle.select().from(schema.todos).where(eq(schema.todos.id, inserted.id));
317
+ {{else}}
206
318
  const [todo] = await this.db.drizzle.insert(schema.todos).values(input).returning();
319
+ {{/if}}
207
320
  return todo;
208
321
  {{/if}}
209
322
  }
210
323
 
324
+ {{#if isPrisma8}}
325
+ async update(id: string, input: UpdateTodoDto): Promise<Todo> {
326
+ {{else}}
211
327
  async update(id: string, input: UpdateTodoDto) {
328
+ {{/if}}
212
329
  {{#if isPrisma8}}
213
- return ((this.db.prisma.orm.public as any).Todo).where({ id }).update(input);
330
+ const todo = await this.db.prisma.orm.public.Todo.where({ id: Number(id) }).update(input);
331
+ if (!todo) {
332
+ throw new NotFoundException("Todo not found");
333
+ }
334
+ return todo;
214
335
  {{else if usePrisma}}
215
336
  const result = await this.db.prisma.todo.update({ data: input, where: { id } });
216
337
  return result;
217
338
  {{else if useTypeorm}}
218
- const result = await this.db.typeorm.getRepository(Todo).update(id, input);
219
- return result;
339
+ const repository = this.db.typeorm.getRepository(Todo);
340
+ const result = await repository.update(id, input);
341
+ if (result.affected === 0) {
342
+ throw new NotFoundException("Todo not found");
343
+ }
344
+ const todo = await repository.findOneBy({ id });
345
+ if (!todo) {
346
+ throw new NotFoundException("Todo not found");
347
+ }
348
+ return todo;
220
349
  {{else if useDrizzle}}
350
+ {{#if hasSqlserver}}
351
+ const [todo] = await this.db.drizzle.update(schema.todos).set(input).output().where(eq(schema.todos.id, Number(id)));
352
+ if (!todo) {
353
+ throw new NotFoundException("Todo not found");
354
+ }
355
+ {{else if hasMysql}}
356
+ await this.db.drizzle.update(schema.todos).set(input).where(eq(schema.todos.id, Number(id)));
357
+ const [todo] = await this.db.drizzle.select().from(schema.todos).where(eq(schema.todos.id, Number(id)));
358
+ if (!todo) {
359
+ throw new NotFoundException("Todo not found");
360
+ }
361
+ {{else}}
221
362
  const [todo] = await this.db.drizzle.update(schema.todos).set(input).where(eq(schema.todos.id, Number(id))).returning();
363
+ {{/if}}
222
364
  return todo;
223
365
  {{/if}}
224
366
  }
225
367
 
226
368
  async delete(id: string) {
227
369
  {{#if isPrisma8}}
228
- await ((this.db.prisma.orm.public as any).Todo).where({ id }).delete();
370
+ await this.db.prisma.orm.public.Todo.where({ id: Number(id) }).delete();
229
371
  {{else if usePrisma}}
230
372
  await this.db.prisma.todo.delete({ where: { id } });
231
373
  {{else if useTypeorm}}
232
374
  await this.db.typeorm.getRepository(Todo).delete(id);
233
375
  {{else if useDrizzle}}
376
+ {{#if hasSqlserver}}
377
+ const [todo] = await this.db.drizzle.delete(schema.todos).output().where(eq(schema.todos.id, Number(id)));
378
+ if (!todo) {
379
+ throw new NotFoundException("Todo not found");
380
+ }
381
+ {{else}}
234
382
  await this.db.drizzle.delete(schema.todos).where(eq(schema.todos.id, Number(id)));
383
+ {{/if}}
235
384
  {{/if}}
236
385
  return { message: "Todo deleted successfully" };
237
386
  }
238
387
  {{/if}}
239
388
  {{else}}
240
- findAll() {
389
+ findAll({{#if hasAuth}}authorId: string{{/if}}) {
390
+ {{#if hasAuth}}
391
+ return this.todos.filter((todo) => todo.authorId === authorId);
392
+ {{else}}
241
393
  return [...this.todos];
394
+ {{/if}}
242
395
  }
243
396
 
244
- create(input: CreateTodoDto) {
245
- const todo = { id: String(this.nextId++), ...input };
397
+ create(input: CreateTodoDto{{#if hasAuth}}, authorId: string{{/if}}) {
398
+ const id = String(this.nextId);
399
+ this.nextId += 1;
400
+ const todo = { id, ...input{{#if hasAuth}}, authorId{{/if}} };
246
401
  this.todos.push(todo);
247
402
  return todo;
248
403
  }
249
404
 
250
- update(id: string, input: UpdateTodoDto) {
251
- const todo = this.todos.find((t) => t.id === id);
405
+ update(id: string, input: UpdateTodoDto{{#if hasAuth}}, authorId: string{{/if}}) {
406
+ const todo = this.todos.find((item) => item.id === id{{#if hasAuth}} && item.authorId === authorId{{/if}});
252
407
  if (!todo) {
253
- return { message: "Todo not found" };
408
+ throw new NotFoundException("Todo not found");
254
409
  }
255
410
  Object.assign(todo, input);
256
411
  return todo;
257
412
  }
258
413
 
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);
414
+ delete(id: string{{#if hasAuth}}, authorId: string{{/if}}) {
415
+ const index = this.todos.findIndex((item) => item.id === id{{#if hasAuth}} && item.authorId === authorId{{/if}});
416
+ if (index === -1) {
417
+ throw new NotFoundException("Todo not found");
263
418
  }
419
+ this.todos.splice(index, 1);
264
420
  return { message: "Todo deleted successfully" };
265
421
  }
266
422
  {{/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}}