@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.
- package/README.md +31 -0
- package/dist/cli.js +2 -1
- package/dist/constants-CUTbfu9C.js +1 -0
- package/dist/index.js +6 -405
- package/dist/nonInteractive-C1KZ0b_6.js +5 -0
- package/dist/nonInteractiveOptions-CIaoLAWg.js +24 -0
- package/dist/projectGeneratorService-CeWJK-HA.js +420 -0
- package/dist/projectName-CcE90t2V.js +1 -0
- package/dist/templates/addons/husky/pre-commit.hbs +1 -1
- package/dist/templates/base/.env.example.hbs +30 -2
- package/dist/templates/base/.env.hbs +7 -2
- package/dist/templates/base/README.md.hbs +11 -2
- package/dist/templates/base/pnpm-workspace.yaml.hbs +9 -4
- package/dist/templates/base/prisma.config.ts.hbs +6 -1
- package/dist/templates/base/src/app.controller.spec.ts.hbs +6 -0
- package/dist/templates/base/src/app.module.ts.hbs +6 -23
- package/dist/templates/base/src/database/adapters/interfaces/db-adapter.interface.ts.hbs +5 -5
- package/dist/templates/base/src/database/adapters/mongo/raw-mongo.adapter.ts.hbs +6 -4
- package/dist/templates/base/src/database/adapters/mongo/typeorm-mongo.adapter.ts.hbs +27 -0
- package/dist/templates/base/src/database/db.module.ts.hbs +33 -13
- package/dist/templates/base/src/database/db.service.ts.hbs +12 -4
- package/dist/templates/base/src/database/entities/todo.entity.ts.hbs +17 -5
- package/dist/templates/base/src/database/index.ts.hbs +2 -0
- package/dist/templates/base/src/database/orm/drizzle/schema.ts.hbs +80 -20
- package/dist/templates/base/src/database/orm/typeorm/data-source.ts.hbs +34 -12
- package/dist/templates/base/src/libs/middlewares/graphql-throttler.guard.ts.hbs +22 -0
- package/dist/templates/base/src/libs/middlewares/rate-limit.trpc.middleware.ts.hbs +2 -1
- package/dist/templates/base/src/libs/trpc/inner.context.ts.hbs +2 -2
- package/dist/templates/base/src/main.ts.hbs +2 -2
- package/dist/templates/base/test/app.e2e-spec.ts.hbs +378 -202
- package/dist/templates/extras/docker/Dockerfile.hbs +9 -2
- package/dist/templates/extras/health/src/health/health.controller.ts.hbs +12 -1
- package/dist/templates/extras/swagger/create-docs.ts.hbs +6 -1
- package/dist/templates/feature/graphql/src/graphql/models/todo.model.ts.hbs +1 -1
- package/dist/templates/feature/graphql/src/graphql/resolvers/todo.resolver.ts.hbs +1 -1
- package/dist/templates/feature/rest/todo-example/src/api/todo/todo.controller.ts.hbs +80 -7
- package/dist/templates/feature/rest/todo-example/src/api/todo/todo.router.ts.hbs +4 -4
- package/dist/templates/feature/rest/todo-example/src/api/todo/todo.service.ts.hbs +314 -34
- package/dist/templates/monorepo/apps/api-gateway/src/main.ts.hbs +2 -2
- package/dist/templates/monorepo/root/README.md.hbs +8 -13
- package/dist/templates/single-project/architecture/nest-api/.env.hbs +6 -2
- package/dist/templates/single-project/architecture/nest-api/pnpm-workspace.yaml.hbs +6 -0
- package/dist/templates/single-project/architecture/nest-api/src/main.ts.hbs +2 -2
- package/dist/templates/single-project/architecture/nest-gateway/src/main.ts.hbs +2 -2
- package/dist/templates/single-project/architecture/nest-microservice/.env.hbs +30 -1
- 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 +26 -2
- package/dist/templates/single-project/architecture/nest-microservice/src/app.module.ts.hbs +61 -1
- package/dist/templates/single-project/architecture/nest-microservice/src/app.service.ts.hbs +16 -4
- package/dist/templates/single-project/architecture/nest-microservice/src/http-throttler.guard.ts.hbs +13 -0
- package/dist/templates/single-project/architecture/nest-microservice/src/main.ts.hbs +26 -7
- package/dist/templates/single-project/architecture/nest-microservice/test/microservice.e2e-spec.ts.hbs +7 -87
- package/dist/templates/single-project/shared/config/env.ts.hbs +14 -14
- package/package.json +6 -5
- package/dist/constants-DVhgS48N.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var a=Object.defineProperty;var r=(e,t)=>a(e,"name",{value:t,configurable:!0});const s="my-nest-app",m=64,n=/^[a-z][a-z0-9-]*$/u;function E(e){return e.trim()||s}r(E,"resolveProjectName");function o(e){const t=e.trim();return t?t.length>64?"Project name must be at most 64 characters":n.test(t)?null:"Use lowercase letters, numbers, and hyphens; must start with a letter":null}r(o,"validateProjectName");export{s as D,m as M,n as P,E as r,o as v};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
set -e
|
|
3
3
|
|
|
4
|
-
{{#if isPnpm}}pnpm test{{else if isYarn}}yarn test{{else if isBun}}bun run test{{else}}npm test{{/if}}
|
|
4
|
+
{{#if isPnpm}}pnpm test --passWithNoTests{{else if isYarn}}yarn test --passWithNoTests{{else if isBun}}bun run test --passWithNoTests{{else}}npm test -- --passWithNoTests{{/if}}
|
|
5
5
|
|
|
6
6
|
{{#if hasFormatter}}
|
|
7
7
|
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR)
|
|
@@ -1,10 +1,33 @@
|
|
|
1
1
|
# Server
|
|
2
2
|
PORT=3000
|
|
3
3
|
NODE_ENV=development
|
|
4
|
-
CORS_ORIGIN=http://localhost:
|
|
4
|
+
CORS_ORIGIN=http://localhost:3000
|
|
5
5
|
# Comma-separated trusted reverse proxy IP addresses or CIDRs
|
|
6
6
|
TRUSTED_PROXY_IPS={{#each trustedProxyIps}}{{#unless @first}},{{/unless}}{{this}}{{/each}}
|
|
7
7
|
|
|
8
|
+
{{#if (eq architecture "nest-microservice")}}
|
|
9
|
+
# Microservice transport
|
|
10
|
+
MICROSERVICE_PORT=3001
|
|
11
|
+
{{/if}}
|
|
12
|
+
{{#if (includes microservices "redis")}}
|
|
13
|
+
REDIS_URL=redis://127.0.0.1:6379
|
|
14
|
+
{{/if}}
|
|
15
|
+
{{#if (includes microservices "mqtt")}}
|
|
16
|
+
MQTT_URL=mqtt://127.0.0.1:1883
|
|
17
|
+
{{/if}}
|
|
18
|
+
{{#if (includes microservices "nats")}}
|
|
19
|
+
NATS_URL=nats://127.0.0.1:4222
|
|
20
|
+
{{/if}}
|
|
21
|
+
{{#if (includes microservices "rabbitmq")}}
|
|
22
|
+
RABBITMQ_URL=amqp://127.0.0.1:5672
|
|
23
|
+
{{/if}}
|
|
24
|
+
{{#if (includes microservices "kafka")}}
|
|
25
|
+
KAFKA_BROKER=127.0.0.1:9092
|
|
26
|
+
{{/if}}
|
|
27
|
+
{{#if (includes microservices "grpc")}}
|
|
28
|
+
GRPC_URL=0.0.0.0:5000
|
|
29
|
+
{{/if}}
|
|
30
|
+
|
|
8
31
|
{{#if hasDatabase}}
|
|
9
32
|
# Database
|
|
10
33
|
{{/if}}
|
|
@@ -35,7 +58,12 @@ MONGODB_URL=mongodb://localhost:27017/{{projectNameKebab}}_db
|
|
|
35
58
|
GRAPHQL_PLAYGROUND=true
|
|
36
59
|
|
|
37
60
|
{{/if}}
|
|
38
|
-
{{#if (eq auth "passport")}}
|
|
61
|
+
{{#if (and (eq auth "passport") (not hasDatabase))}}
|
|
62
|
+
# External identity provider (RS256 JWKS)
|
|
63
|
+
OIDC_JWKS_URI=https://identity.example.com/.well-known/jwks.json
|
|
64
|
+
OIDC_ISSUER=https://identity.example.com/
|
|
65
|
+
OIDC_AUDIENCE=generated-resource-server
|
|
66
|
+
{{else if (eq auth "passport")}}
|
|
39
67
|
# JWT
|
|
40
68
|
JWT_ACCESS_SECRET=change-me-to-a-random-secret-at-least-32-characters-long
|
|
41
69
|
{{#if hasDatabase}}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
CORS_ORIGIN=http://localhost:
|
|
1
|
+
CORS_ORIGIN=http://localhost:3000
|
|
2
2
|
PORT=3000
|
|
3
3
|
TRUSTED_PROXY_IPS={{#each trustedProxyIps}}{{#unless @first}},{{/unless}}{{this}}{{/each}}
|
|
4
4
|
{{#if hasGraphql}}
|
|
@@ -26,7 +26,12 @@ SQLSERVER_TRUST_SERVER_CERTIFICATE=true
|
|
|
26
26
|
{{#if hasMongodb}}
|
|
27
27
|
MONGODB_URL=mongodb://localhost:27017/{{projectNameKebab}}_db
|
|
28
28
|
{{/if}}
|
|
29
|
-
{{#if (eq auth "passport")}}
|
|
29
|
+
{{#if (and (eq auth "passport") (not hasDatabase))}}
|
|
30
|
+
# External identity provider (RS256 JWKS)
|
|
31
|
+
OIDC_JWKS_URI=https://identity.example.com/.well-known/jwks.json
|
|
32
|
+
OIDC_ISSUER=https://identity.example.com/
|
|
33
|
+
OIDC_AUDIENCE=generated-resource-server
|
|
34
|
+
{{else if (eq auth "passport")}}
|
|
30
35
|
JWT_ACCESS_SECRET=change-me-to-a-random-secret-at-least-32-characters-long
|
|
31
36
|
{{#if hasDatabase}}
|
|
32
37
|
JWT_REFRESH_SECRET=change-me-to-a-different-random-secret-at-least-32-characters
|
|
@@ -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
|
|
|
@@ -98,9 +102,14 @@ This project uses **Better Auth** with database-backed sessions. Set `BETTER_AUT
|
|
|
98
102
|
|
|
99
103
|
Run `auth:generate` with your package manager. The script uses the installed CLI version.
|
|
100
104
|
{{#if usePrisma}}
|
|
101
|
-
|
|
105
|
+
{{#if hasMongodb}}
|
|
106
|
+
`auth:generate` normalizes MongoDB IDs and writes auth models to `src/database/orm/prisma/auth.prisma`, using `auth-schema.prisma` as intermediate CLI output. Then run `prisma:push` and `prisma:generate`, as shown in Setup.
|
|
107
|
+
{{else}}
|
|
108
|
+
`auth:generate` updates auth models in `src/database/orm/prisma/schema.prisma`. For local development, run `prisma:push` and then `prisma:generate`, as shown in Setup. For a workflow with migration history, use `prisma:migrate --name auth` instead of pushing the schema and then regenerate the client. For deployments, apply the committed migrations with `prisma:migrate:deploy`.
|
|
109
|
+
{{/if}}
|
|
110
|
+
Inspect the schema diff after changing plugins.
|
|
102
111
|
{{else if useDrizzle}}
|
|
103
|
-
|
|
112
|
+
For local development, run `db:push`, as shown in Setup. For a workflow with migration history, use `db:generate` and `db:migrate` instead. Auth owns `src/database/orm/drizzle/auth-schema.ts`; application tables remain in `schema.ts`. Commit generated migration files. SQLite requires no Docker service.
|
|
104
113
|
{{else}}
|
|
105
114
|
Then run `auth:migrate` and `build`.
|
|
106
115
|
{{/if}}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
allowBuilds:
|
|
2
|
-
{{#if useDrizzle}}
|
|
2
|
+
{{#if (or useDrizzle useTypescript7)}}
|
|
3
3
|
esbuild: true
|
|
4
4
|
{{/if}}
|
|
5
5
|
protobufjs: true
|
|
6
6
|
"@nestjs/core": true
|
|
7
|
-
{{#if useTypescript7}}
|
|
8
|
-
esbuild: true
|
|
9
|
-
{{/if}}
|
|
10
7
|
{{#if swagger}}
|
|
11
8
|
"@scarf/scarf": true
|
|
12
9
|
{{/if}}
|
|
@@ -20,7 +17,9 @@ allowBuilds:
|
|
|
20
17
|
"@prisma/client": true
|
|
21
18
|
{{/if}}
|
|
22
19
|
{{#if isPrisma8}}
|
|
20
|
+
{{#unless (or useDrizzle useTypescript7)}}
|
|
23
21
|
esbuild: true
|
|
22
|
+
{{/unless}}
|
|
24
23
|
msgpackr-extract: true
|
|
25
24
|
workerd: true
|
|
26
25
|
{{/if}}
|
|
@@ -31,3 +30,9 @@ allowBuilds:
|
|
|
31
30
|
{{#if hasSqlite}}
|
|
32
31
|
better-sqlite3: true
|
|
33
32
|
{{/if}}
|
|
33
|
+
{{#if hasTrpc}}
|
|
34
|
+
peerDependencyRules:
|
|
35
|
+
allowedVersions:
|
|
36
|
+
"nestjs-trpc>@nestjs/common": "^12.0.0"
|
|
37
|
+
"nestjs-trpc>@nestjs/core": "^12.0.0"
|
|
38
|
+
{{/if}}
|
|
@@ -26,7 +26,6 @@ export default definePrismaConfig({
|
|
|
26
26
|
import { defineConfig } from "prisma/config";
|
|
27
27
|
|
|
28
28
|
export default defineConfig({
|
|
29
|
-
schema: "src/database/orm/prisma{{#unless isBetterAuth}}/schema.prisma{{/unless}}",
|
|
30
29
|
datasource: {
|
|
31
30
|
{{#if hasPostgres}}url: env.POSTGRES_URL,{{/if}}
|
|
32
31
|
{{#if hasMysql}}url: env.MYSQL_URL,{{/if}}
|
|
@@ -34,5 +33,11 @@ export default defineConfig({
|
|
|
34
33
|
{{#if hasSqlserver}}url: `sqlserver://${env.SQLSERVER_HOST}:${env.SQLSERVER_PORT};database=${env.SQLSERVER_DATABASE};user={${env.SQLSERVER_USER.replaceAll("}", "}}")}};password={${env.SQLSERVER_PASSWORD.replaceAll("}", "}}")}};encrypt=${env.SQLSERVER_ENCRYPT};trustServerCertificate=${env.SQLSERVER_TRUST_SERVER_CERTIFICATE}`,{{/if}}
|
|
35
34
|
{{#if hasMongodb}}url: env.MONGODB_URL,{{/if}}
|
|
36
35
|
},
|
|
36
|
+
{{#unless isMonorepo}}
|
|
37
|
+
migrations: {
|
|
38
|
+
path: "src/database/orm/prisma/migrations",
|
|
39
|
+
},
|
|
40
|
+
{{/unless}}
|
|
41
|
+
schema: "src/database/orm/prisma{{#unless isBetterAuth}}/schema.prisma{{/unless}}",
|
|
37
42
|
});
|
|
38
43
|
{{/if}}
|
|
@@ -7,6 +7,9 @@ import { AppController } from "./app.controller.js";
|
|
|
7
7
|
import { AppService } from "./app.service.js";
|
|
8
8
|
{{#if (or hasDatabase hasOrm)}}
|
|
9
9
|
import { DbService } from "./database/db.service.js";
|
|
10
|
+
{{#if (and (eq architecture "nest-microservice") hasTodoExample)}}
|
|
11
|
+
import { TodoService } from "./api/todo/todo.service.js";
|
|
12
|
+
{{/if}}
|
|
10
13
|
{{/if}}
|
|
11
14
|
|
|
12
15
|
|
|
@@ -21,6 +24,9 @@ describe(AppController, () => {
|
|
|
21
24
|
AppService,
|
|
22
25
|
{{#if (or hasDatabase hasOrm)}}
|
|
23
26
|
{ provide: DbService, useValue: {} },
|
|
27
|
+
{{#if (and (eq architecture "nest-microservice") hasTodoExample)}}
|
|
28
|
+
{ provide: TodoService, useValue: {} },
|
|
29
|
+
{{/if}}
|
|
24
30
|
{{/if}}
|
|
25
31
|
],
|
|
26
32
|
}).compile();
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import { Module
|
|
2
|
-
{{#if (and hasGraphql hasRateLimiting)}}
|
|
3
|
-
import { GqlExecutionContext } from "@nestjs/graphql";
|
|
4
|
-
{{/if}}
|
|
1
|
+
import { Module } from "@nestjs/common";
|
|
5
2
|
{{#if (and isPassportAuth hasDatabase)}}
|
|
6
3
|
import { PassportModule } from "@nestjs/passport";
|
|
7
4
|
{{/if}}
|
|
@@ -50,30 +47,16 @@ import { HealthModule } from "./health/health.module.js";
|
|
|
50
47
|
{{/if}}
|
|
51
48
|
{{#if hasRateLimiting}}
|
|
52
49
|
import { APP_GUARD } from "@nestjs/core";
|
|
53
|
-
import { ThrottlerGuard, ThrottlerModule } from "@nestjs/throttler";
|
|
50
|
+
import { {{#unless hasGraphql}}ThrottlerGuard, {{/unless}}ThrottlerModule } from "@nestjs/throttler";
|
|
51
|
+
{{/if}}
|
|
52
|
+
{{#if (and hasGraphql hasRateLimiting)}}
|
|
53
|
+
import { GraphqlThrottlerGuard } from "./libs/middlewares/graphql-throttler.guard.js";
|
|
54
54
|
{{/if}}
|
|
55
55
|
{{#if (and isPassportAuth hasDatabase hasGraphql (not hasRateLimiting))}}
|
|
56
56
|
import { APP_GUARD } from "@nestjs/core";
|
|
57
57
|
{{/if}}
|
|
58
58
|
import { AppService } from "./app.service.js";
|
|
59
59
|
|
|
60
|
-
{{#if (and hasGraphql hasRateLimiting)}}
|
|
61
|
-
@Injectable()
|
|
62
|
-
class GraphqlThrottlerGuard extends ThrottlerGuard {
|
|
63
|
-
protected getRequestResponse(context: ExecutionContext) {
|
|
64
|
-
if (context.getType<string>() !== "graphql") return super.getRequestResponse(context);
|
|
65
|
-
const gqlContext = GqlExecutionContext.create(context).getContext();
|
|
66
|
-
return { req: gqlContext.req, res: { header: () => undefined } };
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
protected getTracker(request: Record<string, unknown>): Promise<string> {
|
|
70
|
-
const socket = request.socket as { remoteAddress?: string } | undefined;
|
|
71
|
-
const ip = request.ip;
|
|
72
|
-
return Promise.resolve(typeof ip === "string" ? ip : socket?.remoteAddress ?? "unknown");
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
{{/if}}
|
|
76
|
-
|
|
77
60
|
@Module({
|
|
78
61
|
{{#if hasRest}}
|
|
79
62
|
controllers: [
|
|
@@ -86,7 +69,7 @@ class GraphqlThrottlerGuard extends ThrottlerGuard {
|
|
|
86
69
|
{{#if hasPostgres}}postgresUrl: env.POSTGRES_URL,{{/if}}
|
|
87
70
|
{{#if hasMysql}}mysqlUrl: env.MYSQL_URL,{{/if}}
|
|
88
71
|
{{#if hasSqlite}}sqlitePath: env.SQLITE_PATH,{{/if}}
|
|
89
|
-
{{#if hasSqlserver}}sqlserver: {
|
|
72
|
+
{{#if hasSqlserver}}sqlserver: { database: env.SQLSERVER_DATABASE, options: { encrypt: env.SQLSERVER_ENCRYPT, trustServerCertificate: env.SQLSERVER_TRUST_SERVER_CERTIFICATE }, password: env.SQLSERVER_PASSWORD, port: env.SQLSERVER_PORT, server: env.SQLSERVER_HOST, user: env.SQLSERVER_USER },{{/if}}
|
|
90
73
|
{{#if hasMongodb}}mongodbUrl: env.MONGODB_URL,{{/if}}
|
|
91
74
|
}),
|
|
92
75
|
{{/if}}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
{{#if (and hasMongodb (or useRawSql useTypeorm))}}
|
|
2
|
+
import type { Collection, Document } from "mongodb";
|
|
3
|
+
{{/if}}
|
|
1
4
|
{{#if (or hasPostgres hasMysql hasSqlite hasSqlserver)}}
|
|
2
5
|
export interface ISqlAdapter<TClient = unknown> {
|
|
3
6
|
query: <T = unknown>(sql: string, params?: unknown[]) => Promise<T[]>;
|
|
@@ -7,12 +10,9 @@ export interface ISqlAdapter<TClient = unknown> {
|
|
|
7
10
|
{{/if}}
|
|
8
11
|
|
|
9
12
|
{{#if hasMongodb}}
|
|
10
|
-
{{#if useRawSql}}
|
|
11
|
-
import type { Collection, Document } from "mongodb";
|
|
12
|
-
{{/if}}
|
|
13
13
|
export interface IMongoAdapter<TClient = unknown> {
|
|
14
|
-
{{#if useRawSql}}
|
|
15
|
-
collection: <T
|
|
14
|
+
{{#if (or useRawSql useTypeorm)}}
|
|
15
|
+
collection: <T = unknown>(name: string) => Collection<T & Document>;
|
|
16
16
|
{{else}}
|
|
17
17
|
collection: <T = unknown>(name: string) => T;
|
|
18
18
|
{{/if}}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { Injectable, Inject
|
|
2
|
-
import
|
|
1
|
+
import { Injectable, Inject } from "@nestjs/common";
|
|
2
|
+
import type { OnModuleDestroy, OnModuleInit } from "@nestjs/common";
|
|
3
|
+
import { MongoClient } from "mongodb";
|
|
4
|
+
import type { Collection, Db, Document } from "mongodb";
|
|
3
5
|
import type { IMongoAdapter } from "../interfaces/db-adapter.interface.js";
|
|
4
6
|
|
|
5
7
|
@Injectable()
|
|
6
8
|
export class RawMongoAdapter implements IMongoAdapter<Db>, OnModuleInit, OnModuleDestroy {
|
|
7
9
|
constructor(@Inject("MONGODB_CLIENT") private readonly client: MongoClient) {}
|
|
8
|
-
collection<T
|
|
9
|
-
return this.client.db().collection<T>(name);
|
|
10
|
+
collection<T = unknown>(name: string): Collection<T & Document> {
|
|
11
|
+
return this.client.db().collection<T & Document>(name);
|
|
10
12
|
}
|
|
11
13
|
getClient(): Db { return this.client.db(); }
|
|
12
14
|
async onModuleInit(): Promise<void> {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
2
|
+
import type { OnModuleDestroy } from "@nestjs/common";
|
|
3
|
+
import type { DataSource } from "typeorm";
|
|
4
|
+
import type { Collection, Document } from "mongodb";
|
|
5
|
+
import type { IMongoAdapter } from "../interfaces/db-adapter.interface.js";
|
|
6
|
+
|
|
7
|
+
@Injectable()
|
|
8
|
+
export class TypeormMongoAdapter implements IMongoAdapter<DataSource>, OnModuleDestroy {
|
|
9
|
+
constructor(@Inject("TYPEORM_DATA_SOURCE") private readonly dataSource: DataSource) {}
|
|
10
|
+
|
|
11
|
+
collection<T = unknown>(name: string): Collection<T & Document> {
|
|
12
|
+
const databaseName = this.dataSource.options.database;
|
|
13
|
+
return this.dataSource.mongoManager.mongoQueryRunner.databaseConnection
|
|
14
|
+
.db(typeof databaseName === "string" ? databaseName : undefined)
|
|
15
|
+
.collection(name) as unknown as Collection<T & Document>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getClient(): DataSource {
|
|
19
|
+
return this.dataSource;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async onModuleDestroy(): Promise<void> {
|
|
23
|
+
if (this.dataSource.isInitialized) {
|
|
24
|
+
await this.dataSource.destroy();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -66,10 +66,18 @@ import mysql from 'mysql2/promise';
|
|
|
66
66
|
import { drizzle } from 'drizzle-orm/better-sqlite3';
|
|
67
67
|
import Database from 'better-sqlite3';
|
|
68
68
|
{{/if}}
|
|
69
|
+
{{#if hasSqlserver}}
|
|
70
|
+
import { drizzle } from 'drizzle-orm/node-mssql';
|
|
71
|
+
import sql from 'mssql';
|
|
72
|
+
{{/if}}
|
|
69
73
|
{{/if}}
|
|
70
74
|
|
|
71
75
|
{{#if useTypeorm}}
|
|
76
|
+
{{#if hasMongodb}}
|
|
77
|
+
import { TypeormMongoAdapter } from './adapters/mongo/typeorm-mongo.adapter.js';
|
|
78
|
+
{{else}}
|
|
72
79
|
import { TypeormSqlAdapter } from './adapters/sql/typeorm-sql.adapter.js';
|
|
80
|
+
{{/if}}
|
|
73
81
|
import { AppDataSource } from "./orm/typeorm/data-source.js";
|
|
74
82
|
{{/if}}
|
|
75
83
|
|
|
@@ -155,8 +163,7 @@ export class DbModule {
|
|
|
155
163
|
providers.push({
|
|
156
164
|
provide: 'PRISMA_SQL_CLIENT',
|
|
157
165
|
useValue: prismaSql,
|
|
158
|
-
}
|
|
159
|
-
providers.push({
|
|
166
|
+
}, {
|
|
160
167
|
provide: 'SQL_ADAPTER',
|
|
161
168
|
useClass: PrismaSqlAdapter,
|
|
162
169
|
});
|
|
@@ -173,8 +180,7 @@ export class DbModule {
|
|
|
173
180
|
providers.push({
|
|
174
181
|
provide: 'PRISMA_MONGO_CLIENT',
|
|
175
182
|
useValue: prismaMongo,
|
|
176
|
-
}
|
|
177
|
-
providers.push({
|
|
183
|
+
}, {
|
|
178
184
|
provide: 'MONGO_ADAPTER',
|
|
179
185
|
useClass: PrismaMongoAdapter,
|
|
180
186
|
});
|
|
@@ -184,30 +190,43 @@ export class DbModule {
|
|
|
184
190
|
{{#if useDrizzle}}
|
|
185
191
|
providers.push({
|
|
186
192
|
provide: 'DRIZZLE_CLIENT',
|
|
187
|
-
useFactory: () => {
|
|
193
|
+
useFactory: {{#if hasSqlserver}}async {{/if}}() => {
|
|
188
194
|
{{#if hasPostgres}}
|
|
189
195
|
const client = new Pool({ connectionString: options.postgresUrl });
|
|
190
196
|
return drizzle({ client, schema });
|
|
191
197
|
{{else if hasMysql}}
|
|
192
198
|
const client = mysql.createPool({ uri: options.mysqlUrl });
|
|
193
|
-
return drizzle(client, {
|
|
199
|
+
return drizzle(client, { mode: "default", schema });
|
|
200
|
+
{{else if hasSqlserver}}
|
|
201
|
+
const client = await new sql.ConnectionPool({
|
|
202
|
+
database: options.sqlserver?.database ?? 'app_db',
|
|
203
|
+
options: options.sqlserver?.options ?? { encrypt: true, trustServerCertificate: true },
|
|
204
|
+
password: options.sqlserver?.password ?? 'DevOnly_Strong_Password_2026!X9',
|
|
205
|
+
port: options.sqlserver?.port ?? 1433,
|
|
206
|
+
server: options.sqlserver?.server ?? 'localhost',
|
|
207
|
+
user: options.sqlserver?.user ?? 'sa',
|
|
208
|
+
}).connect();
|
|
209
|
+
return drizzle({ client, schema });
|
|
194
210
|
{{else}}
|
|
195
211
|
const client = new Database(options.sqlitePath || ':memory:');
|
|
196
212
|
return drizzle({ client, schema });
|
|
197
213
|
{{/if}}
|
|
198
214
|
},
|
|
199
|
-
});
|
|
200
|
-
providers.push({ provide: 'SQL_ADAPTER', useClass: DrizzleSqlAdapter });
|
|
215
|
+
}, { provide: 'SQL_ADAPTER', useClass: DrizzleSqlAdapter });
|
|
201
216
|
{{/if}}
|
|
202
217
|
|
|
203
218
|
{{#if useTypeorm}}
|
|
204
219
|
providers.push({
|
|
205
220
|
provide: 'TYPEORM_DATA_SOURCE',
|
|
206
221
|
useFactory: () => AppDataSource.initialize(),
|
|
207
|
-
}
|
|
208
|
-
|
|
222
|
+
}, {
|
|
223
|
+
{{#if hasMongodb}}
|
|
224
|
+
provide: 'MONGO_ADAPTER',
|
|
225
|
+
useClass: TypeormMongoAdapter,
|
|
226
|
+
{{else}}
|
|
209
227
|
provide: 'SQL_ADAPTER',
|
|
210
228
|
useClass: TypeormSqlAdapter,
|
|
229
|
+
{{/if}}
|
|
211
230
|
});
|
|
212
231
|
{{/if}}
|
|
213
232
|
|
|
@@ -246,12 +265,13 @@ export class DbModule {
|
|
|
246
265
|
{{/if}}
|
|
247
266
|
|
|
248
267
|
{{#if hasMongodb}}
|
|
249
|
-
if (!options.mongodbUrl)
|
|
268
|
+
if (!options.mongodbUrl) {
|
|
269
|
+
throw new Error("A MongoDB URL is required");
|
|
270
|
+
}
|
|
250
271
|
providers.push({
|
|
251
272
|
provide: 'MONGODB_CLIENT',
|
|
252
273
|
useFactory: () => new MongoClient(options.mongodbUrl!, { serverSelectionTimeoutMS: 5000 }),
|
|
253
|
-
}
|
|
254
|
-
providers.push({
|
|
274
|
+
}, {
|
|
255
275
|
provide: 'MONGO_ADAPTER',
|
|
256
276
|
useClass: RawMongoAdapter,
|
|
257
277
|
});
|
|
@@ -49,6 +49,9 @@ import type { MySql2Database } from 'drizzle-orm/mysql2';
|
|
|
49
49
|
{{#if hasSqlite}}
|
|
50
50
|
import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
|
|
51
51
|
{{/if}}
|
|
52
|
+
{{#if hasSqlserver}}
|
|
53
|
+
import type { NodeMsSqlDatabase } from 'drizzle-orm/node-mssql';
|
|
54
|
+
{{/if}}
|
|
52
55
|
{{#if isMonorepo}}
|
|
53
56
|
import type * as schema from './database/orm/drizzle/schema.js';
|
|
54
57
|
{{else}}
|
|
@@ -58,13 +61,14 @@ import type * as schema from './orm/drizzle/schema.js';
|
|
|
58
61
|
{{#if useTypeorm}}
|
|
59
62
|
import type { DataSource } from 'typeorm';
|
|
60
63
|
{{/if}}
|
|
64
|
+
|
|
61
65
|
{{#if (or hasPostgres hasMysql hasSqlite hasSqlserver)}}
|
|
62
66
|
{{#if usePrisma}}
|
|
63
67
|
type SqlClient = PrismaClient;
|
|
64
68
|
{{else if useTypeorm}}
|
|
65
69
|
type SqlClient = DataSource;
|
|
66
70
|
{{else if useDrizzle}}
|
|
67
|
-
type DrizzleClient = {{#if hasPostgres}}NodePgDatabase{{/if}}{{#if hasMysql}}MySql2Database{{/if}}{{#if hasSqlite}}BetterSQLite3Database{{/if}}<typeof schema
|
|
71
|
+
type DrizzleClient = {{#if hasPostgres}}NodePgDatabase{{/if}}{{#if hasMysql}}MySql2Database{{/if}}{{#if hasSqlite}}BetterSQLite3Database{{/if}}{{#if hasSqlserver}}NodeMsSqlDatabase<typeof schema>{{/if}}{{#unless hasSqlserver}}<typeof schema>{{/unless}};
|
|
68
72
|
type SqlClient = DrizzleClient;
|
|
69
73
|
{{else if hasPostgres}}
|
|
70
74
|
type SqlClient = import('pg').Pool;
|
|
@@ -75,6 +79,8 @@ type SqlClient = unknown;
|
|
|
75
79
|
{{#if hasMongodb}}
|
|
76
80
|
{{#if usePrisma}}
|
|
77
81
|
type MongoClient = PrismaClient;
|
|
82
|
+
{{else if useTypeorm}}
|
|
83
|
+
type MongoClient = DataSource;
|
|
78
84
|
{{else}}
|
|
79
85
|
type MongoClient = import('mongodb').Db;
|
|
80
86
|
{{/if}}
|
|
@@ -125,18 +131,20 @@ export class DbService {
|
|
|
125
131
|
{{/if}}
|
|
126
132
|
{{/if}}
|
|
127
133
|
{{#if useDrizzle}}
|
|
128
|
-
{{#if (or hasPostgres hasMysql hasSqlite)}}
|
|
134
|
+
{{#if (or hasPostgres hasMysql hasSqlite hasSqlserver)}}
|
|
129
135
|
get drizzle(): DrizzleClient {
|
|
130
136
|
return this.sql.getClient();
|
|
131
137
|
}
|
|
132
138
|
{{/if}}
|
|
133
139
|
{{/if}}
|
|
134
140
|
{{#if useTypeorm}}
|
|
135
|
-
{{#if (or hasPostgres hasMysql hasSqlite)}}
|
|
136
141
|
get typeorm(): DataSource {
|
|
142
|
+
{{#if hasMongodb}}
|
|
143
|
+
return this.mongo.getClient();
|
|
144
|
+
{{else}}
|
|
137
145
|
return this.sql.getClient();
|
|
146
|
+
{{/if}}
|
|
138
147
|
}
|
|
139
|
-
{{/if}}
|
|
140
148
|
{{/if}}
|
|
141
149
|
}
|
|
142
150
|
{{/if}}
|
|
@@ -6,26 +6,38 @@ import {
|
|
|
6
6
|
Column,
|
|
7
7
|
CreateDateColumn,
|
|
8
8
|
Entity,
|
|
9
|
+
{{#if hasMongodb}}
|
|
10
|
+
ObjectIdColumn,
|
|
11
|
+
{{else}}
|
|
9
12
|
PrimaryGeneratedColumn,
|
|
13
|
+
{{/if}}
|
|
10
14
|
UpdateDateColumn,
|
|
11
15
|
} from "typeorm";
|
|
16
|
+
{{#if hasMongodb}}
|
|
17
|
+
import type { ObjectId } from "mongodb";
|
|
18
|
+
{{/if}}
|
|
12
19
|
|
|
13
20
|
@Entity("todos")
|
|
14
21
|
export class Todo {
|
|
15
|
-
|
|
22
|
+
{{#if hasMongodb}}
|
|
23
|
+
@ObjectIdColumn()
|
|
24
|
+
id: ObjectId;
|
|
25
|
+
{{else}}
|
|
26
|
+
@PrimaryGeneratedColumn("{{#if hasSqlserver}}increment{{else}}uuid{{/if}}")
|
|
16
27
|
id: string;
|
|
28
|
+
{{/if}}
|
|
17
29
|
|
|
18
|
-
@Column({
|
|
30
|
+
@Column({ length: 255, nullable: true, type: "varchar" })
|
|
19
31
|
description?: string;
|
|
20
32
|
|
|
21
|
-
@Column({ type: "varchar"
|
|
33
|
+
@Column({ length: 255, type: "varchar" })
|
|
22
34
|
title: string;
|
|
23
35
|
|
|
24
|
-
@Column({ default: false, name: "is_completed", type: "boolean" })
|
|
36
|
+
@Column({ default: false, name: "is_completed", type: "{{#if hasSqlserver}}bit{{else}}boolean{{/if}}" })
|
|
25
37
|
completed: boolean;
|
|
26
38
|
|
|
27
39
|
{{#if hasAuth}}
|
|
28
|
-
@Column({ type: "varchar"
|
|
40
|
+
@Column({ nullable: true, type: "varchar" })
|
|
29
41
|
authorId?: string;
|
|
30
42
|
{{/if}}
|
|
31
43
|
|
|
@@ -9,6 +9,7 @@ export type { PrismaClient } from '@prisma/client';
|
|
|
9
9
|
export type { Todo } from '@prisma/client';
|
|
10
10
|
{{/if}}
|
|
11
11
|
{{else}}
|
|
12
|
+
{{#unless isPrisma8}}
|
|
12
13
|
{{#if isMonorepo}}
|
|
13
14
|
export type { PrismaClient } from './database/orm/prisma/generated/client.js';
|
|
14
15
|
{{#if hasTodoExample}}
|
|
@@ -20,6 +21,7 @@ export type { PrismaClient } from './orm/prisma/generated/client.js';
|
|
|
20
21
|
export type { Todo } from './orm/prisma/generated/client.js';
|
|
21
22
|
{{/if}}
|
|
22
23
|
{{/if}}
|
|
24
|
+
{{/unless}}
|
|
23
25
|
{{/if}}
|
|
24
26
|
{{/if}}
|
|
25
27
|
export * from './adapters/interfaces/db-adapter.interface.js';
|