fiberx-backend-toolkit 0.1.21 → 1.0.3
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 +207 -139
- package/dist/code_templates/email_enqueue_code_template.js +2 -2
- package/dist/code_templates/sequelize_code_template.d.ts +1 -1
- package/dist/code_templates/sequelize_code_template.js +131 -78
- package/dist/config/constants.d.ts +1 -0
- package/dist/config/constants.js +82 -15
- package/dist/database/connectors/sequelize_connector.d.ts +2 -0
- package/dist/database/connectors/sequelize_connector.js +43 -21
- package/dist/database/main.d.ts +3 -2
- package/dist/database/main.js +4 -2
- package/dist/database/schema/schema_diff_util.d.ts +0 -1
- package/dist/database/schema/schema_diff_util.js +7 -15
- package/dist/database/scripts/create_schema_script.js +6 -3
- package/dist/database/scripts/make_migrations_script.js +17 -10
- package/dist/database/scripts/migration_runner_script.d.ts +3 -1
- package/dist/database/scripts/migration_runner_script.js +58 -23
- package/dist/database/scripts/seeder_runner_script.d.ts +3 -1
- package/dist/database/scripts/seeder_runner_script.js +49 -17
- package/dist/database/scripts/sequelize_model_generator_script.d.ts +2 -2
- package/dist/database/scripts/sequelize_model_generator_script.js +11 -5
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/mailer/main.d.ts +1 -1
- package/dist/mailer/processors/email_delivery_processor.js +45 -13
- package/dist/mailer/processors/email_enqueue_processor.js +23 -7
- package/dist/mailer/utils/mailer_data_loader_util.d.ts +4 -4
- package/dist/mailer/utils/mailer_data_loader_util.js +5 -5
- package/dist/middle_ware/authentication_middle_ware.d.ts +3 -3
- package/dist/middle_ware/authentication_middle_ware.js +27 -25
- package/dist/middle_ware/cookie_manager_middle_ware.js +1 -1
- package/dist/middle_ware/main.d.ts +3 -2
- package/dist/middle_ware/main.js +4 -2
- package/dist/middle_ware/rate_limiter_middle_ware.js +0 -1
- package/dist/middle_ware/request_logger_middle_ware.js +2 -1
- package/dist/middle_ware/response_formatter_middle_ware.js +5 -4
- package/dist/middle_ware/secure_headers_middle_ware.js +2 -1
- package/dist/rbac/rbac_loader_util.js +2 -2
- package/dist/storage/drivers/gcs_storage_driver.js +5 -5
- package/dist/storage/drivers/local_storage_driver.js +2 -2
- package/dist/storage/main.d.ts +1 -1
- package/dist/storage/processors/file_upload_processor.js +4 -4
- package/dist/storage/utils/storage_driver_util.d.ts +1 -1
- package/dist/storage/utils/storage_driver_util.js +12 -10
- package/dist/types/express_decelaration.d.ts +1 -1
- package/dist/types/express_decelaration.js +0 -1
- package/dist/types/middle_ware_type.d.ts +14 -12
- package/dist/types/middle_ware_type.js +0 -2
- package/dist/types/schema_type.js +0 -1
- package/dist/types/util_type.js +0 -1
- package/dist/utils/content_manager_util.js +11 -9
- package/dist/utils/crypto_key_util.js +9 -10
- package/dist/utils/encryptor_decryptor_util.js +19 -9
- package/dist/utils/env_manager_util.d.ts +1 -0
- package/dist/utils/env_manager_util.js +10 -2
- package/dist/utils/fs_actions_util.js +1 -1
- package/dist/utils/input_transformer_util.js +11 -25
- package/dist/utils/input_validator_util.d.ts +1 -1
- package/dist/utils/input_validator_util.js +75 -27
- package/dist/utils/logger_util.d.ts +2 -2
- package/dist/utils/logger_util.js +23 -9
- package/dist/utils/main.d.ts +1 -1
- package/dist/utils/safe_execute_util.js +21 -11
- package/dist/utils/sql_formatter_util.js +1 -5
- package/dist/utils/totp_service_util.js +3 -7
- package/dist/utils/uuid_gen_util.js +6 -2
- package/dist/validators/file_validator_util.js +2 -2
- package/dist/validators/query_validator_util.js +3 -3
- package/package.json +68 -2
|
@@ -35,18 +35,32 @@ class SequelizeConnector extends base_connector_1.default {
|
|
|
35
35
|
this.logger.error("Failed to log SQL query", { error });
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
+
coerceBoolean(value, fallback) {
|
|
39
|
+
if (typeof value === "boolean")
|
|
40
|
+
return value;
|
|
41
|
+
if (typeof value === "string") {
|
|
42
|
+
return ["true", "1", "yes", "on"].includes(value.trim().toLowerCase());
|
|
43
|
+
}
|
|
44
|
+
if (typeof value === "number")
|
|
45
|
+
return value === 1;
|
|
46
|
+
return fallback;
|
|
47
|
+
}
|
|
48
|
+
coerceNumber(value, fallback) {
|
|
49
|
+
const parsed = Number(value);
|
|
50
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
51
|
+
}
|
|
38
52
|
// ------------------------------------------------
|
|
39
53
|
// Create Sequelize instance (shared)
|
|
40
54
|
// ------------------------------------------------
|
|
41
55
|
createSequelizeInstance(options = {}) {
|
|
42
56
|
const dialect = options.dialect ?? this.env_manager.getEnvVar("DB_DIALECT", "postgres");
|
|
43
|
-
const logging_enabled = options.logging ?? this.env_manager.getEnvVar("DB_LOGGING", false);
|
|
57
|
+
const logging_enabled = this.coerceBoolean(options.logging ?? this.env_manager.getEnvVar("DB_LOGGING", false), false);
|
|
44
58
|
const logging = logging_enabled ? this.formatSQLQueryLog : false;
|
|
45
59
|
const database = options.database ?? this.env_manager.getEnvVar("DB_NAME");
|
|
46
60
|
const username = options.username ?? this.env_manager.getEnvVar("DB_USER");
|
|
47
61
|
const password = options.password ?? this.env_manager.getEnvVar("DB_PASSWORD");
|
|
48
62
|
const host = options.host ?? this.env_manager.getEnvVar("DB_HOST");
|
|
49
|
-
const port = options.port ?? this.env_manager.getEnvVar("DB_PORT", 5432);
|
|
63
|
+
const port = this.coerceNumber(options.port ?? this.env_manager.getEnvVar("DB_PORT", 5432), 5432);
|
|
50
64
|
return new sequelize_1.Sequelize({
|
|
51
65
|
database,
|
|
52
66
|
username,
|
|
@@ -79,28 +93,36 @@ class SequelizeConnector extends base_connector_1.default {
|
|
|
79
93
|
dialect,
|
|
80
94
|
logging: false,
|
|
81
95
|
});
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
96
|
+
try {
|
|
97
|
+
await admin.authenticate();
|
|
98
|
+
const queryInterface = admin.getQueryInterface();
|
|
99
|
+
const quoted_database = queryInterface.quoteIdentifier(database);
|
|
100
|
+
switch (dialect) {
|
|
101
|
+
case "postgres": {
|
|
102
|
+
const [rows] = await admin.query(`SELECT 1 FROM pg_database WHERE datname = :db`, { replacements: { db: database } });
|
|
103
|
+
if (rows.length === 0) {
|
|
104
|
+
await admin.query(`CREATE DATABASE ${quoted_database}`);
|
|
105
|
+
this.logger.info(`📦 Created DB ${database}`);
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case "mysql":
|
|
110
|
+
case "mariadb":
|
|
111
|
+
await admin.query(`CREATE DATABASE IF NOT EXISTS ${quoted_database}`);
|
|
112
|
+
break;
|
|
113
|
+
case "mssql": {
|
|
114
|
+
const escaped_database = database.replace(/'/g, "''");
|
|
115
|
+
await admin.query(`
|
|
116
|
+
IF DB_ID('${escaped_database}') IS NULL
|
|
117
|
+
CREATE DATABASE ${quoted_database}
|
|
118
|
+
`);
|
|
119
|
+
break;
|
|
89
120
|
}
|
|
90
|
-
break;
|
|
91
121
|
}
|
|
92
|
-
case "mysql":
|
|
93
|
-
case "mariadb":
|
|
94
|
-
await admin.query(`CREATE DATABASE IF NOT EXISTS \`${database}\``);
|
|
95
|
-
break;
|
|
96
|
-
case "mssql":
|
|
97
|
-
await admin.query(`
|
|
98
|
-
IF DB_ID('${database}') IS NULL
|
|
99
|
-
CREATE DATABASE [${database}]
|
|
100
|
-
`);
|
|
101
|
-
break;
|
|
102
122
|
}
|
|
103
|
-
|
|
123
|
+
finally {
|
|
124
|
+
await admin.close();
|
|
125
|
+
}
|
|
104
126
|
}
|
|
105
127
|
catch (error) {
|
|
106
128
|
this.logger.error(`DB auto-create skipped: ${database}`, { error });
|
package/dist/database/main.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ import MakeMigrationsScript from "./scripts/make_migrations_script";
|
|
|
5
5
|
import MigrationRunnerScript from "./scripts/migration_runner_script";
|
|
6
6
|
import CreateSeederScript from "./scripts/create_seeder_script";
|
|
7
7
|
import SeederRunnerScript from "./scripts/seeder_runner_script";
|
|
8
|
-
import
|
|
8
|
+
import SequelizeModelGeneratorScript from "./scripts/sequelize_model_generator_script";
|
|
9
|
+
declare const SeqeulizeModelGeneratorScript: typeof SequelizeModelGeneratorScript;
|
|
9
10
|
import BaseConnector from "./connectors/base_connector";
|
|
10
11
|
import SequelizeConnector from "./connectors/sequelize_connector";
|
|
11
|
-
export { SchemaDiffUtil, SchemaNormalizerUtil, CreateSchemaScript, MakeMigrationsScript, MigrationRunnerScript, CreateSeederScript, SeederRunnerScript, SeqeulizeModelGeneratorScript, BaseConnector, SequelizeConnector };
|
|
12
|
+
export { SchemaDiffUtil, SchemaNormalizerUtil, CreateSchemaScript, MakeMigrationsScript, MigrationRunnerScript, CreateSeederScript, SeederRunnerScript, SequelizeModelGeneratorScript, SeqeulizeModelGeneratorScript, BaseConnector, SequelizeConnector, };
|
package/dist/database/main.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.SequelizeConnector = exports.BaseConnector = exports.SeqeulizeModelGeneratorScript = exports.SeederRunnerScript = exports.CreateSeederScript = exports.MigrationRunnerScript = exports.MakeMigrationsScript = exports.CreateSchemaScript = exports.SchemaNormalizerUtil = exports.SchemaDiffUtil = void 0;
|
|
6
|
+
exports.SequelizeConnector = exports.BaseConnector = exports.SeqeulizeModelGeneratorScript = exports.SequelizeModelGeneratorScript = exports.SeederRunnerScript = exports.CreateSeederScript = exports.MigrationRunnerScript = exports.MakeMigrationsScript = exports.CreateSchemaScript = exports.SchemaNormalizerUtil = exports.SchemaDiffUtil = void 0;
|
|
7
7
|
const schema_diff_util_1 = __importDefault(require("./schema/schema_diff_util"));
|
|
8
8
|
exports.SchemaDiffUtil = schema_diff_util_1.default;
|
|
9
9
|
const schema_normalizer_util_1 = __importDefault(require("./schema/schema_normalizer_util"));
|
|
@@ -19,7 +19,9 @@ exports.CreateSeederScript = create_seeder_script_1.default;
|
|
|
19
19
|
const seeder_runner_script_1 = __importDefault(require("./scripts/seeder_runner_script"));
|
|
20
20
|
exports.SeederRunnerScript = seeder_runner_script_1.default;
|
|
21
21
|
const sequelize_model_generator_script_1 = __importDefault(require("./scripts/sequelize_model_generator_script"));
|
|
22
|
-
exports.
|
|
22
|
+
exports.SequelizeModelGeneratorScript = sequelize_model_generator_script_1.default;
|
|
23
|
+
const SeqeulizeModelGeneratorScript = sequelize_model_generator_script_1.default;
|
|
24
|
+
exports.SeqeulizeModelGeneratorScript = SeqeulizeModelGeneratorScript;
|
|
23
25
|
const base_connector_1 = __importDefault(require("./connectors/base_connector"));
|
|
24
26
|
exports.BaseConnector = base_connector_1.default;
|
|
25
27
|
const sequelize_connector_1 = __importDefault(require("./connectors/sequelize_connector"));
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { SchemaDiffInterface, SchemaSnapshotInterface } from "../../types/schema_type";
|
|
2
2
|
declare class SchemaDiffUtil {
|
|
3
|
-
private static indexKey;
|
|
4
3
|
static getSchemaDifference(prev: SchemaSnapshotInterface, curr: SchemaSnapshotInterface): SchemaDiffInterface;
|
|
5
4
|
}
|
|
6
5
|
export default SchemaDiffUtil;
|
|
@@ -5,18 +5,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const input_validator_util_1 = __importDefault(require("../../utils/input_validator_util"));
|
|
7
7
|
class SchemaDiffUtil {
|
|
8
|
-
static indexKey(i) {
|
|
9
|
-
return JSON.stringify({
|
|
10
|
-
fields: i.fields,
|
|
11
|
-
unique: i.unique,
|
|
12
|
-
using: i.using,
|
|
13
|
-
operator: i.operator,
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
8
|
static getSchemaDifference(prev, curr) {
|
|
17
9
|
const diff = {
|
|
18
10
|
columns: { added: [], removed: [], modified: [] },
|
|
19
|
-
indexes: { added: [], removed: [], modified: [] }
|
|
11
|
+
indexes: { added: [], removed: [], modified: [] },
|
|
20
12
|
};
|
|
21
13
|
// Table rename
|
|
22
14
|
if (prev.table_name !== curr.table_name) {
|
|
@@ -45,10 +37,10 @@ class SchemaDiffUtil {
|
|
|
45
37
|
// Indexes
|
|
46
38
|
const prev_indexes = prev?.indexes || [];
|
|
47
39
|
const curr_indexes = curr?.indexes || [];
|
|
48
|
-
const prev_map = new Map(prev_indexes.map(i => [
|
|
49
|
-
const curr_map = new Map(curr_indexes.map(i => [
|
|
50
|
-
for (const [
|
|
51
|
-
const prev_idx = prev_map.get(
|
|
40
|
+
const prev_map = new Map(prev_indexes.map((i) => [i.name, i]));
|
|
41
|
+
const curr_map = new Map(curr_indexes.map((i) => [i.name, i]));
|
|
42
|
+
for (const [name, curr_idx] of curr_map) {
|
|
43
|
+
const prev_idx = prev_map.get(name);
|
|
52
44
|
if (!prev_idx) {
|
|
53
45
|
diff.indexes.added.push(curr_idx.name);
|
|
54
46
|
}
|
|
@@ -56,8 +48,8 @@ class SchemaDiffUtil {
|
|
|
56
48
|
diff.indexes.modified.push(curr_idx.name);
|
|
57
49
|
}
|
|
58
50
|
}
|
|
59
|
-
for (const [
|
|
60
|
-
if (!curr_map.has(
|
|
51
|
+
for (const [name, prev_idx] of prev_map) {
|
|
52
|
+
if (!curr_map.has(name)) {
|
|
61
53
|
diff.indexes.removed.push(prev_idx.name);
|
|
62
54
|
}
|
|
63
55
|
}
|
|
@@ -57,8 +57,12 @@ class CreateSchemaScript {
|
|
|
57
57
|
run() {
|
|
58
58
|
const file_base_name = main_1.InputTransformerUtil.toSchemaFileName(this.raw_input);
|
|
59
59
|
const base_pascal = main_1.InputTransformerUtil.toPascalCase(file_base_name);
|
|
60
|
-
const schema_name = base_pascal.toLowerCase().endsWith("schema")
|
|
61
|
-
|
|
60
|
+
const schema_name = base_pascal.toLowerCase().endsWith("schema")
|
|
61
|
+
? base_pascal
|
|
62
|
+
: `${base_pascal}Schema`;
|
|
63
|
+
const model_name = base_pascal.toLowerCase().endsWith("schema")
|
|
64
|
+
? base_pascal.replace(/Schema$/i, "")
|
|
65
|
+
: base_pascal;
|
|
62
66
|
const table_name = main_1.InputTransformerUtil.pluralizeSnakeCase(main_1.InputTransformerUtil.toSnakeCase(model_name));
|
|
63
67
|
const migration_priority = this.getNextMigrationPriority();
|
|
64
68
|
const file_name = `${file_base_name}.ts`;
|
|
@@ -67,7 +71,6 @@ class CreateSchemaScript {
|
|
|
67
71
|
main_1.InputValidatorUtil.dirExists(this.schemas_dir, true);
|
|
68
72
|
this.ensureSchemaDoesNotExist(file_path);
|
|
69
73
|
this.createSchemaFile(file_path, schema_name, model_name, table_name, migration_priority);
|
|
70
|
-
;
|
|
71
74
|
this.logger.success(`✅ Schema created successfully Created database/schemas/${file_base_name}.ts`);
|
|
72
75
|
this.logger.info(`📄 File Path: ${file_path}`);
|
|
73
76
|
this.logger.info(`🧩 Schema Name: ${schema_name}`);
|
|
@@ -21,10 +21,12 @@ class MakeMigrationsScript {
|
|
|
21
21
|
}
|
|
22
22
|
// Method to handle generating migration file name
|
|
23
23
|
generateMigrationFilename(table_name, type, migration_priority) {
|
|
24
|
-
const timestamp = new Date()
|
|
24
|
+
const timestamp = new Date()
|
|
25
|
+
.toISOString()
|
|
26
|
+
.replace(/[-:.TZ]/g, "")
|
|
27
|
+
.slice(0, 14);
|
|
25
28
|
return `${migration_priority}_${timestamp}_${type}_table_${table_name}.ts`;
|
|
26
29
|
}
|
|
27
|
-
;
|
|
28
30
|
// Methos to write schema snapshot
|
|
29
31
|
writeSchemaSnapshot(model_name, schema_file_path) {
|
|
30
32
|
const snapshot_path = this.getSnapshotPath(model_name);
|
|
@@ -43,9 +45,8 @@ class MakeMigrationsScript {
|
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
47
|
// Method to handle create update schema table migration file
|
|
46
|
-
createUpdateSchemaMigrationFile(file_path,
|
|
48
|
+
createUpdateSchemaMigrationFile(file_path, schema_content, prev_schema_content, schema_diff) {
|
|
47
49
|
const { table_name, model_name } = schema_content;
|
|
48
|
-
const schema_file_name = path_1.default.basename(schema_file_path);
|
|
49
50
|
const template = (0, sequelize_code_template_1.SEQUELIZE_UPDATE_EXISTING_SCHEMA_MIGRATION_FILE_CODE_TEMPLATE)(table_name, model_name, schema_diff, schema_content, prev_schema_content);
|
|
50
51
|
try {
|
|
51
52
|
fs_1.default.writeFileSync(file_path, template, { encoding: "utf-8" });
|
|
@@ -73,9 +74,12 @@ class MakeMigrationsScript {
|
|
|
73
74
|
// Method to handle creating migration files for new and updated schemas
|
|
74
75
|
createMigrationForSchema(schema_file_path, schema_content) {
|
|
75
76
|
this.logger.info(`💾 Ready to create migration for: ${schema_file_path}`);
|
|
76
|
-
const { table_name, migration_priority, model_name
|
|
77
|
-
if (!table_name
|
|
78
|
-
|
|
77
|
+
const { table_name, migration_priority, model_name } = schema_content;
|
|
78
|
+
if (!table_name ||
|
|
79
|
+
!model_name ||
|
|
80
|
+
!schema_content.columns ||
|
|
81
|
+
!Number.isFinite(Number(migration_priority))) {
|
|
82
|
+
this.logger.error(`❌ Schema is missing table_name, model_name, migration_priority, or columns: ${schema_file_path}`);
|
|
79
83
|
return;
|
|
80
84
|
}
|
|
81
85
|
const snapshot_path = this.getSnapshotPath(model_name);
|
|
@@ -98,11 +102,12 @@ class MakeMigrationsScript {
|
|
|
98
102
|
!diff.columns.removed.length &&
|
|
99
103
|
!Object.keys(diff.columns.modified).length &&
|
|
100
104
|
!diff.indexes.added.length &&
|
|
101
|
-
!diff.indexes.removed.length
|
|
105
|
+
!diff.indexes.removed.length &&
|
|
106
|
+
!diff.indexes.modified.length) {
|
|
102
107
|
this.logger.info("ℹ️ No schema changes detected");
|
|
103
108
|
return false;
|
|
104
109
|
}
|
|
105
|
-
migration_file_created = this.createUpdateSchemaMigrationFile(migration_file_path,
|
|
110
|
+
migration_file_created = this.createUpdateSchemaMigrationFile(migration_file_path, schema_content, previous_snapshot, diff);
|
|
106
111
|
}
|
|
107
112
|
if (migration_file_created) {
|
|
108
113
|
this.logger.success(`✅ Migration file created: ${migration_file_name}`);
|
|
@@ -124,7 +129,9 @@ class MakeMigrationsScript {
|
|
|
124
129
|
main_1.InputValidatorUtil.dirExists(this.schemas_dir, true);
|
|
125
130
|
main_1.InputValidatorUtil.dirExists(this.migrations_dir, true);
|
|
126
131
|
// Fetch all TypeScript schema files
|
|
127
|
-
const schema_files = fs_1.default
|
|
132
|
+
const schema_files = fs_1.default
|
|
133
|
+
.readdirSync(this.schemas_dir)
|
|
134
|
+
.filter((file) => file.endsWith(".ts"));
|
|
128
135
|
if (!schema_files.length) {
|
|
129
136
|
this.logger.info("⚠️ No schema files found.");
|
|
130
137
|
return;
|
|
@@ -4,9 +4,11 @@ declare class MigrationRunnerScript {
|
|
|
4
4
|
private readonly migrations_dir;
|
|
5
5
|
private readonly db_connection;
|
|
6
6
|
private readonly logger;
|
|
7
|
-
private
|
|
7
|
+
private sequelize_instance?;
|
|
8
8
|
constructor();
|
|
9
9
|
private getMigrationFiles;
|
|
10
|
+
private getSequelizeInstance;
|
|
11
|
+
private normalizeTableName;
|
|
10
12
|
private ensureMetaTable;
|
|
11
13
|
private getAppliedMigrations;
|
|
12
14
|
private applyMigration;
|
|
@@ -17,39 +17,63 @@ class MigrationRunnerScript {
|
|
|
17
17
|
sequelize_instance;
|
|
18
18
|
constructor() {
|
|
19
19
|
main_2.InputValidatorUtil.dirExists(this.migrations_dir, true);
|
|
20
|
-
this.sequelize_instance = this.db_connection.connectSync();
|
|
21
20
|
}
|
|
22
21
|
// Fetch all migration files
|
|
23
22
|
getMigrationFiles(schema_name) {
|
|
24
|
-
const files = fs_1.default.readdirSync(this.migrations_dir).filter(
|
|
23
|
+
const files = fs_1.default.readdirSync(this.migrations_dir).filter((file) => {
|
|
24
|
+
if (file.endsWith(".d.ts"))
|
|
25
|
+
return false;
|
|
26
|
+
return file.endsWith(".ts") || file.endsWith(".js");
|
|
27
|
+
});
|
|
25
28
|
if (schema_name) {
|
|
26
|
-
return files.filter(f => f.toLowerCase().includes(schema_name.toLowerCase()));
|
|
29
|
+
return files.filter((f) => f.toLowerCase().includes(schema_name.toLowerCase()));
|
|
27
30
|
}
|
|
28
31
|
return files;
|
|
29
32
|
}
|
|
33
|
+
async getSequelizeInstance() {
|
|
34
|
+
if (!this.sequelize_instance) {
|
|
35
|
+
this.sequelize_instance = await this.db_connection.connect();
|
|
36
|
+
}
|
|
37
|
+
return this.sequelize_instance;
|
|
38
|
+
}
|
|
39
|
+
normalizeTableName(table) {
|
|
40
|
+
if (typeof table === "string")
|
|
41
|
+
return table;
|
|
42
|
+
if (table && typeof table === "object") {
|
|
43
|
+
const table_obj = table;
|
|
44
|
+
return table_obj.tableName ?? table_obj.table_name ?? table_obj.name ?? "";
|
|
45
|
+
}
|
|
46
|
+
return "";
|
|
47
|
+
}
|
|
30
48
|
// Ensure SequelizeMeta table exists
|
|
31
49
|
async ensureMetaTable() {
|
|
32
|
-
const
|
|
33
|
-
const
|
|
50
|
+
const sequelize = await this.getSequelizeInstance();
|
|
51
|
+
const queryInterface = sequelize.getQueryInterface();
|
|
52
|
+
const table_names = (await queryInterface.showAllTables()).map((table) => this.normalizeTableName(table));
|
|
34
53
|
if (!table_names.includes(constants_1.SEQUELIZE_META_TABLE_NAME)) {
|
|
35
54
|
this.logger.info("⏳ Creating SequelizeMeta table...");
|
|
36
55
|
await queryInterface.createTable(constants_1.SEQUELIZE_META_TABLE_NAME, {
|
|
37
56
|
name: {
|
|
38
57
|
type: sequelize_1.DataTypes.STRING,
|
|
39
58
|
allowNull: false,
|
|
40
|
-
primaryKey: true
|
|
41
|
-
}
|
|
59
|
+
primaryKey: true,
|
|
60
|
+
},
|
|
42
61
|
});
|
|
43
62
|
this.logger.success("✅ SequelizeMeta table created.");
|
|
44
63
|
}
|
|
45
64
|
}
|
|
46
65
|
// Fetch already applied migrations
|
|
47
66
|
async getAppliedMigrations() {
|
|
48
|
-
const
|
|
49
|
-
|
|
67
|
+
const sequelize = await this.getSequelizeInstance();
|
|
68
|
+
const queryInterface = sequelize.getQueryInterface();
|
|
69
|
+
const table_name = queryInterface.quoteTable(constants_1.SEQUELIZE_META_TABLE_NAME);
|
|
70
|
+
const column_name = queryInterface.quoteIdentifier("name");
|
|
71
|
+
const results = await sequelize.query(`SELECT ${column_name} FROM ${table_name};`, { type: sequelize_1.QueryTypes.SELECT });
|
|
72
|
+
return results.map((row) => row.name);
|
|
50
73
|
}
|
|
51
74
|
// Apply a single migration
|
|
52
75
|
async applyMigration(file_path, operation) {
|
|
76
|
+
const sequelize = await this.getSequelizeInstance();
|
|
53
77
|
const MigrationClass = require(file_path)?.default;
|
|
54
78
|
if (!MigrationClass) {
|
|
55
79
|
const log_msg = `Migration file has no default export: ${file_path}`;
|
|
@@ -57,20 +81,30 @@ class MigrationRunnerScript {
|
|
|
57
81
|
throw new Error(log_msg);
|
|
58
82
|
}
|
|
59
83
|
const migration_instance = new MigrationClass();
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
await migration_instance.down.bind(migration_instance)(queryInterface, this.sequelize_instance);
|
|
67
|
-
await this.sequelize_instance.getQueryInterface().bulkDelete(constants_1.SEQUELIZE_META_TABLE_NAME, { name: path_1.default.basename(file_path) });
|
|
84
|
+
if (typeof migration_instance[operation] !== "function") {
|
|
85
|
+
const log_msg = `Migration file has no "${operation}" method: ${file_path}`;
|
|
86
|
+
this.logger.error(log_msg);
|
|
87
|
+
throw new Error(log_msg);
|
|
68
88
|
}
|
|
89
|
+
const queryInterface = sequelize.getQueryInterface();
|
|
90
|
+
const migration_name = path_1.default.basename(file_path);
|
|
91
|
+
await sequelize.transaction(async (transaction) => {
|
|
92
|
+
const migration_options = { transaction };
|
|
93
|
+
if (operation === "up") {
|
|
94
|
+
await migration_instance.up.bind(migration_instance)(queryInterface, sequelize, migration_options);
|
|
95
|
+
await queryInterface.bulkInsert(constants_1.SEQUELIZE_META_TABLE_NAME, [{ name: migration_name }], migration_options);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
await migration_instance.down.bind(migration_instance)(queryInterface, sequelize, migration_options);
|
|
99
|
+
await queryInterface.bulkDelete(constants_1.SEQUELIZE_META_TABLE_NAME, { name: migration_name }, migration_options);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
69
102
|
}
|
|
70
103
|
// Main runner
|
|
71
104
|
async run(operation, schema_name, migration_file) {
|
|
72
105
|
this.logger.info(`🏃♂️ Starting Migration process Operation: ${operation.toUpperCase()}, Schema: ${schema_name}, File: ${migration_file || "all"}`);
|
|
73
|
-
await this.
|
|
106
|
+
const sequelize = await this.getSequelizeInstance();
|
|
107
|
+
await sequelize.authenticate();
|
|
74
108
|
this.logger.success("✅ Database connected.");
|
|
75
109
|
await this.ensureMetaTable();
|
|
76
110
|
let files = [];
|
|
@@ -84,20 +118,21 @@ class MigrationRunnerScript {
|
|
|
84
118
|
files = [full_path];
|
|
85
119
|
}
|
|
86
120
|
else {
|
|
87
|
-
files = this.getMigrationFiles(schema_name).map(f => path_1.default.join(this.migrations_dir, f));
|
|
121
|
+
files = this.getMigrationFiles(schema_name).map((f) => path_1.default.join(this.migrations_dir, f));
|
|
88
122
|
}
|
|
89
123
|
// Sort ascending for UP, descending for DOWN
|
|
90
124
|
files.sort((a, b) => {
|
|
91
125
|
const getPriority = (file_path) => {
|
|
92
|
-
const file_name =
|
|
126
|
+
const file_name = path_1.default.basename(file_path);
|
|
93
127
|
const match = file_name.match(/^(\d+)_/);
|
|
94
128
|
return match ? Number(match[1]) : Number.MAX_SAFE_INTEGER;
|
|
95
129
|
};
|
|
96
130
|
const a_priority = getPriority(a);
|
|
97
131
|
const b_priority = getPriority(b);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
132
|
+
const priority_sort = a_priority - b_priority;
|
|
133
|
+
const name_sort = path_1.default.basename(a).localeCompare(path_1.default.basename(b));
|
|
134
|
+
const sort_result = priority_sort || name_sort;
|
|
135
|
+
return operation === "up" ? sort_result : -sort_result;
|
|
101
136
|
});
|
|
102
137
|
const applied_migrations = await this.getAppliedMigrations();
|
|
103
138
|
for (const file of files) {
|
|
@@ -4,9 +4,11 @@ declare class SeederRunnerScript {
|
|
|
4
4
|
private readonly seeders_dir;
|
|
5
5
|
private readonly db_connection;
|
|
6
6
|
private readonly logger;
|
|
7
|
-
private
|
|
7
|
+
private sequelize_instance?;
|
|
8
8
|
constructor();
|
|
9
9
|
private getSeederFiles;
|
|
10
|
+
private getSequelizeInstance;
|
|
11
|
+
private normalizeTableName;
|
|
10
12
|
private ensureMetaTable;
|
|
11
13
|
private getAppliedSeeders;
|
|
12
14
|
private applySeeder;
|
|
@@ -17,20 +17,39 @@ class SeederRunnerScript {
|
|
|
17
17
|
sequelize_instance;
|
|
18
18
|
constructor() {
|
|
19
19
|
main_2.InputValidatorUtil.dirExists(this.seeders_dir, true);
|
|
20
|
-
this.sequelize_instance = this.db_connection.connectSync();
|
|
21
20
|
}
|
|
22
21
|
// Get all seeder files
|
|
23
22
|
getSeederFiles(seeder_name) {
|
|
24
|
-
let files = fs_1.default.readdirSync(this.seeders_dir).filter(
|
|
23
|
+
let files = fs_1.default.readdirSync(this.seeders_dir).filter((file) => {
|
|
24
|
+
if (file.endsWith(".d.ts"))
|
|
25
|
+
return false;
|
|
26
|
+
return file.endsWith(".ts") || file.endsWith(".js");
|
|
27
|
+
});
|
|
25
28
|
if (seeder_name) {
|
|
26
|
-
files = files.filter(f => f.toLowerCase().includes(seeder_name.toLowerCase()));
|
|
29
|
+
files = files.filter((f) => f.toLowerCase().includes(seeder_name.toLowerCase()));
|
|
27
30
|
}
|
|
28
31
|
return files;
|
|
29
32
|
}
|
|
33
|
+
async getSequelizeInstance() {
|
|
34
|
+
if (!this.sequelize_instance) {
|
|
35
|
+
this.sequelize_instance = await this.db_connection.connect();
|
|
36
|
+
}
|
|
37
|
+
return this.sequelize_instance;
|
|
38
|
+
}
|
|
39
|
+
normalizeTableName(table) {
|
|
40
|
+
if (typeof table === "string")
|
|
41
|
+
return table;
|
|
42
|
+
if (table && typeof table === "object") {
|
|
43
|
+
const table_obj = table;
|
|
44
|
+
return table_obj.tableName ?? table_obj.table_name ?? table_obj.name ?? "";
|
|
45
|
+
}
|
|
46
|
+
return "";
|
|
47
|
+
}
|
|
30
48
|
// Ensure SequelizeSeederMeta table exists
|
|
31
49
|
async ensureMetaTable() {
|
|
32
|
-
const
|
|
33
|
-
const
|
|
50
|
+
const sequelize = await this.getSequelizeInstance();
|
|
51
|
+
const queryInterface = sequelize.getQueryInterface();
|
|
52
|
+
const tables = (await queryInterface.showAllTables()).map((table) => this.normalizeTableName(table));
|
|
34
53
|
if (!tables.includes(constants_1.SEQUELIZE_SEEDER_META_TABLE_NAME)) {
|
|
35
54
|
this.logger.info("⏳ Creating Sequelize seeder meta table table...");
|
|
36
55
|
await queryInterface.createTable(constants_1.SEQUELIZE_SEEDER_META_TABLE_NAME, {
|
|
@@ -41,31 +60,44 @@ class SeederRunnerScript {
|
|
|
41
60
|
}
|
|
42
61
|
// Get already applied seeders
|
|
43
62
|
async getAppliedSeeders() {
|
|
44
|
-
const
|
|
45
|
-
|
|
63
|
+
const sequelize = await this.getSequelizeInstance();
|
|
64
|
+
const queryInterface = sequelize.getQueryInterface();
|
|
65
|
+
const table_name = queryInterface.quoteTable(constants_1.SEQUELIZE_SEEDER_META_TABLE_NAME);
|
|
66
|
+
const column_name = queryInterface.quoteIdentifier("name");
|
|
67
|
+
const results = await sequelize.query(`SELECT ${column_name} FROM ${table_name};`, { type: sequelize_1.QueryTypes.SELECT });
|
|
68
|
+
return results.map((row) => row.name);
|
|
46
69
|
}
|
|
47
70
|
// Apply a single seeder
|
|
48
71
|
async applySeeder(file_path, operation) {
|
|
72
|
+
const sequelize = await this.getSequelizeInstance();
|
|
49
73
|
const SeederClass = require(file_path)?.default;
|
|
50
74
|
if (!SeederClass) {
|
|
51
75
|
throw new Error(`Seeder file has no default export: ${file_path}`);
|
|
52
76
|
}
|
|
53
77
|
const seeder_instance = new SeederClass();
|
|
54
|
-
const queryInterface =
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
await seeder_instance.down(queryInterface, this.sequelize_instance);
|
|
61
|
-
await queryInterface.bulkDelete(constants_1.SEQUELIZE_SEEDER_META_TABLE_NAME, { name: path_1.default.basename(file_path) });
|
|
78
|
+
const queryInterface = sequelize.getQueryInterface();
|
|
79
|
+
const seeder_name = path_1.default.basename(file_path);
|
|
80
|
+
if (typeof seeder_instance[operation] !== "function") {
|
|
81
|
+
throw new Error(`Seeder file has no "${operation}" method: ${file_path}`);
|
|
62
82
|
}
|
|
83
|
+
await sequelize.transaction(async (transaction) => {
|
|
84
|
+
const seeder_options = { transaction };
|
|
85
|
+
if (operation === "up") {
|
|
86
|
+
await seeder_instance.up(queryInterface, sequelize, seeder_options);
|
|
87
|
+
await queryInterface.bulkInsert(constants_1.SEQUELIZE_SEEDER_META_TABLE_NAME, [{ name: seeder_name }], seeder_options);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
await seeder_instance.down(queryInterface, sequelize, seeder_options);
|
|
91
|
+
await queryInterface.bulkDelete(constants_1.SEQUELIZE_SEEDER_META_TABLE_NAME, { name: seeder_name }, seeder_options);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
63
94
|
}
|
|
64
95
|
// Main runner
|
|
65
96
|
async run(operation, seeder_name, seeder_file) {
|
|
66
97
|
try {
|
|
67
98
|
this.logger.info(`🏃♂️ Starting seeder process Operation: ${operation.toUpperCase()}, Seeder: ${seeder_name || "all"}, File: ${seeder_file || "none"}`);
|
|
68
|
-
await this.
|
|
99
|
+
const sequelize = await this.getSequelizeInstance();
|
|
100
|
+
await sequelize.authenticate();
|
|
69
101
|
this.logger.success("✅ Database connected.");
|
|
70
102
|
await this.ensureMetaTable();
|
|
71
103
|
let files = [];
|
|
@@ -78,7 +110,7 @@ class SeederRunnerScript {
|
|
|
78
110
|
files = [full_path];
|
|
79
111
|
}
|
|
80
112
|
else {
|
|
81
|
-
files = this.getSeederFiles(seeder_name).map(f => path_1.default.join(this.seeders_dir, f));
|
|
113
|
+
files = this.getSeederFiles(seeder_name).map((f) => path_1.default.join(this.seeders_dir, f));
|
|
82
114
|
}
|
|
83
115
|
// Sort by filename: ascending for UP, descending for DOWN
|
|
84
116
|
files.sort((a, b) => (operation === "up" ? a.localeCompare(b) : b.localeCompare(a)));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare class
|
|
1
|
+
declare class SequelizeModelGeneratorScript {
|
|
2
2
|
private name;
|
|
3
3
|
private readonly schemas_dir;
|
|
4
4
|
private readonly models_dir;
|
|
@@ -8,4 +8,4 @@ declare class SeqeulizeModelGeneratorScript {
|
|
|
8
8
|
private generateModelFile;
|
|
9
9
|
generateModelsFromSchemas(): void;
|
|
10
10
|
}
|
|
11
|
-
export default
|
|
11
|
+
export default SequelizeModelGeneratorScript;
|
|
@@ -8,7 +8,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
8
8
|
const main_1 = require("../../utils/main");
|
|
9
9
|
const constants_1 = require("../../config/constants");
|
|
10
10
|
const sequelize_code_template_1 = require("../../code_templates/sequelize_code_template");
|
|
11
|
-
class
|
|
11
|
+
class SequelizeModelGeneratorScript {
|
|
12
12
|
name = "sequelize_model_generator_script";
|
|
13
13
|
schemas_dir = constants_1.SCHEMAS_DIR;
|
|
14
14
|
models_dir = constants_1.MODELS_DIR;
|
|
@@ -24,7 +24,7 @@ class SeqeulizeModelGeneratorScript {
|
|
|
24
24
|
const imports = sorted_models
|
|
25
25
|
.map((model_obj) => {
|
|
26
26
|
model_names.push(model_obj.name);
|
|
27
|
-
return `import ${model_obj.name} from "./${model_obj.file_name.replace(
|
|
27
|
+
return `import ${model_obj.name} from "./${model_obj.file_name.replace(".ts", "")}";`;
|
|
28
28
|
})
|
|
29
29
|
.join("\n");
|
|
30
30
|
const template = (0, sequelize_code_template_1.SEQUELIZE_MODELS_INDEX_CODE_TEMPLATE)(model_names, imports);
|
|
@@ -64,7 +64,9 @@ class SeqeulizeModelGeneratorScript {
|
|
|
64
64
|
}
|
|
65
65
|
// Loop through all schemas and generate model files
|
|
66
66
|
generateModelsFromSchemas() {
|
|
67
|
-
const schema_files = fs_1.default
|
|
67
|
+
const schema_files = fs_1.default
|
|
68
|
+
.readdirSync(this.schemas_dir)
|
|
69
|
+
.filter((file) => file.endsWith(".ts"));
|
|
68
70
|
if (!schema_files.length) {
|
|
69
71
|
this.logger.info("⚠️ No schema files found.");
|
|
70
72
|
return;
|
|
@@ -96,7 +98,11 @@ class SeqeulizeModelGeneratorScript {
|
|
|
96
98
|
else if (generation_result === "created") {
|
|
97
99
|
created_count++;
|
|
98
100
|
}
|
|
99
|
-
models.push({
|
|
101
|
+
models.push({
|
|
102
|
+
name: schema_content.model_name,
|
|
103
|
+
file_name: model_file_name,
|
|
104
|
+
migration_priority,
|
|
105
|
+
});
|
|
100
106
|
}
|
|
101
107
|
catch (error) {
|
|
102
108
|
this.logger.error(`Failed to load schema: ${schema_file_path}`, { error });
|
|
@@ -111,4 +117,4 @@ class SeqeulizeModelGeneratorScript {
|
|
|
111
117
|
this.logger.success(`❌ Failed: ${failed_count}`);
|
|
112
118
|
}
|
|
113
119
|
}
|
|
114
|
-
exports.default =
|
|
120
|
+
exports.default = SequelizeModelGeneratorScript;
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,8 @@
|
|
|
1
1
|
export * from "./types/main";
|
|
2
|
+
export * from "./utils/main";
|
|
3
|
+
export * from "./database/main";
|
|
4
|
+
export * from "./middle_ware/main";
|
|
5
|
+
export * from "./validators/main";
|
|
6
|
+
export * from "./storage/main";
|
|
7
|
+
export * from "./mailer/main";
|
|
8
|
+
export * from "./rbac/main";
|
package/dist/index.js
CHANGED
|
@@ -15,3 +15,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./types/main"), exports);
|
|
18
|
+
__exportStar(require("./utils/main"), exports);
|
|
19
|
+
__exportStar(require("./database/main"), exports);
|
|
20
|
+
__exportStar(require("./middle_ware/main"), exports);
|
|
21
|
+
__exportStar(require("./validators/main"), exports);
|
|
22
|
+
__exportStar(require("./storage/main"), exports);
|
|
23
|
+
__exportStar(require("./mailer/main"), exports);
|
|
24
|
+
__exportStar(require("./rbac/main"), exports);
|
package/dist/mailer/main.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ import EmailEnqueueGenerator from "./generators/email_enqueue_generator";
|
|
|
2
2
|
import EmailEnqueueProcessor from "./processors/email_enqueue_processor";
|
|
3
3
|
import EmailDeliveryProcessor from "./processors/email_delivery_processor";
|
|
4
4
|
import MailerDataLoaderUtil from "./utils/mailer_data_loader_util";
|
|
5
|
-
export { EmailEnqueueGenerator, EmailEnqueueProcessor, EmailDeliveryProcessor, MailerDataLoaderUtil };
|
|
5
|
+
export { EmailEnqueueGenerator, EmailEnqueueProcessor, EmailDeliveryProcessor, MailerDataLoaderUtil, };
|