@nest-arch/tui 0.4.0 → 0.4.4
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.
- package/dist/cli.js +1 -1
- package/dist/{constants-C3xmDWeK.js → constants-7dJLZpB2.js} +1 -1
- package/dist/index.js +188 -134
- package/dist/templates/addons/husky/pre-commit.hbs +11 -26
- package/dist/templates/base/.env.example.hbs +9 -0
- package/dist/templates/base/.env.hbs +7 -0
- package/dist/templates/base/README.md.hbs +16 -0
- package/dist/templates/base/pnpm-workspace.yaml.hbs +6 -0
- package/dist/templates/base/src/app.module.ts.hbs +68 -1
- package/dist/templates/base/src/app.router.ts.hbs +1 -2
- package/dist/templates/base/src/database/adapters/mongo/prisma-mongo.adapter.ts.hbs +11 -3
- package/dist/templates/base/src/database/adapters/sql/prisma-sql.adapter.ts.hbs +1 -1
- package/dist/templates/base/src/database/db.module.ts.hbs +24 -8
- package/dist/templates/base/src/database/db.service.ts.hbs +20 -0
- package/dist/templates/base/src/database/entities/app.entity.ts.hbs +25 -0
- package/dist/templates/base/src/database/index.ts.hbs +19 -0
- package/dist/templates/base/src/database/orm/drizzle/schema.ts.hbs +42 -11
- package/dist/templates/base/src/database/orm/typeorm/data-source.ts.hbs +12 -1
- package/dist/templates/base/src/libs/middlewares/auth.trpc.middleware.ts.hbs +47 -0
- package/dist/templates/base/src/libs/middlewares/rate-limit.trpc.middleware.ts.hbs +43 -0
- package/dist/templates/base/src/libs/trpc/inner.context.ts.hbs +6 -3
- package/dist/templates/base/src/main.ts.hbs +13 -4
- package/dist/templates/base/src/modules/users/entities/user.entity.ts.hbs +22 -0
- package/dist/templates/base/test/app.e2e-spec.ts.hbs +670 -37
- package/dist/templates/base/test/bootstrap.e2e-spec.ts.hbs +11 -1
- package/dist/templates/extras/docker/.dockerignore.hbs +8 -1
- package/dist/templates/extras/docker/Dockerfile.hbs +8 -10
- package/dist/templates/extras/health/src/health/health.controller.ts.hbs +54 -0
- package/dist/templates/extras/health/src/health/health.module.ts.hbs +9 -0
- package/dist/templates/extras/swagger/create-docs.ts.hbs +9 -3
- package/dist/templates/feature/graphql/src/graphql/graphql.module.ts.hbs +6 -17
- package/dist/templates/feature/graphql/src/graphql/orm/drizzle/drizzle-graphql.module.ts.hbs +3 -2
- package/dist/templates/feature/graphql/src/graphql/resolvers/health.resolver.ts.hbs +14 -0
- package/dist/templates/feature/graphql/src/graphql/resolvers/todo.resolver.ts.hbs +165 -53
- package/dist/templates/feature/rest/todo-example/src/api/todo/dto/create-todo.dto.ts.hbs +12 -0
- package/dist/templates/feature/rest/todo-example/src/api/todo/dto/update-todo.dto.ts.hbs +12 -0
- package/dist/templates/feature/rest/todo-example/src/api/todo/todo.controller.ts.hbs +18 -8
- package/dist/templates/feature/rest/todo-example/src/api/todo/todo.router.ts.hbs +41 -13
- package/dist/templates/feature/rest/todo-example/src/api/todo/todo.service.ts.hbs +68 -10
- package/dist/templates/monorepo/apps/api-gateway/package.json.hbs +2 -2
- package/dist/templates/monorepo/apps/api-gateway/src/app.controller.spec.ts.hbs +5 -0
- package/dist/templates/monorepo/apps/api-gateway/src/app.controller.ts.hbs +6 -0
- package/dist/templates/monorepo/apps/api-gateway/src/app.module.ts.hbs +32 -1
- package/dist/templates/monorepo/apps/api-gateway/src/app.service.ts.hbs +1 -1
- package/dist/templates/monorepo/apps/api-gateway/src/main.ts.hbs +13 -4
- package/dist/templates/monorepo/apps/api-gateway/test/app.e2e-spec.ts.hbs +26 -1
- package/dist/templates/monorepo/feature/graphql/src/graphql/graphql.module.ts.hbs +6 -10
- package/dist/templates/monorepo/feature/graphql/src/graphql/resolvers/health.resolver.ts.hbs +14 -0
- package/dist/templates/monorepo/feature/graphql/src/graphql/resolvers/todo.resolver.ts.hbs +147 -47
- package/dist/templates/monorepo/packages/env/src/api-gateway.ts.hbs +7 -0
- package/dist/templates/monorepo/packages/shared/package.json.hbs +1 -0
- package/dist/templates/monorepo/packages/shared/src/auth.ts.hbs +6 -0
- package/dist/templates/monorepo/root/pnpm-workspace.yaml.hbs +10 -2
- package/dist/templates/single-project/architecture/nest-api/.env.hbs +6 -0
- package/dist/templates/single-project/architecture/nest-api/package.json.hbs +1 -1
- package/dist/templates/single-project/architecture/nest-api/src/main.ts.hbs +13 -4
- package/dist/templates/single-project/architecture/nest-gateway/src/main.ts.hbs +3 -3
- package/dist/templates/single-project/architecture/nest-microservice/proto/app.proto.hbs +13 -0
- package/dist/templates/single-project/architecture/nest-microservice/src/app.controller.ts.hbs +10 -4
- package/dist/templates/single-project/architecture/nest-microservice/src/app.service.ts.hbs +2 -2
- package/dist/templates/single-project/architecture/nest-microservice/src/main.ts.hbs +3 -3
- package/dist/templates/single-project/architecture/nest-microservice/test/microservice.e2e-spec.ts.hbs +7 -1
- package/dist/templates/single-project/shared/config/env.ts.hbs +12 -1
- package/package.json +2 -2
|
@@ -46,7 +46,17 @@ it("boots the compiled application through main.ts", async () => {
|
|
|
46
46
|
const port = await getFreePort();
|
|
47
47
|
const origin = "https://allowed.example";
|
|
48
48
|
const application = spawn(process.execPath, ["dist/main.js"], {
|
|
49
|
-
env: {
|
|
49
|
+
env: {
|
|
50
|
+
...process.env,
|
|
51
|
+
CORS_ORIGIN: origin,
|
|
52
|
+
{{#if (and isPassportAuth (not hasDatabase))}}
|
|
53
|
+
OIDC_AUDIENCE: "generated-resource-server",
|
|
54
|
+
OIDC_ISSUER: "https://identity.example.test/",
|
|
55
|
+
OIDC_JWKS_URI: "https://identity.example.test/.well-known/jwks.json",
|
|
56
|
+
{{/if}}
|
|
57
|
+
NODE_ENV: "test",
|
|
58
|
+
PORT: String(port),
|
|
59
|
+
},
|
|
50
60
|
stdio: ["ignore", "pipe", "pipe"],
|
|
51
61
|
});
|
|
52
62
|
startedProcesses.push(application);
|
|
@@ -3,23 +3,21 @@ FROM node:22-alpine
|
|
|
3
3
|
WORKDIR /app
|
|
4
4
|
|
|
5
5
|
{{#if (eq packageManager "pnpm")}}
|
|
6
|
-
RUN corepack enable
|
|
7
|
-
COPY package.json pnpm-lock.yaml ./
|
|
8
|
-
RUN pnpm install --frozen-lockfile
|
|
6
|
+
RUN corepack enable
|
|
9
7
|
{{else if (eq packageManager "yarn")}}
|
|
10
|
-
|
|
11
|
-
RUN yarn install --frozen-lockfile
|
|
8
|
+
RUN corepack enable
|
|
12
9
|
{{else}}
|
|
13
|
-
COPY package*.json ./
|
|
14
|
-
RUN npm ci
|
|
15
10
|
{{/if}}
|
|
16
11
|
|
|
17
12
|
COPY . .
|
|
18
|
-
RUN {{packageManager}}
|
|
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 (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{{else}}npm install{{/if}}
|
|
14
|
+
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
|
|
19
15
|
|
|
20
|
-
|
|
16
|
+
ENV NODE_ENV=production
|
|
17
|
+
|
|
18
|
+
EXPOSE {{#if (eq httpProvider "fastify")}}3001{{else}}3000{{/if}}
|
|
21
19
|
{{#if (includes microservices "grpc")}}
|
|
22
20
|
EXPOSE 5000
|
|
23
21
|
{{/if}}
|
|
24
22
|
|
|
25
|
-
CMD ["
|
|
23
|
+
CMD ["node", "dist/main"]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Controller, Get } from "@nestjs/common";
|
|
2
|
+
import { HealthCheck, HealthCheckService } from "@nestjs/terminus";
|
|
3
|
+
{{#if isBetterAuth}}
|
|
4
|
+
import { AllowAnonymous } from "@thallesp/nestjs-better-auth";
|
|
5
|
+
{{/if}}
|
|
6
|
+
{{#if hasDatabase}}
|
|
7
|
+
import { DbService } from "../database/db.service.js";
|
|
8
|
+
{{#if useDrizzle}}
|
|
9
|
+
import { sql } from "drizzle-orm";
|
|
10
|
+
{{/if}}
|
|
11
|
+
{{/if}}
|
|
12
|
+
|
|
13
|
+
{{#if isBetterAuth}}
|
|
14
|
+
@AllowAnonymous()
|
|
15
|
+
{{/if}}
|
|
16
|
+
@Controller("health")
|
|
17
|
+
export class HealthController {
|
|
18
|
+
constructor(
|
|
19
|
+
private readonly health: HealthCheckService{{#if hasDatabase}},
|
|
20
|
+
private readonly db: DbService{{/if}}
|
|
21
|
+
) {}
|
|
22
|
+
|
|
23
|
+
@Get()
|
|
24
|
+
@HealthCheck()
|
|
25
|
+
check() {
|
|
26
|
+
return this.health.check([
|
|
27
|
+
() => ({ app: { status: "up" } }),
|
|
28
|
+
{{#if hasDatabase}}
|
|
29
|
+
async () => {
|
|
30
|
+
try {
|
|
31
|
+
{{#if (or usePrisma isPrisma8)}}
|
|
32
|
+
await this.db.prisma.$queryRaw`SELECT 1`;
|
|
33
|
+
{{else if useDrizzle}}
|
|
34
|
+
{{#if hasSqlite}}
|
|
35
|
+
await this.db.drizzle.get(sql`SELECT 1`);
|
|
36
|
+
{{else}}
|
|
37
|
+
await this.db.drizzle.execute(sql`SELECT 1`);
|
|
38
|
+
{{/if}}
|
|
39
|
+
{{else if useTypeorm}}
|
|
40
|
+
await this.db.typeorm.query("SELECT 1");
|
|
41
|
+
{{else if hasMongodb}}
|
|
42
|
+
await this.db.raw.mongo.command({ ping: 1 });
|
|
43
|
+
{{else}}
|
|
44
|
+
await this.db.raw.sql.query("SELECT 1");
|
|
45
|
+
{{/if}}
|
|
46
|
+
return { db: { status: "up" } };
|
|
47
|
+
} catch {
|
|
48
|
+
return { db: { status: "down" } };
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{{/if}}
|
|
52
|
+
]);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Module } from "@nestjs/common";
|
|
2
|
+
import { TerminusModule } from "@nestjs/terminus";
|
|
3
|
+
import { HealthController } from "./health.controller.js";
|
|
4
|
+
|
|
5
|
+
@Module({
|
|
6
|
+
controllers: [HealthController],
|
|
7
|
+
imports: [TerminusModule],
|
|
8
|
+
})
|
|
9
|
+
export class HealthModule {}
|
|
@@ -19,6 +19,7 @@ interface DocsIntegrations {
|
|
|
19
19
|
zod?: {
|
|
20
20
|
withFastify?: boolean;
|
|
21
21
|
};
|
|
22
|
+
bearerAuth?: boolean;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export interface CreateDocsOptions {
|
|
@@ -176,11 +177,16 @@ export async function createDocs(
|
|
|
176
177
|
app: INestApplication,
|
|
177
178
|
options: CreateDocsOptions = {}
|
|
178
179
|
): Promise<OpenAPIObject> {
|
|
179
|
-
const
|
|
180
|
+
const builder = new DocumentBuilder()
|
|
180
181
|
.setTitle(options.title ?? "NestJS API")
|
|
181
182
|
.setDescription(options.description ?? "Generated with Nest Arch")
|
|
182
|
-
.setVersion(options.version ?? "1.0.0")
|
|
183
|
-
|
|
183
|
+
.setVersion(options.version ?? "1.0.0");
|
|
184
|
+
|
|
185
|
+
if (options.integrations?.bearerAuth === true) {
|
|
186
|
+
builder.addBearerAuth();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const config = builder.build();
|
|
184
190
|
|
|
185
191
|
let baseSpec = SwaggerModule.createDocument(app, config) as OpenAPIObject;
|
|
186
192
|
baseSpec = await applyZodCleanup(baseSpec, options.integrations?.zod);
|
|
@@ -1,33 +1,22 @@
|
|
|
1
1
|
import { Module } from "@nestjs/common";
|
|
2
|
-
import {
|
|
2
|
+
import { GraphQLModule } from "@nestjs/graphql";
|
|
3
3
|
import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";
|
|
4
|
-
import {
|
|
4
|
+
import type { IncomingMessage } from "node:http";
|
|
5
|
+
import path from "node:path";
|
|
5
6
|
import { env } from "../config/env.js";
|
|
6
|
-
{
|
|
7
|
-
// WARNING: If you use @as-integrations/fastify with multiple GraphQL endpoints
|
|
8
|
-
// in a single application, make sure to enable the disableHealthCheck setting
|
|
9
|
-
// in the GraphQLModule configuration below.
|
|
10
|
-
{{/if}}
|
|
7
|
+
import { HealthResolver } from "./resolvers/health.resolver.js";
|
|
11
8
|
{{#if hasTodoExample}}
|
|
12
9
|
import { TodoResolver } from "./resolvers/todo.resolver.js";
|
|
13
10
|
{{/if}}
|
|
14
11
|
|
|
15
|
-
@Resolver()
|
|
16
|
-
class HealthResolver {
|
|
17
|
-
@Query(() => String)
|
|
18
|
-
hello(): string { return "Hello GraphQL!"; }
|
|
19
|
-
}
|
|
20
|
-
|
|
21
12
|
@Module({
|
|
22
13
|
imports: [
|
|
23
14
|
GraphQLModule.forRoot<ApolloDriverConfig>({
|
|
24
15
|
driver: ApolloDriver,
|
|
25
|
-
autoSchemaFile: join(process.cwd(), "src/schema.gql"),
|
|
16
|
+
autoSchemaFile: path.join(process.cwd(), "src/schema.gql"),
|
|
26
17
|
graphiql: env.GRAPHQL_PLAYGROUND,
|
|
18
|
+
context: ({ req, res }: { req: IncomingMessage; res: unknown }) => ({ req, res }),
|
|
27
19
|
sortSchema: true,
|
|
28
|
-
{{#if (eq httpProvider "fastify")}}
|
|
29
|
-
disableHealthCheck: true,
|
|
30
|
-
{{/if}}
|
|
31
20
|
}),
|
|
32
21
|
],
|
|
33
22
|
providers: [
|
package/dist/templates/feature/graphql/src/graphql/orm/drizzle/drizzle-graphql.module.ts.hbs
CHANGED
|
@@ -16,7 +16,7 @@ import mysql from "mysql2";
|
|
|
16
16
|
import { drizzle } from "drizzle-orm/better-sqlite3";
|
|
17
17
|
import Database from "better-sqlite3";
|
|
18
18
|
{{/if}}
|
|
19
|
-
import * as dbSchema from "
|
|
19
|
+
import * as dbSchema from "../../../database/orm/drizzle/schema.js";
|
|
20
20
|
{{/if}}
|
|
21
21
|
|
|
22
22
|
const schema = buildSchema({{#if isMonorepo}}db{{else}}
|
|
@@ -24,13 +24,14 @@ const schema = buildSchema({{#if isMonorepo}}db{{else}}
|
|
|
24
24
|
drizzle(new Pool({ connectionString: env.POSTGRES_URL }), { schema: dbSchema })
|
|
25
25
|
{{/if}}
|
|
26
26
|
{{#if hasMysql}}
|
|
27
|
-
drizzle(mysql.createPool(env.MYSQL_URL), { schema: dbSchema })
|
|
27
|
+
drizzle(mysql.createPool(env.MYSQL_URL), { mode: "default", schema: dbSchema })
|
|
28
28
|
{{/if}}
|
|
29
29
|
{{#if hasSqlite}}
|
|
30
30
|
drizzle(new Database(env.SQLITE_PATH), { schema: dbSchema })
|
|
31
31
|
{{/if}}
|
|
32
32
|
{{/if}});
|
|
33
33
|
|
|
34
|
+
|
|
34
35
|
@Module({
|
|
35
36
|
providers: [
|
|
36
37
|
{
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Query, Resolver } from "@nestjs/graphql";
|
|
2
|
+
{{#if isBetterAuth}}
|
|
3
|
+
import { AllowAnonymous } from "@thallesp/nestjs-better-auth";
|
|
4
|
+
{{/if}}
|
|
5
|
+
{{#if isBetterAuth}}
|
|
6
|
+
@AllowAnonymous()
|
|
7
|
+
{{/if}}
|
|
8
|
+
@Resolver()
|
|
9
|
+
export class HealthResolver {
|
|
10
|
+
@Query(() => String)
|
|
11
|
+
hello(): string {
|
|
12
|
+
return "Hello GraphQL!";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -39,34 +39,38 @@ export class TodoResolver {
|
|
|
39
39
|
}
|
|
40
40
|
{{else}}
|
|
41
41
|
{{#if (and hasAuth hasDatabase)}}
|
|
42
|
-
import { UseGuards } from "@nestjs/common";
|
|
43
|
-
{{/if}}
|
|
44
|
-
import { Args, Mutation, Query, Resolver } from "@nestjs/graphql";
|
|
45
|
-
{{#if (and hasAuth hasDatabase)}}
|
|
42
|
+
import { BadRequestException, NotFoundException, UseGuards } from "@nestjs/common";
|
|
46
43
|
import { UserEntity } from "../../auth/decorators/index.js";
|
|
47
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";
|
|
48
53
|
{{/if}}
|
|
54
|
+
{{#if (and hasDatabase useDrizzle)}}
|
|
55
|
+
import { and, eq } from "drizzle-orm";
|
|
56
|
+
import * as schema from "../../database/orm/drizzle/schema.js";
|
|
57
|
+
{{/if}}
|
|
58
|
+
{{#if hasDatabase}}
|
|
49
59
|
{{#if isMonorepo}}
|
|
50
60
|
import { DbService } from "@repo/db";
|
|
51
61
|
{{else}}
|
|
52
62
|
import { DbService } from "../../database/db.service.js";
|
|
53
63
|
{{/if}}
|
|
64
|
+
{{/if}}
|
|
54
65
|
import { CreateTodoInput } from "../dto/create-todo.input.js";
|
|
55
66
|
import { UpdateTodoInput } from "../dto/update-todo.input.js";
|
|
56
|
-
{{#if useTypeorm}}
|
|
57
|
-
import { GraphRelationBuilder } from "typeorm-relations-graphql";
|
|
58
|
-
import { GraphQLResolveInfo } from "graphql";
|
|
59
|
-
{{/if}}
|
|
60
|
-
{{#if useDrizzle}}
|
|
61
|
-
import * as schema from "../../database/orm/drizzle/schema.js";
|
|
62
|
-
{{/if}}
|
|
63
|
-
{{#if (and hasAuth hasDatabase)}}
|
|
64
67
|
import { Todo } from "../models/todo.model.js";
|
|
65
|
-
{{/if}}
|
|
66
68
|
|
|
67
69
|
@Resolver(() => Todo)
|
|
68
70
|
export class TodoResolver {
|
|
71
|
+
{{#if hasDatabase}}
|
|
69
72
|
constructor(private readonly db: DbService) {}
|
|
73
|
+
{{/if}}
|
|
70
74
|
|
|
71
75
|
@Query(() => String)
|
|
72
76
|
hello(): string {
|
|
@@ -74,93 +78,201 @@ export class TodoResolver {
|
|
|
74
78
|
}{{#if hasDatabase}}
|
|
75
79
|
|
|
76
80
|
@Query(() => [Todo])
|
|
77
|
-
|
|
81
|
+
{{#if hasAuth}}
|
|
82
|
+
@UseGuards(GqlAuthGuard)
|
|
83
|
+
{{/if}}
|
|
84
|
+
todos({{#if useTypeorm}}info: GraphQLResolveInfo, {{/if}}{{#if hasAuth}}@UserEntity() user: { id: string }{{/if}}) {
|
|
78
85
|
{{#if useTypeorm}}
|
|
79
|
-
const builder = new GraphRelationBuilder(this.db.
|
|
86
|
+
const builder = new GraphRelationBuilder(this.db.typeorm);
|
|
80
87
|
const relations = builder.buildForQuery(Todo, info, "todos");
|
|
81
|
-
|
|
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}}
|
|
82
93
|
{{else if isPrisma8}}
|
|
94
|
+
{{#if hasAuth}}
|
|
95
|
+
return ((this.db.prisma.orm.public as any).Todo).where({ authorId: user.id }).all();
|
|
96
|
+
{{else}}
|
|
83
97
|
return ((this.db.prisma.orm.public as any).Todo).all();
|
|
98
|
+
{{/if}}
|
|
84
99
|
{{else if usePrisma}}
|
|
100
|
+
{{#if hasAuth}}
|
|
101
|
+
return this.db.prisma.todo.findMany({ where: { authorId: user.id } });
|
|
102
|
+
{{else}}
|
|
85
103
|
return this.db.prisma.todo.findMany();
|
|
104
|
+
{{/if}}
|
|
86
105
|
{{else if useDrizzle}}
|
|
87
|
-
|
|
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}}
|
|
88
111
|
{{else}}
|
|
89
112
|
return [];
|
|
90
113
|
{{/if}}
|
|
91
114
|
}
|
|
92
115
|
|
|
116
|
+
{{#if hasAuth}}
|
|
93
117
|
@UseGuards(GqlAuthGuard)
|
|
118
|
+
{{/if}}
|
|
94
119
|
@Mutation(() => Todo)
|
|
95
|
-
createTodo(
|
|
120
|
+
async createTodo(
|
|
121
|
+
{{#if hasAuth}}
|
|
96
122
|
@UserEntity() user: { id: string },
|
|
123
|
+
{{/if}}
|
|
97
124
|
@Args("input") input: CreateTodoInput{{#if useTypeorm}}, info: GraphQLResolveInfo{{/if}}
|
|
98
125
|
) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const builder = new GraphRelationBuilder(this.db.getDataSource());
|
|
103
|
-
const relations = builder.buildForQuery(Todo, info, "createTodo");
|
|
104
|
-
return this.db.getRepository(Todo).findOneOrFail({
|
|
105
|
-
where: { id: saved.id },
|
|
106
|
-
relations,
|
|
107
|
-
});
|
|
108
|
-
{{else if isPrisma8}}
|
|
126
|
+
if (!input.title.trim()) throw new BadRequestException("Title must not be empty");
|
|
127
|
+
{{#if isPrisma8}}
|
|
128
|
+
{{#if hasAuth}}
|
|
109
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}}
|
|
110
133
|
{{else if usePrisma}}
|
|
111
|
-
|
|
112
|
-
|
|
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);
|
|
148
|
+
const relations = builder.buildForQuery(Todo, info, "createTodo");
|
|
149
|
+
return this.db.typeorm.getRepository(TodoEntity).findOneOrFail({
|
|
150
|
+
relations,
|
|
151
|
+
where: { id: saved.id },
|
|
113
152
|
});
|
|
114
153
|
{{else if useDrizzle}}
|
|
115
|
-
|
|
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");
|
|
159
|
+
return todo;
|
|
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");
|
|
116
167
|
return todo;
|
|
168
|
+
{{/if}}
|
|
117
169
|
{{else}}
|
|
118
170
|
return { id: "1", ...input };
|
|
119
171
|
{{/if}}
|
|
120
172
|
}
|
|
121
173
|
|
|
174
|
+
{{#if hasAuth}}
|
|
122
175
|
@UseGuards(GqlAuthGuard)
|
|
176
|
+
{{/if}}
|
|
123
177
|
@Mutation(() => Todo)
|
|
124
|
-
updateTodo(
|
|
178
|
+
async updateTodo(
|
|
179
|
+
{{#if hasAuth}}
|
|
180
|
+
@UserEntity() user: { id: string },
|
|
181
|
+
{{/if}}
|
|
182
|
+
@Args("input") input: UpdateTodoInput{{#if useTypeorm}}, info: GraphQLResolveInfo{{/if}}
|
|
183
|
+
) {
|
|
125
184
|
const { id, ...data } = input;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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);
|
|
129
207
|
const relations = builder.buildForQuery(Todo, info, "updateTodo");
|
|
130
|
-
return this.db.getRepository(
|
|
131
|
-
where: { id },
|
|
208
|
+
return this.db.typeorm.getRepository(TodoEntity).findOneOrFail({
|
|
132
209
|
relations,
|
|
210
|
+
where: { id },
|
|
133
211
|
});
|
|
134
|
-
{{else if isPrisma8}}
|
|
135
|
-
return ((this.db.prisma.orm.public as any).Todo).where({ id }).update(data);
|
|
136
|
-
{{else if usePrisma}}
|
|
137
|
-
return this.db.prisma.todo.update({ where: { id }, data });
|
|
138
212
|
{{else if useDrizzle}}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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");
|
|
144
224
|
return todo;
|
|
145
225
|
{{else}}
|
|
146
226
|
return { id, ...data };
|
|
147
227
|
{{/if}}
|
|
148
228
|
}
|
|
149
229
|
|
|
230
|
+
{{#if hasAuth}}
|
|
150
231
|
@UseGuards(GqlAuthGuard)
|
|
232
|
+
{{/if}}
|
|
151
233
|
@Mutation(() => Boolean)
|
|
152
|
-
async deleteTodo(
|
|
153
|
-
{{#if
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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}}
|
|
157
244
|
await ((this.db.prisma.orm.public as any).Todo).where({ id }).delete();
|
|
245
|
+
{{/if}}
|
|
158
246
|
return true;
|
|
159
247
|
{{else if usePrisma}}
|
|
160
|
-
|
|
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");
|
|
161
262
|
return true;
|
|
162
263
|
{{else if useDrizzle}}
|
|
163
|
-
|
|
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}}
|
|
164
276
|
return true;
|
|
165
277
|
{{else}}
|
|
166
278
|
return true;
|
|
@@ -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 {
|
|
@@ -21,7 +24,7 @@ import {
|
|
|
21
24
|
{{/if}}
|
|
22
25
|
} from "@nestjs/swagger";
|
|
23
26
|
{{/if}}
|
|
24
|
-
{{#if isPassportAuth}}
|
|
27
|
+
{{#if (and isPassportAuth swagger)}}
|
|
25
28
|
import {
|
|
26
29
|
ApiBearerAuth,
|
|
27
30
|
} from "@nestjs/swagger";
|
|
@@ -34,6 +37,9 @@ import type { UserSession } from "../../auth/auth.js";
|
|
|
34
37
|
import { RestAuthGuard } from "../../auth/guards/rest-auth.guard.js";
|
|
35
38
|
import { CurrentUser } from "../../auth/decorators/current-user.decorator.js";
|
|
36
39
|
{{/if}}
|
|
40
|
+
{{#if (and isBetterAuth hasDatabase hasGraphql)}}
|
|
41
|
+
import { RestAuthGuard } from "../../auth/guards/rest-auth.guard.js";
|
|
42
|
+
{{/if}}
|
|
37
43
|
import { TodoService } from "./todo.service.js";
|
|
38
44
|
import { CreateTodoDto } from "./dto/create-todo.dto.js";
|
|
39
45
|
import { UpdateTodoDto } from "./dto/update-todo.dto.js";
|
|
@@ -42,7 +48,7 @@ import { UpdateTodoDto } from "./dto/update-todo.dto.js";
|
|
|
42
48
|
@ApiTags("Todos")
|
|
43
49
|
{{/if}}
|
|
44
50
|
@Controller("todos")
|
|
45
|
-
{{#if (and isPassportAuth hasDatabase)}}
|
|
51
|
+
{{#if (or (and isPassportAuth hasDatabase) (and isBetterAuth hasDatabase hasGraphql))}}
|
|
46
52
|
@UseGuards(RestAuthGuard)
|
|
47
53
|
{{/if}}
|
|
48
54
|
export class TodoController {
|
|
@@ -64,7 +70,11 @@ export class TodoController {
|
|
|
64
70
|
return this.todoService.findAll(user.id);
|
|
65
71
|
}
|
|
66
72
|
{{else if (and isBetterAuth hasDatabase)}}
|
|
73
|
+
{{#if (and isMonorepo usePrisma)}}
|
|
74
|
+
findAll(@Session() session: UserSession): ReturnType<TodoService["findAll"]> {
|
|
75
|
+
{{else}}
|
|
67
76
|
findAll(@Session() session: UserSession) {
|
|
77
|
+
{{/if}}
|
|
68
78
|
return this.todoService.findAll(session.user.id);
|
|
69
79
|
}
|
|
70
80
|
{{else}}
|
|
@@ -86,20 +96,20 @@ export class TodoController {
|
|
|
86
96
|
{{/if}}
|
|
87
97
|
{{#if (and isPassportAuth hasDatabase)}}
|
|
88
98
|
create(
|
|
89
|
-
@Body({ schema: CreateTodoDto.schema }) input: CreateTodoDto,
|
|
99
|
+
@Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: CreateTodoDto.schema }){{/if}} input: CreateTodoDto,
|
|
90
100
|
@CurrentUser() user: { id: string }
|
|
91
101
|
) {
|
|
92
102
|
return this.todoService.create(input, user.id);
|
|
93
103
|
}
|
|
94
104
|
{{else if (and isBetterAuth hasDatabase)}}
|
|
95
105
|
create(
|
|
96
|
-
@Body({ schema: CreateTodoDto.schema }) input: CreateTodoDto,
|
|
106
|
+
@Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: CreateTodoDto.schema }){{/if}} input: CreateTodoDto,
|
|
97
107
|
@Session() session: UserSession
|
|
98
108
|
) {
|
|
99
109
|
return this.todoService.create(input, session.user.id);
|
|
100
110
|
}
|
|
101
111
|
{{else}}
|
|
102
|
-
create(@Body({ schema: CreateTodoDto.schema }) input: CreateTodoDto) {
|
|
112
|
+
create(@Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: CreateTodoDto.schema }){{/if}} input: CreateTodoDto) {
|
|
103
113
|
return this.todoService.create(input);
|
|
104
114
|
}
|
|
105
115
|
{{/if}}
|
|
@@ -118,7 +128,7 @@ export class TodoController {
|
|
|
118
128
|
{{#if (and isPassportAuth hasDatabase)}}
|
|
119
129
|
update(
|
|
120
130
|
@Param("id") id: string,
|
|
121
|
-
@Body({ schema: UpdateTodoDto.schema }) input: UpdateTodoDto,
|
|
131
|
+
@Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: UpdateTodoDto.schema }){{/if}} input: UpdateTodoDto,
|
|
122
132
|
@CurrentUser() user: { id: string }
|
|
123
133
|
) {
|
|
124
134
|
return this.todoService.update(id, input, user.id);
|
|
@@ -126,7 +136,7 @@ export class TodoController {
|
|
|
126
136
|
{{else if (and isBetterAuth hasDatabase)}}
|
|
127
137
|
update(
|
|
128
138
|
@Param("id") id: string,
|
|
129
|
-
@Body({ schema: UpdateTodoDto.schema }) input: UpdateTodoDto,
|
|
139
|
+
@Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: UpdateTodoDto.schema }){{/if}} input: UpdateTodoDto,
|
|
130
140
|
@Session() session: UserSession
|
|
131
141
|
) {
|
|
132
142
|
return this.todoService.update(id, input, session.user.id);
|
|
@@ -134,7 +144,7 @@ export class TodoController {
|
|
|
134
144
|
{{else}}
|
|
135
145
|
update(
|
|
136
146
|
@Param("id") id: string,
|
|
137
|
-
@Body({ schema: UpdateTodoDto.schema }) input: UpdateTodoDto
|
|
147
|
+
@Body{{#if (includes addons "nestjs-zod")}}(){{else}}({ schema: UpdateTodoDto.schema }){{/if}} input: UpdateTodoDto
|
|
138
148
|
) {
|
|
139
149
|
return this.todoService.update(id, input);
|
|
140
150
|
}
|