@flusys/nestjs-core 1.1.0-beta → 1.2.0-rc.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 +136 -162
- package/cjs/config/env-config.service.js +14 -10
- package/cjs/docs/docs.config.js +99 -15
- package/cjs/docs/index.js +0 -1
- package/cjs/index.js +0 -1
- package/cjs/interfaces/base-entity.interface.js +5 -3
- package/cjs/interfaces/database.interface.js +1 -3
- package/cjs/migration/datasource.factory.js +1 -3
- package/cjs/migration/index.js +0 -12
- package/cjs/migration/migration.cli.js +1 -17
- package/cjs/migration/migration.runner.js +37 -65
- package/cjs/utils/datasource-config.builder.js +2 -14
- package/config/env-config.service.d.ts +3 -1
- package/docs/docs.config.d.ts +8 -0
- package/docs/index.d.ts +0 -1
- package/fesm/config/env-config.service.js +14 -10
- package/fesm/docs/docs.config.js +89 -15
- package/fesm/docs/index.js +0 -1
- package/fesm/index.js +0 -2
- package/fesm/interfaces/app-config.interfaces.js +1 -3
- package/fesm/interfaces/base-entity.interface.js +5 -5
- package/fesm/interfaces/database.interface.js +1 -5
- package/fesm/migration/cli.js +1 -20
- package/fesm/migration/datasource.factory.js +3 -20
- package/fesm/migration/index.js +0 -14
- package/fesm/migration/migration.cli.js +1 -17
- package/fesm/migration/migration.runner.js +43 -132
- package/fesm/utils/datasource-config.builder.js +2 -13
- package/index.d.ts +0 -1
- package/interfaces/app-config.interfaces.d.ts +1 -0
- package/interfaces/base-entity.interface.d.ts +2 -2
- package/interfaces/database.interface.d.ts +2 -1
- package/package.json +9 -9
- package/utils/datasource-config.builder.d.ts +0 -1
- package/cjs/docs/docs.setup.js +0 -14
- package/cjs/seeders/base-seeder.js +0 -95
- package/cjs/seeders/cli.js +0 -398
- package/cjs/seeders/data-generator.js +0 -247
- package/cjs/seeders/entity-reader.js +0 -168
- package/cjs/seeders/index.js +0 -77
- package/cjs/seeders/seed-config.js +0 -101
- package/cjs/seeders/seed-runner.js +0 -320
- package/cjs/seeders/template-generator.js +0 -297
- package/docs/docs.setup.d.ts +0 -3
- package/fesm/docs/docs.setup.js +0 -4
- package/fesm/seeders/base-seeder.js +0 -110
- package/fesm/seeders/cli.js +0 -366
- package/fesm/seeders/data-generator.js +0 -249
- package/fesm/seeders/entity-reader.js +0 -170
- package/fesm/seeders/index.js +0 -11
- package/fesm/seeders/seed-config.js +0 -85
- package/fesm/seeders/seed-runner.js +0 -323
- package/fesm/seeders/template-generator.js +0 -257
- package/seeders/base-seeder.d.ts +0 -14
- package/seeders/cli.d.ts +0 -3
- package/seeders/data-generator.d.ts +0 -15
- package/seeders/entity-reader.d.ts +0 -45
- package/seeders/index.d.ts +0 -7
- package/seeders/seed-config.d.ts +0 -11
- package/seeders/seed-runner.d.ts +0 -47
- package/seeders/template-generator.d.ts +0 -16
|
@@ -4,26 +4,37 @@ import * as path from 'path';
|
|
|
4
4
|
import { envConfig } from '../config';
|
|
5
5
|
import { getActiveTenants, getDatabaseForTenant, getMigrationsFolderPath } from '../utils';
|
|
6
6
|
import { initializeDataSource } from './datasource.factory';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
7
|
+
function getLabel(tenantId) {
|
|
8
|
+
return tenantId ? `[${tenantId}]` : '[default]';
|
|
9
|
+
}
|
|
10
|
+
async function withDataSource(config, tenantId, operation) {
|
|
11
|
+
const { database } = getDatabaseForTenant(config, tenantId);
|
|
12
|
+
const label = getLabel(tenantId);
|
|
13
|
+
try {
|
|
14
|
+
const ds = await initializeDataSource({
|
|
15
|
+
config,
|
|
16
|
+
tenantId
|
|
17
|
+
});
|
|
18
|
+
const partial = await operation(ds, label);
|
|
19
|
+
await ds.destroy();
|
|
20
|
+
return {
|
|
21
|
+
tenantId,
|
|
22
|
+
database,
|
|
23
|
+
success: true,
|
|
24
|
+
...partial
|
|
25
|
+
};
|
|
26
|
+
} catch (error) {
|
|
27
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
28
|
+
console.error(`${label} ✗ Failed: ${errorMessage}`);
|
|
29
|
+
return {
|
|
30
|
+
tenantId,
|
|
31
|
+
database,
|
|
32
|
+
success: false,
|
|
33
|
+
error: errorMessage
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export function ensureMigrationsFolder(basePath, tenantId) {
|
|
27
38
|
const folder = getMigrationsFolderPath(basePath, tenantId);
|
|
28
39
|
if (!fs.existsSync(folder)) {
|
|
29
40
|
fs.mkdirSync(folder, {
|
|
@@ -33,16 +44,7 @@ import { initializeDataSource } from './datasource.factory';
|
|
|
33
44
|
}
|
|
34
45
|
return folder;
|
|
35
46
|
}
|
|
36
|
-
|
|
37
|
-
* Generate a new migration file
|
|
38
|
-
*
|
|
39
|
-
* Uses TypeORM CLI to generate migration based on entity changes.
|
|
40
|
-
*
|
|
41
|
-
* @param config - Migration configuration
|
|
42
|
-
* @param name - Migration name (e.g., "CreateUsers")
|
|
43
|
-
* @param tenantId - Optional tenant ID for multi-tenant mode
|
|
44
|
-
* @param datasourcePath - Optional path to datasource file
|
|
45
|
-
*/ export async function generateMigration(config, name, tenantId, datasourcePath) {
|
|
47
|
+
export async function generateMigration(config, name, tenantId, datasourcePath) {
|
|
46
48
|
const label = tenantId ? `[${tenantId}]` : '[default]';
|
|
47
49
|
const folder = ensureMigrationsFolder(config.migrationsPath, tenantId);
|
|
48
50
|
console.log(`${label} Generating migration: ${name}`);
|
|
@@ -72,24 +74,9 @@ function findDatasourcePath() {
|
|
|
72
74
|
}
|
|
73
75
|
throw new Error('Could not find datasource file. Specify with --datasource=<path>');
|
|
74
76
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
*
|
|
78
|
-
* Executes all pending migrations for the specified tenant or default database.
|
|
79
|
-
*
|
|
80
|
-
* @param config - Migration configuration
|
|
81
|
-
* @param tenantId - Optional tenant ID for multi-tenant mode
|
|
82
|
-
* @returns Migration result with success status
|
|
83
|
-
*/ export async function runMigrations(config, tenantId) {
|
|
84
|
-
const { database } = getDatabaseForTenant(config, tenantId);
|
|
85
|
-
const label = tenantId ? `[${tenantId}]` : '[default]';
|
|
86
|
-
try {
|
|
87
|
-
const ds = await initializeDataSource({
|
|
88
|
-
config,
|
|
89
|
-
tenantId
|
|
90
|
-
});
|
|
77
|
+
export async function runMigrations(config, tenantId) {
|
|
78
|
+
return withDataSource(config, tenantId, async (ds, label)=>{
|
|
91
79
|
const migrations = await ds.runMigrations();
|
|
92
|
-
await ds.destroy();
|
|
93
80
|
if (migrations.length === 0) {
|
|
94
81
|
console.log(`${label} No pending migrations.`);
|
|
95
82
|
} else {
|
|
@@ -97,105 +84,29 @@ function findDatasourcePath() {
|
|
|
97
84
|
migrations.forEach((m)=>console.log(` - ${m.name}`));
|
|
98
85
|
}
|
|
99
86
|
return {
|
|
100
|
-
tenantId,
|
|
101
|
-
database,
|
|
102
|
-
success: true,
|
|
103
87
|
migrationsRun: migrations.map((m)=>m.name)
|
|
104
88
|
};
|
|
105
|
-
}
|
|
106
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
107
|
-
console.error(`${label} ✗ Failed: ${errorMessage}`);
|
|
108
|
-
return {
|
|
109
|
-
tenantId,
|
|
110
|
-
database,
|
|
111
|
-
success: false,
|
|
112
|
-
error: errorMessage
|
|
113
|
-
};
|
|
114
|
-
}
|
|
89
|
+
});
|
|
115
90
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
*
|
|
119
|
-
* Rolls back the most recently executed migration.
|
|
120
|
-
*
|
|
121
|
-
* @param config - Migration configuration
|
|
122
|
-
* @param tenantId - Optional tenant ID for multi-tenant mode
|
|
123
|
-
* @returns Migration result with success status
|
|
124
|
-
*/ export async function revertMigration(config, tenantId) {
|
|
125
|
-
const { database } = getDatabaseForTenant(config, tenantId);
|
|
126
|
-
const label = tenantId ? `[${tenantId}]` : '[default]';
|
|
127
|
-
try {
|
|
128
|
-
const ds = await initializeDataSource({
|
|
129
|
-
config,
|
|
130
|
-
tenantId
|
|
131
|
-
});
|
|
91
|
+
export async function revertMigration(config, tenantId) {
|
|
92
|
+
return withDataSource(config, tenantId, async (ds, label)=>{
|
|
132
93
|
await ds.undoLastMigration();
|
|
133
|
-
await ds.destroy();
|
|
134
94
|
console.log(`${label} ✓ Reverted!`);
|
|
135
|
-
return {
|
|
136
|
-
|
|
137
|
-
database,
|
|
138
|
-
success: true
|
|
139
|
-
};
|
|
140
|
-
} catch (error) {
|
|
141
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
142
|
-
console.error(`${label} ✗ Failed: ${errorMessage}`);
|
|
143
|
-
return {
|
|
144
|
-
tenantId,
|
|
145
|
-
database,
|
|
146
|
-
success: false,
|
|
147
|
-
error: errorMessage
|
|
148
|
-
};
|
|
149
|
-
}
|
|
95
|
+
return {};
|
|
96
|
+
});
|
|
150
97
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
*
|
|
154
|
-
* Shows whether there are pending migrations to run.
|
|
155
|
-
*
|
|
156
|
-
* @param config - Migration configuration
|
|
157
|
-
* @param tenantId - Optional tenant ID for multi-tenant mode
|
|
158
|
-
* @returns Migration result with status information
|
|
159
|
-
*/ export async function migrationStatus(config, tenantId) {
|
|
160
|
-
const { database } = getDatabaseForTenant(config, tenantId);
|
|
161
|
-
const label = tenantId ? `[${tenantId}]` : '[default]';
|
|
162
|
-
try {
|
|
163
|
-
const ds = await initializeDataSource({
|
|
164
|
-
config,
|
|
165
|
-
tenantId
|
|
166
|
-
});
|
|
98
|
+
export async function migrationStatus(config, tenantId) {
|
|
99
|
+
return withDataSource(config, tenantId, async (ds, label)=>{
|
|
167
100
|
const hasPending = await ds.showMigrations();
|
|
168
|
-
await ds.destroy();
|
|
169
101
|
console.log(`${label} Pending: ${hasPending ? 'Yes' : 'No'}`);
|
|
170
102
|
return {
|
|
171
|
-
tenantId,
|
|
172
|
-
database,
|
|
173
|
-
success: true,
|
|
174
103
|
migrationsRun: [
|
|
175
104
|
hasPending ? 'Has pending' : 'Up to date'
|
|
176
105
|
]
|
|
177
106
|
};
|
|
178
|
-
}
|
|
179
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
180
|
-
console.error(`${label} ✗ Failed: ${errorMessage}`);
|
|
181
|
-
return {
|
|
182
|
-
tenantId,
|
|
183
|
-
database,
|
|
184
|
-
success: false,
|
|
185
|
-
error: errorMessage
|
|
186
|
-
};
|
|
187
|
-
}
|
|
107
|
+
});
|
|
188
108
|
}
|
|
189
|
-
|
|
190
|
-
* Run migration command for all tenants
|
|
191
|
-
*
|
|
192
|
-
* Executes the specified command for all active tenants in batch mode.
|
|
193
|
-
* Only works in multi-tenant database mode.
|
|
194
|
-
*
|
|
195
|
-
* @param config - Migration configuration
|
|
196
|
-
* @param command - Command to run: 'run', 'revert', or 'status'
|
|
197
|
-
* @returns Array of migration results for each tenant
|
|
198
|
-
*/ export async function runForAllTenants(config, command) {
|
|
109
|
+
export async function runForAllTenants(config, command) {
|
|
199
110
|
const tenants = getActiveTenants(config);
|
|
200
111
|
console.log(`\n🔄 Running '${command}' for ${tenants.length} tenant(s)...\n`);
|
|
201
112
|
const results = [];
|
|
@@ -45,7 +45,8 @@
|
|
|
45
45
|
const defaultTenantConfig = {
|
|
46
46
|
id: 'default',
|
|
47
47
|
database: config.defaultDatabaseConfig.database || 'default',
|
|
48
|
-
enableCompanyFeature: config.bootstrapAppConfig?.enableCompanyFeature ?? false
|
|
48
|
+
enableCompanyFeature: config.bootstrapAppConfig?.enableCompanyFeature ?? false,
|
|
49
|
+
permissionMode: config.bootstrapAppConfig?.permissionMode ?? 'FULL'
|
|
49
50
|
};
|
|
50
51
|
return {
|
|
51
52
|
database: defaultTenantConfig.database,
|
|
@@ -60,18 +61,6 @@
|
|
|
60
61
|
}
|
|
61
62
|
return config.entities;
|
|
62
63
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Build full database config for a tenant
|
|
65
|
-
*/ export function buildTenantDatabaseConfig(baseConfig, tenant) {
|
|
66
|
-
return {
|
|
67
|
-
type: baseConfig.type,
|
|
68
|
-
host: tenant.host ?? baseConfig.host,
|
|
69
|
-
port: tenant.port ?? baseConfig.port,
|
|
70
|
-
username: tenant.username ?? baseConfig.username,
|
|
71
|
-
password: tenant.password ?? baseConfig.password,
|
|
72
|
-
database: tenant.database
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
64
|
/**
|
|
76
65
|
* Get active tenants from config
|
|
77
66
|
*/ export function getActiveTenants(config) {
|
package/index.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface ITenantDatabaseConfig {
|
|
|
17
17
|
password?: string;
|
|
18
18
|
database: string;
|
|
19
19
|
enableCompanyFeature?: boolean;
|
|
20
|
+
enableEmailVerification?: boolean;
|
|
20
21
|
permissionMode?: 'FULL' | 'RBAC' | 'DIRECT';
|
|
21
22
|
}
|
|
22
23
|
export interface IDataSourceBuildOptions {
|
|
@@ -30,5 +31,5 @@ export interface IDataSourceBuildOptions {
|
|
|
30
31
|
migrations: string[];
|
|
31
32
|
migrationsTableName: string;
|
|
32
33
|
synchronize: boolean;
|
|
33
|
-
namingStrategy?:
|
|
34
|
+
namingStrategy?: unknown;
|
|
34
35
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/nestjs-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0-rc.1",
|
|
4
4
|
"description": "Core types, interfaces, and constants for Flusys NestJS packages",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "fesm/index.js",
|
|
@@ -61,15 +61,15 @@
|
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
|
-
"@faker-js/faker": "^
|
|
65
|
-
"@nestjs/common": "^
|
|
66
|
-
"@nestjs/config": "^
|
|
67
|
-
"@nestjs/core": "^
|
|
68
|
-
"@nestjs/swagger": "^
|
|
69
|
-
"@nestjs/typeorm": "^
|
|
70
|
-
"dotenv": "^
|
|
64
|
+
"@faker-js/faker": "^10.0.0",
|
|
65
|
+
"@nestjs/common": "^11.0.0",
|
|
66
|
+
"@nestjs/config": "^4.0.0",
|
|
67
|
+
"@nestjs/core": "^11.0.0",
|
|
68
|
+
"@nestjs/swagger": "^11.0.0",
|
|
69
|
+
"@nestjs/typeorm": "^11.0.0",
|
|
70
|
+
"dotenv": "^17.0.0",
|
|
71
71
|
"typeorm": "^0.3.0",
|
|
72
|
-
"typeorm-naming-strategies": "^4.
|
|
72
|
+
"typeorm-naming-strategies": "^4.1.0"
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {}
|
|
75
75
|
}
|
|
@@ -9,5 +9,4 @@ export declare function getDatabaseForTenant(config: IMigrationConfig, tenantId?
|
|
|
9
9
|
tenantConfig: ITenantDatabaseConfig;
|
|
10
10
|
};
|
|
11
11
|
export declare function resolveEntities(config: IMigrationConfig, tenantConfig?: ITenantDatabaseConfig): any[];
|
|
12
|
-
export declare function buildTenantDatabaseConfig(baseConfig: IDatabaseConfig, tenant: ITenantDatabaseConfig): IDatabaseConfig;
|
|
13
12
|
export declare function getActiveTenants(config: IMigrationConfig): ITenantDatabaseConfig[];
|
package/cjs/docs/docs.setup.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "setupSwaggerDocs", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return setupSwaggerDocs;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
const _docsconfig = require("./docs.config");
|
|
12
|
-
function setupSwaggerDocs(app, ...modules) {
|
|
13
|
-
(0, _docsconfig.setupModuleSwaggerDocs)(app, modules);
|
|
14
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "BaseSeeder", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return BaseSeeder;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
function _define_property(obj, key, value) {
|
|
12
|
-
if (key in obj) {
|
|
13
|
-
Object.defineProperty(obj, key, {
|
|
14
|
-
value: value,
|
|
15
|
-
enumerable: true,
|
|
16
|
-
configurable: true,
|
|
17
|
-
writable: true
|
|
18
|
-
});
|
|
19
|
-
} else {
|
|
20
|
-
obj[key] = value;
|
|
21
|
-
}
|
|
22
|
-
return obj;
|
|
23
|
-
}
|
|
24
|
-
let BaseSeeder = class BaseSeeder {
|
|
25
|
-
/**
|
|
26
|
-
* Clear all records from the entity table
|
|
27
|
-
* Respects soft delete if entity has deletedAt column
|
|
28
|
-
* @param hard If true, perform hard delete (ignore soft delete)
|
|
29
|
-
*/ async clear(hard = false) {
|
|
30
|
-
const hasSoftDelete = this.metadata.deleteDateColumn !== undefined;
|
|
31
|
-
if (hard || !hasSoftDelete) {
|
|
32
|
-
// Hard delete - remove all records
|
|
33
|
-
await this.repository.clear();
|
|
34
|
-
} else {
|
|
35
|
-
// Soft delete - set deletedAt
|
|
36
|
-
await this.repository.createQueryBuilder().softDelete().where('id IS NOT NULL').execute();
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Get count of existing records
|
|
41
|
-
* @param includeDeleted If true, count soft-deleted records
|
|
42
|
-
* @returns Total record count
|
|
43
|
-
*/ async count(includeDeleted = false) {
|
|
44
|
-
const hasSoftDelete = this.metadata.deleteDateColumn !== undefined;
|
|
45
|
-
if (hasSoftDelete && !includeDeleted) {
|
|
46
|
-
return this.repository.count({
|
|
47
|
-
where: {
|
|
48
|
-
deletedAt: null
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
return this.repository.count();
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Check if entity has any records
|
|
56
|
-
* @returns True if no records exist
|
|
57
|
-
*/ async isEmpty() {
|
|
58
|
-
const total = await this.count();
|
|
59
|
-
return total === 0;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Get entity name for logging
|
|
63
|
-
*/ getEntityName() {
|
|
64
|
-
return this.metadata.tableName;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Wrap operation in transaction
|
|
68
|
-
* @param operation Function to execute in transaction
|
|
69
|
-
*/ async withTransaction(operation) {
|
|
70
|
-
const queryRunner = this.dataSource.createQueryRunner();
|
|
71
|
-
await queryRunner.connect();
|
|
72
|
-
await queryRunner.startTransaction();
|
|
73
|
-
try {
|
|
74
|
-
const transactionalRepo = queryRunner.manager.getRepository(this.entity);
|
|
75
|
-
const result = await operation(transactionalRepo);
|
|
76
|
-
await queryRunner.commitTransaction();
|
|
77
|
-
return result;
|
|
78
|
-
} catch (error) {
|
|
79
|
-
await queryRunner.rollbackTransaction();
|
|
80
|
-
throw error;
|
|
81
|
-
} finally{
|
|
82
|
-
await queryRunner.release();
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
constructor(dataSource, entity){
|
|
86
|
-
_define_property(this, "dataSource", void 0);
|
|
87
|
-
_define_property(this, "entity", void 0);
|
|
88
|
-
_define_property(this, "repository", void 0);
|
|
89
|
-
_define_property(this, "metadata", void 0);
|
|
90
|
-
this.dataSource = dataSource;
|
|
91
|
-
this.entity = entity;
|
|
92
|
-
this.repository = dataSource.getRepository(entity);
|
|
93
|
-
this.metadata = this.repository.metadata;
|
|
94
|
-
}
|
|
95
|
-
};
|