@solidxai/core 0.1.11-beta.2 → 0.1.11-beta.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/.claude/settings.local.json +2 -1
- package/dist/controllers/datasource-introspection.controller.d.ts +38 -1
- package/dist/controllers/datasource-introspection.controller.d.ts.map +1 -1
- package/dist/controllers/datasource-introspection.controller.js +38 -0
- package/dist/controllers/datasource-introspection.controller.js.map +1 -1
- package/dist/dtos/datasource-introspection-mapping.dto.d.ts +4 -0
- package/dist/dtos/datasource-introspection-mapping.dto.d.ts.map +1 -1
- package/dist/dtos/datasource-introspection-mapping.dto.js +18 -2
- package/dist/dtos/datasource-introspection-mapping.dto.js.map +1 -1
- package/dist/entities/{legacy-common-with-id.entity.d.ts → legacy-common-with-generated-id.entity.d.ts} +2 -2
- package/dist/entities/legacy-common-with-generated-id.entity.d.ts.map +1 -0
- package/dist/entities/{legacy-common-with-id.entity.js → legacy-common-with-generated-id.entity.js} +4 -4
- package/dist/entities/legacy-common-with-generated-id.entity.js.map +1 -0
- package/dist/entities/{legacy-common.entity.d.ts → legacy-common.entity-with-existing-id.entity.d.ts} +1 -1
- package/dist/entities/legacy-common.entity-with-existing-id.entity.d.ts.map +1 -0
- package/dist/entities/{legacy-common.entity.js → legacy-common.entity-with-existing-id.entity.js} +1 -1
- package/dist/entities/legacy-common.entity-with-existing-id.entity.js.map +1 -0
- package/dist/helpers/model-metadata-helper.service.js +3 -3
- package/dist/helpers/model-metadata-helper.service.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/interfaces/datasource-introspection-provider.interface.d.ts +1 -0
- package/dist/interfaces/datasource-introspection-provider.interface.d.ts.map +1 -1
- package/dist/interfaces/datasource-introspection-provider.interface.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +12 -3
- package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.d.ts.map +1 -1
- package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.js +12 -0
- package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.js.map +1 -1
- package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.d.ts.map +1 -1
- package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.js +2 -0
- package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.js.map +1 -1
- package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.d.ts.map +1 -1
- package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.js +28 -15
- package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.js.map +1 -1
- package/dist/services/datasource-introspection.service.d.ts +52 -2
- package/dist/services/datasource-introspection.service.d.ts.map +1 -1
- package/dist/services/datasource-introspection.service.js +534 -160
- package/dist/services/datasource-introspection.service.js.map +1 -1
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.js +10 -10
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
- package/package.json +1 -1
- package/src/controllers/datasource-introspection.controller.ts +27 -1
- package/src/dtos/datasource-introspection-mapping.dto.ts +10 -0
- package/src/entities/{legacy-common-with-id.entity.ts → legacy-common-with-generated-id.entity.ts} +1 -1
- package/src/helpers/model-metadata-helper.service.ts +1 -1
- package/src/index.ts +2 -2
- package/src/interfaces/datasource-introspection-provider.interface.ts +1 -0
- package/src/seeders/seed-data/solid-core-metadata.json +12 -3
- package/src/services/datasource-introspection/mssql-datasource-introspection-provider.service.ts +12 -0
- package/src/services/datasource-introspection/mysql-datasource-introspection-provider.service.ts +2 -0
- package/src/services/datasource-introspection/postgres-datasource-introspection-provider.service.ts +28 -15
- package/src/services/datasource-introspection.service.ts +626 -136
- package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +2 -2
- package/dist/entities/legacy-common-with-id.entity.d.ts.map +0 -1
- package/dist/entities/legacy-common-with-id.entity.js.map +0 -1
- package/dist/entities/legacy-common.entity.d.ts.map +0 -1
- package/dist/entities/legacy-common.entity.js.map +0 -1
- /package/src/entities/{legacy-common.entity.ts → legacy-common.entity-with-existing-id.entity.ts} +0 -0
|
@@ -50,19 +50,101 @@ const crypto_1 = require("crypto");
|
|
|
50
50
|
const fs = __importStar(require("fs/promises"));
|
|
51
51
|
const path = __importStar(require("path"));
|
|
52
52
|
const lodash_1 = require("lodash");
|
|
53
|
+
const ts_morph_1 = require("ts-morph");
|
|
53
54
|
const legacy_table_type_enum_1 = require("../enums/legacy-table-type.enum");
|
|
55
|
+
const string_helper_1 = require("../helpers/string.helper");
|
|
54
56
|
const module_metadata_helper_service_1 = require("../helpers/module-metadata-helper.service");
|
|
55
57
|
const model_metadata_helper_service_1 = require("../helpers/model-metadata-helper.service");
|
|
56
58
|
const model_metadata_repository_1 = require("../repository/model-metadata.repository");
|
|
57
59
|
const module_metadata_repository_1 = require("../repository/module-metadata.repository");
|
|
58
60
|
const datasource_management_service_1 = require("./datasource-management.service");
|
|
61
|
+
const command_service_1 = require("../helpers/command.service");
|
|
59
62
|
const field_metadata_service_1 = require("./field-metadata.service");
|
|
60
63
|
const model_metadata_service_1 = require("./model-metadata.service");
|
|
64
|
+
const module_metadata_service_1 = require("./module-metadata.service");
|
|
61
65
|
const mssql_datasource_introspection_provider_service_1 = require("./datasource-introspection/mssql-datasource-introspection-provider.service");
|
|
62
66
|
const mysql_datasource_introspection_provider_service_1 = require("./datasource-introspection/mysql-datasource-introspection-provider.service");
|
|
63
67
|
const postgres_datasource_introspection_provider_service_1 = require("./datasource-introspection/postgres-datasource-introspection-provider.service");
|
|
68
|
+
const DATASOURCE_TYPE_FAMILY_ALIASES = {
|
|
69
|
+
boolean: ["bit", "bool", "boolean"],
|
|
70
|
+
bigint: ["bigint"],
|
|
71
|
+
int: ["int", "integer", "smallint", "tinyint"],
|
|
72
|
+
numeric: ["numeric"],
|
|
73
|
+
decimal: ["decimal", "money", "smallmoney"],
|
|
74
|
+
float: ["float", "double", "real"],
|
|
75
|
+
date: ["date"],
|
|
76
|
+
time: ["time", "time without time zone", "time with time zone"],
|
|
77
|
+
datetime: ["datetime", "datetime2", "smalldatetime", "timestamp", "timestamp without time zone"],
|
|
78
|
+
datetimeWithTimezone: ["timestamptz", "timestamp with time zone"],
|
|
79
|
+
json: ["json", "simple-json", "simplejson"],
|
|
80
|
+
jsonb: ["jsonb"],
|
|
81
|
+
uuid: ["uniqueidentifier", "uuid"],
|
|
82
|
+
longText: ["text", "ntext", "longtext", "clob"],
|
|
83
|
+
mediumText: ["mediumtext"],
|
|
84
|
+
shortText: ["varchar", "char", "citext"],
|
|
85
|
+
unicodeShortText: ["nvarchar", "nchar"],
|
|
86
|
+
};
|
|
87
|
+
const ORM_TYPE_BY_DATASOURCE_FAMILY = {
|
|
88
|
+
mssql: {
|
|
89
|
+
boolean: "bit",
|
|
90
|
+
bigint: "bigint",
|
|
91
|
+
int: "int",
|
|
92
|
+
numeric: "numeric",
|
|
93
|
+
decimal: "decimal",
|
|
94
|
+
float: "decimal",
|
|
95
|
+
date: "date",
|
|
96
|
+
time: "time",
|
|
97
|
+
datetime: "datetime",
|
|
98
|
+
datetimeWithTimezone: "datetime",
|
|
99
|
+
json: "simple-json",
|
|
100
|
+
jsonb: "simple-json",
|
|
101
|
+
uuid: "uniqueidentifier",
|
|
102
|
+
longText: "text",
|
|
103
|
+
mediumText: "text",
|
|
104
|
+
shortText: "varchar",
|
|
105
|
+
unicodeShortText: "nvarchar",
|
|
106
|
+
},
|
|
107
|
+
mysql: {
|
|
108
|
+
boolean: "boolean",
|
|
109
|
+
bigint: "int",
|
|
110
|
+
int: "int",
|
|
111
|
+
numeric: "decimal",
|
|
112
|
+
decimal: "decimal",
|
|
113
|
+
float: "double",
|
|
114
|
+
date: "date",
|
|
115
|
+
time: "time",
|
|
116
|
+
datetime: "datetime",
|
|
117
|
+
datetimeWithTimezone: "datetime",
|
|
118
|
+
json: "json",
|
|
119
|
+
jsonb: "json",
|
|
120
|
+
uuid: "varchar",
|
|
121
|
+
longText: "longtext",
|
|
122
|
+
mediumText: "mediumtext",
|
|
123
|
+
shortText: "varchar",
|
|
124
|
+
unicodeShortText: "varchar",
|
|
125
|
+
},
|
|
126
|
+
postgres: {
|
|
127
|
+
boolean: "boolean",
|
|
128
|
+
bigint: "bigint",
|
|
129
|
+
int: "integer",
|
|
130
|
+
numeric: "decimal",
|
|
131
|
+
decimal: "decimal",
|
|
132
|
+
float: "decimal",
|
|
133
|
+
date: "date",
|
|
134
|
+
time: "time",
|
|
135
|
+
datetime: "timestamp",
|
|
136
|
+
datetimeWithTimezone: "timestamptz",
|
|
137
|
+
json: "json",
|
|
138
|
+
jsonb: "jsonb",
|
|
139
|
+
uuid: "uuid",
|
|
140
|
+
longText: "text",
|
|
141
|
+
mediumText: "text",
|
|
142
|
+
shortText: "varchar",
|
|
143
|
+
unicodeShortText: "varchar",
|
|
144
|
+
},
|
|
145
|
+
};
|
|
64
146
|
let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
65
|
-
constructor(moduleRef, datasourceManagementService, moduleMetadataRepository, modelMetadataRepository, moduleMetadataHelperService, modelMetadataHelperService, fieldMetadataService, modelMetadataService, mssqlProvider, mysqlProvider, postgresProvider) {
|
|
147
|
+
constructor(moduleRef, datasourceManagementService, moduleMetadataRepository, modelMetadataRepository, moduleMetadataHelperService, modelMetadataHelperService, fieldMetadataService, modelMetadataService, moduleMetadataService, commandService, mssqlProvider, mysqlProvider, postgresProvider) {
|
|
66
148
|
this.moduleRef = moduleRef;
|
|
67
149
|
this.datasourceManagementService = datasourceManagementService;
|
|
68
150
|
this.moduleMetadataRepository = moduleMetadataRepository;
|
|
@@ -71,6 +153,8 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
71
153
|
this.modelMetadataHelperService = modelMetadataHelperService;
|
|
72
154
|
this.fieldMetadataService = fieldMetadataService;
|
|
73
155
|
this.modelMetadataService = modelMetadataService;
|
|
156
|
+
this.moduleMetadataService = moduleMetadataService;
|
|
157
|
+
this.commandService = commandService;
|
|
74
158
|
this.mssqlProvider = mssqlProvider;
|
|
75
159
|
this.mysqlProvider = mysqlProvider;
|
|
76
160
|
this.postgresProvider = postgresProvider;
|
|
@@ -189,24 +273,98 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
189
273
|
const persistedModel = plan.operation === "update" && mappingDto.modelId
|
|
190
274
|
? await this.modelMetadataService.update(mappingDto.modelId, plan.modelPayload)
|
|
191
275
|
: await this.modelMetadataService.create(plan.modelPayload);
|
|
276
|
+
const persistedModelId = mappingDto.modelId ?? persistedModel?.id ?? null;
|
|
277
|
+
return {
|
|
278
|
+
data: {
|
|
279
|
+
modelId: persistedModelId,
|
|
280
|
+
operation: plan.operation,
|
|
281
|
+
metadataJson: plan.metadataJson,
|
|
282
|
+
summary: plan.summary,
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
async createMigrationArtifacts(moduleId, mappingDto) {
|
|
287
|
+
const plan = await this.buildMappingPreview(moduleId, mappingDto);
|
|
288
|
+
const module = await this.loadModule(moduleId);
|
|
289
|
+
const datasource = this.requireDatasource(mappingDto.dataSource);
|
|
290
|
+
if (!mappingDto.modelId) {
|
|
291
|
+
throw new common_1.BadRequestException("Persist the model mapping first so the generated entity can be registered before creating migration artifacts.");
|
|
292
|
+
}
|
|
192
293
|
if (plan.migration.willGenerate && plan.migration.content && plan.migration.filePath) {
|
|
193
294
|
await fs.mkdir(path.dirname(plan.migration.filePath), { recursive: true });
|
|
194
295
|
await fs.writeFile(plan.migration.filePath, plan.migration.content, "utf8");
|
|
195
296
|
}
|
|
196
|
-
const
|
|
297
|
+
const datasourceFile = await this.syncTypeormDatasourceFile(module.name, datasource, plan.modelPayload.singularName);
|
|
197
298
|
return {
|
|
198
299
|
data: {
|
|
199
|
-
modelId:
|
|
300
|
+
modelId: mappingDto.modelId,
|
|
200
301
|
operation: plan.operation,
|
|
201
|
-
metadataJson: plan.metadataJson,
|
|
202
302
|
migration: {
|
|
203
303
|
...plan.migration,
|
|
204
304
|
written: Boolean(plan.migration.willGenerate && plan.migration.filePath),
|
|
205
305
|
},
|
|
306
|
+
datasourceFile,
|
|
206
307
|
summary: plan.summary,
|
|
207
308
|
},
|
|
208
309
|
};
|
|
209
310
|
}
|
|
311
|
+
async generateCode(moduleId) {
|
|
312
|
+
await this.loadModule(moduleId);
|
|
313
|
+
const output = await this.moduleMetadataService.generateCodeViaCtl(moduleId);
|
|
314
|
+
return {
|
|
315
|
+
data: {
|
|
316
|
+
moduleId,
|
|
317
|
+
output,
|
|
318
|
+
message: "Module code generation completed.",
|
|
319
|
+
},
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
async runMigration(moduleId, datasourceName) {
|
|
323
|
+
const module = await this.loadModule(moduleId);
|
|
324
|
+
const datasource = this.requireDatasource(datasourceName);
|
|
325
|
+
const cwd = path.join(process.cwd(), "..");
|
|
326
|
+
const outputs = [];
|
|
327
|
+
const migrationOutput = await this.commandService.executeCommandWithArgs({
|
|
328
|
+
command: "npx",
|
|
329
|
+
args: ["-y", "@solidxai/solidctl@latest", "migration", "-d", datasource.name, "run"],
|
|
330
|
+
cwd,
|
|
331
|
+
});
|
|
332
|
+
outputs.push([
|
|
333
|
+
`npx @solidxai/solidctl@latest migration -d ${datasource.name} run`,
|
|
334
|
+
migrationOutput,
|
|
335
|
+
].filter(Boolean).join("\n"));
|
|
336
|
+
const buildOutput = await this.commandService.executeCommandWithArgs({
|
|
337
|
+
command: "npx",
|
|
338
|
+
args: ["-y", "@solidxai/solidctl@latest", "build"],
|
|
339
|
+
cwd,
|
|
340
|
+
});
|
|
341
|
+
outputs.push([
|
|
342
|
+
"npx @solidxai/solidctl@latest build",
|
|
343
|
+
buildOutput,
|
|
344
|
+
].filter(Boolean).join("\n"));
|
|
345
|
+
const seedOutput = await this.commandService.executeCommandWithArgs({
|
|
346
|
+
command: "npx",
|
|
347
|
+
args: ["-y", "@solidxai/solidctl@latest", "seed", "--modules-to-seed", module.name],
|
|
348
|
+
cwd,
|
|
349
|
+
});
|
|
350
|
+
outputs.push([
|
|
351
|
+
`npx @solidxai/solidctl@latest seed --modules-to-seed ${module.name}`,
|
|
352
|
+
seedOutput,
|
|
353
|
+
].filter(Boolean).join("\n"));
|
|
354
|
+
return {
|
|
355
|
+
data: {
|
|
356
|
+
moduleId,
|
|
357
|
+
datasource: datasource.name,
|
|
358
|
+
output: outputs.join("\n\n"),
|
|
359
|
+
command: [
|
|
360
|
+
`npx @solidxai/solidctl@latest migration -d ${datasource.name} run`,
|
|
361
|
+
"npx @solidxai/solidctl@latest build",
|
|
362
|
+
`npx @solidxai/solidctl@latest seed --modules-to-seed ${module.name}`,
|
|
363
|
+
].join("\n"),
|
|
364
|
+
message: `Migration, build, and seed completed successfully for datasource "${datasource.name}".`,
|
|
365
|
+
},
|
|
366
|
+
};
|
|
367
|
+
}
|
|
210
368
|
async buildMappingPreview(moduleId, mappingDto) {
|
|
211
369
|
const module = await this.loadModule(moduleId);
|
|
212
370
|
const datasource = this.requireDatasource(mappingDto.dataSource);
|
|
@@ -252,6 +410,13 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
252
410
|
mappedModelId: mappingDto.modelId ?? null,
|
|
253
411
|
metadataJson,
|
|
254
412
|
migration,
|
|
413
|
+
datasourceFile: {
|
|
414
|
+
filePath: path.resolve(process.cwd(), "src", `typeorm-${datasource.name}-datasource.ts`),
|
|
415
|
+
created: false,
|
|
416
|
+
updated: false,
|
|
417
|
+
entityRegistered: false,
|
|
418
|
+
migrationGlobRegistered: false,
|
|
419
|
+
},
|
|
255
420
|
summary: {
|
|
256
421
|
includedColumnNames,
|
|
257
422
|
removedColumnNames,
|
|
@@ -584,7 +749,7 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
584
749
|
...preserved,
|
|
585
750
|
...(column.fieldId ? { id: column.fieldId } : {}),
|
|
586
751
|
name: column.fieldName,
|
|
587
|
-
displayName: preserved.displayName
|
|
752
|
+
displayName: column.displayName?.trim() || preserved.displayName || (0, lodash_1.startCase)(column.fieldName),
|
|
588
753
|
description: preserved.description ?? "",
|
|
589
754
|
type: column.solidFieldType,
|
|
590
755
|
ormType: column.ormType,
|
|
@@ -696,23 +861,19 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
696
861
|
const generatedIdUniqueName = this.buildMigrationObjectName("UQ", tableNameLiteral, "ss_id");
|
|
697
862
|
const upColumnStatements = missingSystemColumns.map((definition) => {
|
|
698
863
|
const columnLiteral = this.renderTableColumnLiteral(definition);
|
|
699
|
-
return
|
|
700
|
-
`
|
|
701
|
-
` await queryRunner.addColumn(tableName, new TableColumn(${columnLiteral}));`,
|
|
702
|
-
" }",
|
|
703
|
-
].join("\n");
|
|
864
|
+
return ` if (!(await queryRunner.hasColumn(tableName, ${JSON.stringify(definition.columnName)})))\n`
|
|
865
|
+
+ ` await queryRunner.addColumn(tableName, new TableColumn(${columnLiteral}));`;
|
|
704
866
|
}).join("\n\n");
|
|
705
867
|
const postUpStatements = [];
|
|
706
868
|
if (missingSystemColumns.some((definition) => definition.columnName === "ss_deleted_at")) {
|
|
707
869
|
postUpStatements.push([
|
|
708
870
|
" {",
|
|
709
871
|
" const table = await queryRunner.getTable(tableName);",
|
|
710
|
-
` if (table && !table.indices.some((index) => index.name === ${JSON.stringify(deletedAtIndexName)}))
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
" }",
|
|
872
|
+
` if (table && !table.indices.some((index) => index.name === ${JSON.stringify(deletedAtIndexName)}))`,
|
|
873
|
+
` await queryRunner.createIndex(tableName, new TableIndex(${this.renderTableIndexLiteral({
|
|
874
|
+
name: deletedAtIndexName,
|
|
875
|
+
columnNames: ["ss_deleted_at"],
|
|
876
|
+
})}));`,
|
|
716
877
|
" }",
|
|
717
878
|
].join("\n"));
|
|
718
879
|
}
|
|
@@ -720,13 +881,12 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
720
881
|
postUpStatements.push([
|
|
721
882
|
" {",
|
|
722
883
|
" const table = await queryRunner.getTable(tableName);",
|
|
723
|
-
` if (table && !table.indices.some((index) => index.name === ${JSON.stringify(generatedIdUniqueName)}))
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
" }",
|
|
884
|
+
` if (table && !table.indices.some((index) => index.name === ${JSON.stringify(generatedIdUniqueName)}))`,
|
|
885
|
+
` await queryRunner.createIndex(tableName, new TableIndex(${this.renderTableIndexLiteral({
|
|
886
|
+
name: generatedIdUniqueName,
|
|
887
|
+
columnNames: ["ss_id"],
|
|
888
|
+
isUnique: true,
|
|
889
|
+
})}));`,
|
|
730
890
|
" }",
|
|
731
891
|
].join("\n"));
|
|
732
892
|
}
|
|
@@ -736,9 +896,8 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
736
896
|
" {",
|
|
737
897
|
" const table = await queryRunner.getTable(tableName);",
|
|
738
898
|
` const index = table?.indices.find((entry) => entry.name === ${JSON.stringify(generatedIdUniqueName)});`,
|
|
739
|
-
" if (index)
|
|
899
|
+
" if (index)",
|
|
740
900
|
" await queryRunner.dropIndex(tableName, index);",
|
|
741
|
-
" }",
|
|
742
901
|
" }",
|
|
743
902
|
].join("\n"));
|
|
744
903
|
}
|
|
@@ -747,20 +906,16 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
747
906
|
" {",
|
|
748
907
|
" const table = await queryRunner.getTable(tableName);",
|
|
749
908
|
` const index = table?.indices.find((entry) => entry.name === ${JSON.stringify(deletedAtIndexName)});`,
|
|
750
|
-
" if (index)
|
|
909
|
+
" if (index)",
|
|
751
910
|
" await queryRunner.dropIndex(tableName, index);",
|
|
752
|
-
" }",
|
|
753
911
|
" }",
|
|
754
912
|
].join("\n"));
|
|
755
913
|
}
|
|
756
914
|
downStatements.push(...missingSystemColumns
|
|
757
915
|
.slice()
|
|
758
916
|
.reverse()
|
|
759
|
-
.map((definition) =>
|
|
760
|
-
`
|
|
761
|
-
` await queryRunner.dropColumn(tableName, ${JSON.stringify(definition.columnName)});`,
|
|
762
|
-
" }",
|
|
763
|
-
].join("\n")));
|
|
917
|
+
.map((definition) => ` if (await queryRunner.hasColumn(tableName, ${JSON.stringify(definition.columnName)}))\n`
|
|
918
|
+
+ ` await queryRunner.dropColumn(tableName, ${JSON.stringify(definition.columnName)});`));
|
|
764
919
|
return [
|
|
765
920
|
"import { MigrationInterface, QueryRunner, TableColumn, TableIndex } from \"typeorm\";",
|
|
766
921
|
"",
|
|
@@ -783,27 +938,36 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
783
938
|
}
|
|
784
939
|
renderTableColumnLiteral(definition) {
|
|
785
940
|
const properties = [
|
|
786
|
-
`
|
|
787
|
-
`
|
|
941
|
+
`name: ${JSON.stringify(definition.columnName)}`,
|
|
942
|
+
`type: ${JSON.stringify(definition.type)}`,
|
|
788
943
|
];
|
|
789
944
|
if (definition.length) {
|
|
790
|
-
properties.push(`
|
|
945
|
+
properties.push(`length: ${JSON.stringify(definition.length)}`);
|
|
791
946
|
}
|
|
792
947
|
if (typeof definition.isNullable === "boolean") {
|
|
793
|
-
properties.push(`
|
|
948
|
+
properties.push(`isNullable: ${definition.isNullable}`);
|
|
794
949
|
}
|
|
795
950
|
if (definition.defaultExpression) {
|
|
796
|
-
properties.push(`
|
|
951
|
+
properties.push(`default: ${JSON.stringify(definition.defaultExpression)}`);
|
|
797
952
|
}
|
|
798
953
|
if (definition.isGenerated) {
|
|
799
|
-
properties.push("
|
|
800
|
-
properties.push("
|
|
954
|
+
properties.push("isGenerated: true");
|
|
955
|
+
properties.push("generationStrategy: \"increment\"");
|
|
956
|
+
}
|
|
957
|
+
if (definition.isUnique) {
|
|
958
|
+
properties.push("isUnique: true");
|
|
801
959
|
}
|
|
960
|
+
return `{ ${properties.join(", ")}, }`;
|
|
961
|
+
}
|
|
962
|
+
renderTableIndexLiteral(definition) {
|
|
963
|
+
const properties = [
|
|
964
|
+
`name: ${JSON.stringify(definition.name)}`,
|
|
965
|
+
`columnNames: ${JSON.stringify(definition.columnNames)}`,
|
|
966
|
+
];
|
|
802
967
|
if (definition.isUnique) {
|
|
803
|
-
properties.push("
|
|
968
|
+
properties.push("isUnique: true");
|
|
804
969
|
}
|
|
805
|
-
properties.
|
|
806
|
-
return properties.join("\n");
|
|
970
|
+
return `{ ${properties.join(", ")}, }`;
|
|
807
971
|
}
|
|
808
972
|
buildMigrationObjectName(prefix, tableName, columnName) {
|
|
809
973
|
const hash = (0, crypto_1.createHash)("md5").update(`${tableName}:${columnName}:${prefix}`).digest("hex").slice(0, 24);
|
|
@@ -832,12 +996,14 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
832
996
|
async buildTableInventory(datasource) {
|
|
833
997
|
const provider = this.getProvider(datasource.type);
|
|
834
998
|
const runtimeDataSource = this.resolveDataSourceByName(datasource.name);
|
|
835
|
-
const [
|
|
999
|
+
const [rawTables, rawColumns, models] = await Promise.all([
|
|
836
1000
|
provider.listTables(runtimeDataSource),
|
|
837
1001
|
provider.listColumns(runtimeDataSource),
|
|
838
1002
|
this.modelMetadataRepository.find({ relations: { module: true } }),
|
|
839
1003
|
]);
|
|
840
|
-
const
|
|
1004
|
+
const tables = rawTables.filter((table) => !this.isSolidxInternalTableName(table.tableName));
|
|
1005
|
+
const columns = rawColumns.filter((column) => !this.isSolidxInternalTableName(column.tableName));
|
|
1006
|
+
const modelLookup = this.buildModelLookup(models);
|
|
841
1007
|
const columnsByKey = this.groupColumnsByTable(columns);
|
|
842
1008
|
const tableKeys = new Set();
|
|
843
1009
|
for (const table of tables) {
|
|
@@ -857,7 +1023,7 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
857
1023
|
}
|
|
858
1024
|
const suggestedLegacyTableType = this.detectLegacyTableType(datasource.type, tableColumns);
|
|
859
1025
|
const suggestedIdColumn = this.getSuggestedIdColumn(datasource.type, tableColumns, suggestedLegacyTableType);
|
|
860
|
-
const mappedModel =
|
|
1026
|
+
const mappedModel = this.resolveMappedModel(modelLookup, datasource.name, tableName);
|
|
861
1027
|
const physicalColumns = tableColumns.filter((column) => !this.isHandledBySuperclass(column.columnName, suggestedLegacyTableType));
|
|
862
1028
|
return {
|
|
863
1029
|
schema,
|
|
@@ -892,16 +1058,37 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
892
1058
|
columnsByKey,
|
|
893
1059
|
};
|
|
894
1060
|
}
|
|
895
|
-
|
|
896
|
-
const
|
|
1061
|
+
buildModelLookup(models) {
|
|
1062
|
+
const byDatasourceAndTable = new Map();
|
|
1063
|
+
const byTableName = new Map();
|
|
897
1064
|
for (const model of models) {
|
|
898
1065
|
if (!model.tableName) {
|
|
899
1066
|
continue;
|
|
900
1067
|
}
|
|
901
|
-
|
|
902
|
-
|
|
1068
|
+
byDatasourceAndTable.set(this.toModelMapKey(model.dataSource, model.tableName), model);
|
|
1069
|
+
const normalizedTableName = model.tableName.trim().toLowerCase();
|
|
1070
|
+
const bucket = byTableName.get(normalizedTableName);
|
|
1071
|
+
if (bucket) {
|
|
1072
|
+
bucket.push(model);
|
|
1073
|
+
continue;
|
|
1074
|
+
}
|
|
1075
|
+
byTableName.set(normalizedTableName, [model]);
|
|
1076
|
+
}
|
|
1077
|
+
return {
|
|
1078
|
+
byDatasourceAndTable,
|
|
1079
|
+
byTableName,
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
resolveMappedModel(lookup, datasourceName, tableName) {
|
|
1083
|
+
const exactMatch = lookup.byDatasourceAndTable.get(this.toModelMapKey(datasourceName, tableName));
|
|
1084
|
+
if (exactMatch) {
|
|
1085
|
+
return exactMatch;
|
|
1086
|
+
}
|
|
1087
|
+
const fallbackMatches = lookup.byTableName.get(tableName.trim().toLowerCase()) ?? [];
|
|
1088
|
+
if (fallbackMatches.length === 1) {
|
|
1089
|
+
return fallbackMatches[0];
|
|
903
1090
|
}
|
|
904
|
-
return
|
|
1091
|
+
return fallbackMatches[0] ?? null;
|
|
905
1092
|
}
|
|
906
1093
|
groupColumnsByTable(columns) {
|
|
907
1094
|
const grouped = new Map();
|
|
@@ -916,6 +1103,9 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
916
1103
|
}
|
|
917
1104
|
return grouped;
|
|
918
1105
|
}
|
|
1106
|
+
isSolidxInternalTableName(tableName) {
|
|
1107
|
+
return typeof tableName === "string" && tableName.toLowerCase().startsWith("ss_");
|
|
1108
|
+
}
|
|
919
1109
|
detectLegacyTableType(datasourceType, columns) {
|
|
920
1110
|
const normalizedDatasourceType = datasourceType.toLowerCase();
|
|
921
1111
|
const hasExistingGeneratedId = columns.some((column) => column.isAutoGenerated);
|
|
@@ -983,12 +1173,16 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
983
1173
|
}
|
|
984
1174
|
toDetailColumnRecord(column, legacyTableType, datasourceType) {
|
|
985
1175
|
const superclassFieldName = this.getSuperclassFieldName(column.columnName, legacyTableType);
|
|
1176
|
+
const normalizedColumnName = column.columnName.toLowerCase();
|
|
986
1177
|
const fieldName = legacyTableType === legacy_table_type_enum_1.LegacyTableType.EXISTING_ID && column.isAutoGenerated
|
|
987
1178
|
? "id"
|
|
988
|
-
:
|
|
1179
|
+
: legacyTableType === legacy_table_type_enum_1.LegacyTableType.GENERATED_ID && normalizedColumnName === "id"
|
|
1180
|
+
? "legacyId"
|
|
1181
|
+
: this.toFieldName(column.columnName);
|
|
989
1182
|
return {
|
|
990
1183
|
columnName: column.columnName,
|
|
991
1184
|
fieldName,
|
|
1185
|
+
displayName: (0, lodash_1.startCase)(fieldName),
|
|
992
1186
|
dataType: column.dataType,
|
|
993
1187
|
solidFieldType: this.toSolidFieldType(column),
|
|
994
1188
|
ormType: this.toOrmFieldType(column, datasourceType),
|
|
@@ -999,6 +1193,7 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
999
1193
|
numericScale: column.numericScale,
|
|
1000
1194
|
ordinalPosition: column.ordinalPosition,
|
|
1001
1195
|
isAutoGenerated: column.isAutoGenerated,
|
|
1196
|
+
isPrimaryKey: column.isPrimaryKey,
|
|
1002
1197
|
handledBySuperclass: Boolean(superclassFieldName),
|
|
1003
1198
|
superclassFieldName,
|
|
1004
1199
|
};
|
|
@@ -1033,127 +1228,70 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
1033
1228
|
}
|
|
1034
1229
|
return "LegacyCommonEntityWithExistingId";
|
|
1035
1230
|
}
|
|
1036
|
-
|
|
1037
|
-
const normalized =
|
|
1038
|
-
const
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
if (["bigint"].includes(normalized)) {
|
|
1043
|
-
return "bigint";
|
|
1044
|
-
}
|
|
1045
|
-
if (["int", "integer", "smallint", "tinyint"].includes(normalized)) {
|
|
1046
|
-
return "int";
|
|
1047
|
-
}
|
|
1048
|
-
if (["numeric", "decimal", "float", "double", "real", "money", "smallmoney"].includes(normalized)) {
|
|
1049
|
-
return "decimal";
|
|
1050
|
-
}
|
|
1051
|
-
if (["date"].includes(normalized)) {
|
|
1052
|
-
return "date";
|
|
1053
|
-
}
|
|
1054
|
-
if (["time"].includes(normalized)) {
|
|
1055
|
-
return "time";
|
|
1056
|
-
}
|
|
1057
|
-
if (["datetime", "datetime2", "timestamp", "timestamptz", "smalldatetime"].includes(normalized) || normalized.includes("date")) {
|
|
1058
|
-
return "datetime";
|
|
1231
|
+
getDatasourceTypeFamily(dataType) {
|
|
1232
|
+
const normalized = dataType.toLowerCase();
|
|
1233
|
+
for (const [family, aliases] of Object.entries(DATASOURCE_TYPE_FAMILY_ALIASES)) {
|
|
1234
|
+
if (aliases.includes(normalized)) {
|
|
1235
|
+
return family;
|
|
1236
|
+
}
|
|
1059
1237
|
}
|
|
1060
|
-
if (
|
|
1238
|
+
if (normalized.includes("json")) {
|
|
1061
1239
|
return "json";
|
|
1062
1240
|
}
|
|
1063
|
-
if (
|
|
1064
|
-
return "
|
|
1065
|
-
}
|
|
1066
|
-
if (["text", "ntext", "mediumtext", "longtext", "clob"].includes(normalized)) {
|
|
1067
|
-
return "longText";
|
|
1068
|
-
}
|
|
1069
|
-
if (["varchar", "nvarchar", "char", "nchar", "citext"].includes(normalized)) {
|
|
1070
|
-
if (charLength !== null && charLength > 255) {
|
|
1071
|
-
return "longText";
|
|
1072
|
-
}
|
|
1073
|
-
return "shortText";
|
|
1241
|
+
if (normalized.includes("date")) {
|
|
1242
|
+
return "datetime";
|
|
1074
1243
|
}
|
|
1075
|
-
return
|
|
1244
|
+
return null;
|
|
1076
1245
|
}
|
|
1077
|
-
|
|
1078
|
-
const
|
|
1079
|
-
const
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
return "
|
|
1083
|
-
|
|
1246
|
+
toSolidFieldType(column) {
|
|
1247
|
+
const family = this.getDatasourceTypeFamily(column.dataType);
|
|
1248
|
+
const charLength = column.characterMaximumLength ?? null;
|
|
1249
|
+
switch (family) {
|
|
1250
|
+
case "boolean":
|
|
1251
|
+
return "boolean";
|
|
1252
|
+
case "bigint":
|
|
1084
1253
|
return "bigint";
|
|
1085
|
-
|
|
1086
|
-
return "int";
|
|
1087
|
-
if (["numeric"].includes(normalized))
|
|
1088
|
-
return "numeric";
|
|
1089
|
-
if (["decimal", "float", "double", "real", "money", "smallmoney"].includes(normalized))
|
|
1090
|
-
return "decimal";
|
|
1091
|
-
if (["date"].includes(normalized))
|
|
1092
|
-
return "date";
|
|
1093
|
-
if (["time"].includes(normalized))
|
|
1094
|
-
return "time";
|
|
1095
|
-
if (["datetime2"].includes(normalized))
|
|
1096
|
-
return "datetime2";
|
|
1097
|
-
if (["datetime", "smalldatetime", "timestamp"].includes(normalized) || normalized.includes("date"))
|
|
1098
|
-
return "datetime";
|
|
1099
|
-
if (["json", "jsonb", "simple-json", "simplejson"].includes(normalized) || normalized.includes("json"))
|
|
1100
|
-
return "simple-json";
|
|
1101
|
-
if (["uniqueidentifier", "uuid"].includes(normalized))
|
|
1102
|
-
return "uniqueidentifier";
|
|
1103
|
-
if (["text", "ntext", "mediumtext", "longtext", "clob"].includes(normalized))
|
|
1104
|
-
return "text";
|
|
1105
|
-
if (["nvarchar", "nchar"].includes(normalized))
|
|
1106
|
-
return "nvarchar";
|
|
1107
|
-
return "varchar";
|
|
1108
|
-
}
|
|
1109
|
-
if (normalizedDatasourceType === "mysql") {
|
|
1110
|
-
if (["bigint"].includes(normalized))
|
|
1111
|
-
return "int";
|
|
1112
|
-
if (["int", "integer", "smallint", "tinyint"].includes(normalized))
|
|
1254
|
+
case "int":
|
|
1113
1255
|
return "int";
|
|
1114
|
-
|
|
1256
|
+
case "numeric":
|
|
1257
|
+
case "decimal":
|
|
1258
|
+
case "float":
|
|
1115
1259
|
return "decimal";
|
|
1116
|
-
|
|
1117
|
-
return "double";
|
|
1118
|
-
if (["bit", "bool", "boolean"].includes(normalized))
|
|
1119
|
-
return "boolean";
|
|
1120
|
-
if (["date"].includes(normalized))
|
|
1260
|
+
case "date":
|
|
1121
1261
|
return "date";
|
|
1122
|
-
|
|
1262
|
+
case "time":
|
|
1123
1263
|
return "time";
|
|
1124
|
-
|
|
1264
|
+
case "datetime":
|
|
1265
|
+
case "datetimeWithTimezone":
|
|
1125
1266
|
return "datetime";
|
|
1126
|
-
|
|
1267
|
+
case "json":
|
|
1268
|
+
case "jsonb":
|
|
1127
1269
|
return "json";
|
|
1128
|
-
|
|
1129
|
-
return "
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
return "json";
|
|
1154
|
-
if (["text", "ntext", "mediumtext", "longtext", "clob"].includes(normalized))
|
|
1155
|
-
return "text";
|
|
1156
|
-
return "varchar";
|
|
1270
|
+
case "uuid":
|
|
1271
|
+
return "uuid";
|
|
1272
|
+
case "mediumText":
|
|
1273
|
+
case "longText":
|
|
1274
|
+
return "longText";
|
|
1275
|
+
case "shortText":
|
|
1276
|
+
case "unicodeShortText":
|
|
1277
|
+
if (charLength !== null && charLength > 255) {
|
|
1278
|
+
return "longText";
|
|
1279
|
+
}
|
|
1280
|
+
return "shortText";
|
|
1281
|
+
default:
|
|
1282
|
+
return "shortText";
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
toOrmFieldType(column, datasourceType) {
|
|
1286
|
+
const family = this.getDatasourceTypeFamily(column.dataType);
|
|
1287
|
+
const normalizedDatasourceType = datasourceType.toLowerCase();
|
|
1288
|
+
const ormType = family
|
|
1289
|
+
? ORM_TYPE_BY_DATASOURCE_FAMILY[normalizedDatasourceType]?.[family]
|
|
1290
|
+
: undefined;
|
|
1291
|
+
if (ormType) {
|
|
1292
|
+
return ormType;
|
|
1293
|
+
}
|
|
1294
|
+
return normalizedDatasourceType === "postgres" ? "varchar" : "varchar";
|
|
1157
1295
|
}
|
|
1158
1296
|
toFieldName(columnName) {
|
|
1159
1297
|
return (0, lodash_1.camelCase)(columnName.replace(/^ss_/, ""));
|
|
@@ -1190,6 +1328,240 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
1190
1328
|
toModelMapKey(datasourceName, tableName) {
|
|
1191
1329
|
return `${datasourceName.toLowerCase()}::${tableName.toLowerCase()}`;
|
|
1192
1330
|
}
|
|
1331
|
+
async syncTypeormDatasourceFile(moduleName, datasource, singularName) {
|
|
1332
|
+
const datasourceFilePath = path.resolve(process.cwd(), "src", `typeorm-${datasource.name}-datasource.ts`);
|
|
1333
|
+
const entityClassName = (0, string_helper_1.classify)(singularName);
|
|
1334
|
+
const entityImportPath = `./${moduleName}/entities/${(0, lodash_1.kebabCase)(singularName)}.entity`;
|
|
1335
|
+
const migrationGlob = `join(__dirname, './${moduleName}/migrations/${datasource.name}/*.{ts,js}')`;
|
|
1336
|
+
const existingContent = await fs.readFile(datasourceFilePath, "utf8").catch(() => null);
|
|
1337
|
+
if (!existingContent) {
|
|
1338
|
+
const rendered = this.renderTypeormDatasourceTemplate({
|
|
1339
|
+
datasource,
|
|
1340
|
+
entityClassName,
|
|
1341
|
+
entityImportPath,
|
|
1342
|
+
migrationGlob,
|
|
1343
|
+
});
|
|
1344
|
+
await fs.writeFile(datasourceFilePath, rendered, "utf8");
|
|
1345
|
+
return {
|
|
1346
|
+
filePath: datasourceFilePath,
|
|
1347
|
+
created: true,
|
|
1348
|
+
updated: false,
|
|
1349
|
+
entityRegistered: true,
|
|
1350
|
+
migrationGlobRegistered: true,
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
const project = new ts_morph_1.Project({
|
|
1354
|
+
skipAddingFilesFromTsConfig: true,
|
|
1355
|
+
manipulationSettings: {
|
|
1356
|
+
quoteKind: ts_morph_1.QuoteKind.Single,
|
|
1357
|
+
indentationText: ts_morph_1.IndentationText.FourSpaces,
|
|
1358
|
+
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
|
1359
|
+
},
|
|
1360
|
+
});
|
|
1361
|
+
const sourceFile = project.createSourceFile(datasourceFilePath, existingContent, { overwrite: true });
|
|
1362
|
+
const entityImportDeclaration = sourceFile.getImportDeclarations().find((declaration) => declaration.getModuleSpecifierValue() === entityImportPath);
|
|
1363
|
+
if (entityImportDeclaration) {
|
|
1364
|
+
const alreadyImported = entityImportDeclaration.getNamedImports().some((namedImport) => namedImport.getName() === entityClassName);
|
|
1365
|
+
if (!alreadyImported) {
|
|
1366
|
+
entityImportDeclaration.addNamedImport(entityClassName);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
else {
|
|
1370
|
+
sourceFile.addImportDeclaration({
|
|
1371
|
+
moduleSpecifier: entityImportPath,
|
|
1372
|
+
namedImports: [entityClassName],
|
|
1373
|
+
});
|
|
1374
|
+
}
|
|
1375
|
+
const entitiesArray = sourceFile
|
|
1376
|
+
.getVariableDeclarationOrThrow("entities")
|
|
1377
|
+
.getInitializerIfKindOrThrow(ts_morph_1.SyntaxKind.ArrayLiteralExpression);
|
|
1378
|
+
const entityAlreadyRegistered = this.arrayLiteralContainsValue(entitiesArray, entityClassName);
|
|
1379
|
+
if (!entityAlreadyRegistered) {
|
|
1380
|
+
entitiesArray.addElement(entityClassName);
|
|
1381
|
+
}
|
|
1382
|
+
const dataSourceOptions = this.getTypeormDatasourceOptions(sourceFile);
|
|
1383
|
+
const migrationsArray = this.getObjectPropertyArrayLiteral(dataSourceOptions, "migrations");
|
|
1384
|
+
const migrationAlreadyRegistered = this.arrayLiteralContainsValue(migrationsArray, migrationGlob);
|
|
1385
|
+
if (!migrationAlreadyRegistered) {
|
|
1386
|
+
migrationsArray.addElement(migrationGlob);
|
|
1387
|
+
}
|
|
1388
|
+
sourceFile.organizeImports();
|
|
1389
|
+
sourceFile.formatText();
|
|
1390
|
+
const nextContent = sourceFile.getFullText();
|
|
1391
|
+
const updated = nextContent !== existingContent;
|
|
1392
|
+
if (updated) {
|
|
1393
|
+
await fs.writeFile(datasourceFilePath, nextContent, "utf8");
|
|
1394
|
+
}
|
|
1395
|
+
return {
|
|
1396
|
+
filePath: datasourceFilePath,
|
|
1397
|
+
created: false,
|
|
1398
|
+
updated,
|
|
1399
|
+
entityRegistered: true,
|
|
1400
|
+
migrationGlobRegistered: true,
|
|
1401
|
+
};
|
|
1402
|
+
}
|
|
1403
|
+
renderTypeormDatasourceTemplate(input) {
|
|
1404
|
+
const { datasource, entityClassName, entityImportPath, migrationGlob } = input;
|
|
1405
|
+
const envPrefix = datasource.envPrefix?.toUpperCase?.() || "DEFAULT";
|
|
1406
|
+
const portFallback = datasource.type === "postgres" ? 5432 : datasource.type === "mysql" ? 3306 : 1433;
|
|
1407
|
+
const project = new ts_morph_1.Project({
|
|
1408
|
+
skipAddingFilesFromTsConfig: true,
|
|
1409
|
+
manipulationSettings: {
|
|
1410
|
+
quoteKind: ts_morph_1.QuoteKind.Single,
|
|
1411
|
+
indentationText: ts_morph_1.IndentationText.FourSpaces,
|
|
1412
|
+
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
|
1413
|
+
},
|
|
1414
|
+
});
|
|
1415
|
+
const sourceFile = project.createSourceFile("typeorm-template.ts", "", { overwrite: true });
|
|
1416
|
+
sourceFile.addImportDeclaration({ moduleSpecifier: "reflect-metadata" });
|
|
1417
|
+
sourceFile.addImportDeclaration({ moduleSpecifier: "path", namedImports: ["join"] });
|
|
1418
|
+
sourceFile.addImportDeclaration({
|
|
1419
|
+
moduleSpecifier: "dotenv",
|
|
1420
|
+
namedImports: [{ name: "config", alias: "dotenvConfig" }],
|
|
1421
|
+
});
|
|
1422
|
+
sourceFile.addStatements("dotenvConfig({ path: join(__dirname, '../.env') });");
|
|
1423
|
+
sourceFile.addStatements("");
|
|
1424
|
+
sourceFile.addImportDeclaration({ moduleSpecifier: "typeorm", namedImports: ["DataSource"] });
|
|
1425
|
+
sourceFile.addImportDeclaration({
|
|
1426
|
+
moduleSpecifier: "@solidxai/core",
|
|
1427
|
+
namespaceImport: "SolidCoreModuleExports",
|
|
1428
|
+
});
|
|
1429
|
+
sourceFile.addImportDeclaration({
|
|
1430
|
+
moduleSpecifier: "@solidxai/core",
|
|
1431
|
+
namedImports: ["getDynamicModuleNames", "parseBooleanEnv"],
|
|
1432
|
+
});
|
|
1433
|
+
sourceFile.addImportDeclaration({
|
|
1434
|
+
moduleSpecifier: "typeorm",
|
|
1435
|
+
namedImports: ["getMetadataArgsStorage"],
|
|
1436
|
+
});
|
|
1437
|
+
sourceFile.addImportDeclaration({
|
|
1438
|
+
moduleSpecifier: "typeorm-naming-strategies",
|
|
1439
|
+
namedImports: ["SnakeNamingStrategy"],
|
|
1440
|
+
});
|
|
1441
|
+
sourceFile.addImportDeclaration({
|
|
1442
|
+
moduleSpecifier: entityImportPath,
|
|
1443
|
+
namedImports: [entityClassName],
|
|
1444
|
+
});
|
|
1445
|
+
sourceFile.addFunction({
|
|
1446
|
+
name: "getEntitiesFromExports",
|
|
1447
|
+
parameters: [{ name: "exports", type: "Record<string, any>" }],
|
|
1448
|
+
statements: (writer) => {
|
|
1449
|
+
writer.writeLine("const metadataStorage = getMetadataArgsStorage();");
|
|
1450
|
+
writer.writeLine("return Object.values(exports).filter((item) =>");
|
|
1451
|
+
writer.indent(() => {
|
|
1452
|
+
writer.writeLine("metadataStorage.tables.some((table) => table.target === item),");
|
|
1453
|
+
});
|
|
1454
|
+
writer.write(");");
|
|
1455
|
+
},
|
|
1456
|
+
});
|
|
1457
|
+
sourceFile.addVariableStatement({
|
|
1458
|
+
declarationKind: ts_morph_1.VariableDeclarationKind.Const,
|
|
1459
|
+
declarations: [
|
|
1460
|
+
{
|
|
1461
|
+
name: "coreEntities",
|
|
1462
|
+
initializer: "getEntitiesFromExports(SolidCoreModuleExports)",
|
|
1463
|
+
},
|
|
1464
|
+
],
|
|
1465
|
+
});
|
|
1466
|
+
sourceFile.addVariableStatement({
|
|
1467
|
+
declarationKind: ts_morph_1.VariableDeclarationKind.Const,
|
|
1468
|
+
declarations: [
|
|
1469
|
+
{
|
|
1470
|
+
name: "dynamicModules",
|
|
1471
|
+
initializer: "getDynamicModuleNames()",
|
|
1472
|
+
},
|
|
1473
|
+
],
|
|
1474
|
+
});
|
|
1475
|
+
sourceFile.addVariableStatement({
|
|
1476
|
+
declarationKind: ts_morph_1.VariableDeclarationKind.Const,
|
|
1477
|
+
declarations: [
|
|
1478
|
+
{
|
|
1479
|
+
name: "entities",
|
|
1480
|
+
initializer: `[\n ...coreEntities,\n ${entityClassName},\n]`,
|
|
1481
|
+
},
|
|
1482
|
+
],
|
|
1483
|
+
});
|
|
1484
|
+
sourceFile.addVariableStatement({
|
|
1485
|
+
declarationKind: ts_morph_1.VariableDeclarationKind.Const,
|
|
1486
|
+
declarations: [
|
|
1487
|
+
{
|
|
1488
|
+
name: "logging",
|
|
1489
|
+
initializer: `parseBooleanEnv('${envPrefix}_DATABASE_LOGGING')`,
|
|
1490
|
+
},
|
|
1491
|
+
],
|
|
1492
|
+
});
|
|
1493
|
+
sourceFile.addStatements("// IMPORTANT: synchronize must be false when using migrations");
|
|
1494
|
+
sourceFile.addVariableStatement({
|
|
1495
|
+
declarationKind: ts_morph_1.VariableDeclarationKind.Const,
|
|
1496
|
+
isExported: true,
|
|
1497
|
+
declarations: [
|
|
1498
|
+
{
|
|
1499
|
+
name: "DefaultDataSource",
|
|
1500
|
+
initializer: (writer) => {
|
|
1501
|
+
writer.write("new DataSource(");
|
|
1502
|
+
writer.inlineBlock(() => {
|
|
1503
|
+
writer.writeLine(`type: '${datasource.type}',`);
|
|
1504
|
+
writer.blankLine();
|
|
1505
|
+
writer.writeLine(`host: process.env.${envPrefix}_DATABASE_HOST,`);
|
|
1506
|
+
writer.writeLine(`port: +(process.env.${envPrefix}_DATABASE_PORT || ${portFallback}),`);
|
|
1507
|
+
writer.writeLine(`username: process.env.${envPrefix}_DATABASE_USER,`);
|
|
1508
|
+
writer.writeLine(`password: process.env.${envPrefix}_DATABASE_PASSWORD,`);
|
|
1509
|
+
writer.writeLine(`database: process.env.${envPrefix}_DATABASE_NAME,`);
|
|
1510
|
+
writer.blankLine();
|
|
1511
|
+
writer.writeLine("entities,");
|
|
1512
|
+
writer.writeLine("migrations: [");
|
|
1513
|
+
writer.indent(() => {
|
|
1514
|
+
writer.writeLine(`${migrationGlob},`);
|
|
1515
|
+
});
|
|
1516
|
+
writer.writeLine("],");
|
|
1517
|
+
writer.writeLine("synchronize: false,");
|
|
1518
|
+
writer.writeLine("logging,");
|
|
1519
|
+
writer.writeLine("namingStrategy: new SnakeNamingStrategy(),");
|
|
1520
|
+
if (datasource.type === "mssql") {
|
|
1521
|
+
writer.writeLine("options: {");
|
|
1522
|
+
writer.indent(() => {
|
|
1523
|
+
writer.writeLine("encrypt: false,");
|
|
1524
|
+
writer.writeLine("trustServerCertificate: true,");
|
|
1525
|
+
});
|
|
1526
|
+
writer.writeLine("},");
|
|
1527
|
+
}
|
|
1528
|
+
});
|
|
1529
|
+
writer.write(")");
|
|
1530
|
+
},
|
|
1531
|
+
},
|
|
1532
|
+
],
|
|
1533
|
+
});
|
|
1534
|
+
sourceFile.organizeImports();
|
|
1535
|
+
sourceFile.formatText();
|
|
1536
|
+
return sourceFile.getFullText();
|
|
1537
|
+
}
|
|
1538
|
+
arrayLiteralContainsValue(arrayLiteral, rawValue) {
|
|
1539
|
+
const normalizedTarget = rawValue.replace(/\s+/g, "");
|
|
1540
|
+
return arrayLiteral.getElements().some((element) => element.getText().replace(/\s+/g, "") === normalizedTarget);
|
|
1541
|
+
}
|
|
1542
|
+
getTypeormDatasourceOptions(sourceFile) {
|
|
1543
|
+
const defaultDataSourceDeclaration = sourceFile.getVariableDeclarationOrThrow("DefaultDataSource");
|
|
1544
|
+
const initializer = defaultDataSourceDeclaration.getInitializer();
|
|
1545
|
+
if (!initializer || !ts_morph_1.Node.isNewExpression(initializer)) {
|
|
1546
|
+
throw new common_1.BadRequestException("Unable to locate DefaultDataSource initializer in datasource file.");
|
|
1547
|
+
}
|
|
1548
|
+
const options = initializer.getArguments()[0];
|
|
1549
|
+
if (!options || !ts_morph_1.Node.isObjectLiteralExpression(options)) {
|
|
1550
|
+
throw new common_1.BadRequestException("Unable to locate DefaultDataSource options object in datasource file.");
|
|
1551
|
+
}
|
|
1552
|
+
return options;
|
|
1553
|
+
}
|
|
1554
|
+
getObjectPropertyArrayLiteral(objectLiteral, propertyName) {
|
|
1555
|
+
const property = objectLiteral.getProperty(propertyName);
|
|
1556
|
+
if (!property || !ts_morph_1.Node.isPropertyAssignment(property)) {
|
|
1557
|
+
throw new common_1.BadRequestException(`Unable to locate "${propertyName}" property in datasource file.`);
|
|
1558
|
+
}
|
|
1559
|
+
const initializer = property.getInitializer();
|
|
1560
|
+
if (!initializer || !ts_morph_1.Node.isArrayLiteralExpression(initializer)) {
|
|
1561
|
+
throw new common_1.BadRequestException(`Unable to locate "${propertyName}" array in datasource file.`);
|
|
1562
|
+
}
|
|
1563
|
+
return initializer;
|
|
1564
|
+
}
|
|
1193
1565
|
buildSynchronizeBlockedMessage(datasource) {
|
|
1194
1566
|
return `Datasource "${datasource.displayName}" has synchronize enabled. Set ${datasource.envPrefix}_DATABASE_SYNCHRONIZE=false before starting legacy table introspection.`;
|
|
1195
1567
|
}
|
|
@@ -1271,6 +1643,8 @@ exports.DatasourceIntrospectionService = DatasourceIntrospectionService = __deco
|
|
|
1271
1643
|
model_metadata_helper_service_1.ModelMetadataHelperService,
|
|
1272
1644
|
field_metadata_service_1.FieldMetadataService,
|
|
1273
1645
|
model_metadata_service_1.ModelMetadataService,
|
|
1646
|
+
module_metadata_service_1.ModuleMetadataService,
|
|
1647
|
+
command_service_1.CommandService,
|
|
1274
1648
|
mssql_datasource_introspection_provider_service_1.MssqlDatasourceIntrospectionProviderService,
|
|
1275
1649
|
mysql_datasource_introspection_provider_service_1.MysqlDatasourceIntrospectionProviderService,
|
|
1276
1650
|
postgres_datasource_introspection_provider_service_1.PostgresDatasourceIntrospectionProviderService])
|