@solidxai/core 0.1.11-beta.9 → 0.1.11
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/CHANGELOG.md +456 -0
- package/dist/controllers/datasource-introspection.controller.d.ts +8 -0
- package/dist/controllers/datasource-introspection.controller.d.ts.map +1 -1
- package/dist/controllers/media.controller.js +0 -2
- package/dist/controllers/media.controller.js.map +1 -1
- package/dist/helpers/environment.helper.d.ts +0 -1
- package/dist/helpers/environment.helper.d.ts.map +1 -1
- package/dist/helpers/environment.helper.js +0 -4
- package/dist/helpers/environment.helper.js.map +1 -1
- package/dist/helpers/model-metadata-helper.service.d.ts +1 -2
- package/dist/helpers/model-metadata-helper.service.d.ts.map +1 -1
- package/dist/helpers/model-metadata-helper.service.js +2 -6
- package/dist/helpers/model-metadata-helper.service.js.map +1 -1
- package/dist/helpers/module-metadata-helper.service.js +1 -1
- package/dist/helpers/module-metadata-helper.service.js.map +1 -1
- package/dist/helpers/solid-registry.d.ts +1 -2
- package/dist/helpers/solid-registry.d.ts.map +1 -1
- package/dist/helpers/solid-registry.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +1 -0
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/repository/scheduled-job.repository.d.ts +2 -2
- package/dist/repository/scheduled-job.repository.d.ts.map +1 -1
- package/dist/repository/scheduled-job.repository.js +3 -6
- package/dist/repository/scheduled-job.repository.js.map +1 -1
- package/dist/repository/security-rule.repository.d.ts +2 -2
- package/dist/repository/security-rule.repository.d.ts.map +1 -1
- package/dist/repository/security-rule.repository.js +3 -6
- package/dist/repository/security-rule.repository.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +62 -33
- package/dist/services/authentication.service.d.ts +2 -0
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +32 -11
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts.map +1 -1
- package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js +5 -7
- package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js.map +1 -1
- package/dist/services/crud-helper.service.d.ts.map +1 -1
- package/dist/services/crud-helper.service.js +7 -0
- package/dist/services/crud-helper.service.js.map +1 -1
- package/dist/services/datasource-introspection.service.d.ts +10 -0
- package/dist/services/datasource-introspection.service.d.ts.map +1 -1
- package/dist/services/datasource-introspection.service.js +109 -17
- package/dist/services/datasource-introspection.service.js.map +1 -1
- package/dist/services/menu-item-metadata.service.d.ts.map +1 -1
- package/dist/services/menu-item-metadata.service.js +1 -0
- package/dist/services/menu-item-metadata.service.js.map +1 -1
- package/dist/services/model-metadata.service.d.ts +2 -0
- package/dist/services/model-metadata.service.d.ts.map +1 -1
- package/dist/services/model-metadata.service.js +49 -16
- package/dist/services/model-metadata.service.js.map +1 -1
- package/dist/services/module-metadata.service.d.ts.map +1 -1
- package/dist/services/module-metadata.service.js +0 -28
- package/dist/services/module-metadata.service.js.map +1 -1
- package/dist/services/settings/default-settings-provider.service.d.ts +212 -0
- package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
- package/dist/services/settings/default-settings-provider.service.js +106 -0
- package/dist/services/settings/default-settings-provider.service.js.map +1 -1
- package/dist/services/solid-ts-morph.service.d.ts +6 -0
- package/dist/services/solid-ts-morph.service.d.ts.map +1 -1
- package/dist/services/solid-ts-morph.service.js +43 -0
- package/dist/services/solid-ts-morph.service.js.map +1 -1
- package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
- package/dist/subscribers/audit.subscriber.js +2 -8
- package/dist/subscribers/audit.subscriber.js.map +1 -1
- package/dist/subscribers/computed-entity-field.subscriber.d.ts +0 -8
- package/dist/subscribers/computed-entity-field.subscriber.d.ts.map +1 -1
- package/dist/subscribers/computed-entity-field.subscriber.js +3 -36
- package/dist/subscribers/computed-entity-field.subscriber.js.map +1 -1
- package/dist/subscribers/created-by-updated-by.subscriber.d.ts.map +1 -1
- package/dist/subscribers/created-by-updated-by.subscriber.js.map +1 -1
- package/dist/subscribers/field-metadata.subscriber.d.ts.map +1 -1
- package/dist/subscribers/field-metadata.subscriber.js.map +1 -1
- package/dist/subscribers/scheduled-job.subscriber.d.ts.map +1 -1
- package/dist/subscribers/scheduled-job.subscriber.js +2 -3
- package/dist/subscribers/scheduled-job.subscriber.js.map +1 -1
- package/dist/subscribers/security-rule.subscriber.d.ts.map +1 -1
- package/dist/subscribers/security-rule.subscriber.js +3 -5
- package/dist/subscribers/security-rule.subscriber.js.map +1 -1
- package/package.json +1 -1
- package/src/controllers/media.controller.ts +1 -1
- package/src/helpers/environment.helper.ts +0 -11
- package/src/helpers/model-metadata-helper.service.ts +2 -7
- package/src/helpers/module-metadata-helper.service.ts +1 -1
- package/src/helpers/solid-registry.ts +1 -7
- package/src/index.ts +0 -1
- package/src/interfaces.ts +1 -0
- package/src/repository/scheduled-job.repository.ts +4 -10
- package/src/repository/security-rule.repository.ts +4 -10
- package/src/seeders/seed-data/solid-core-metadata.json +62 -33
- package/src/services/authentication.service.ts +46 -12
- package/src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts +5 -11
- package/src/services/crud-helper.service.ts +7 -0
- package/src/services/datasource-introspection.service.ts +176 -16
- package/src/services/menu-item-metadata.service.ts +2 -1
- package/src/services/model-metadata.service.ts +63 -22
- package/src/services/module-metadata.service.ts +0 -36
- package/src/services/settings/default-settings-provider.service.ts +106 -0
- package/src/services/solid-ts-morph.service.ts +61 -1
- package/src/subscribers/audit.subscriber.ts +2 -11
- package/src/subscribers/computed-entity-field.subscriber.ts +6 -63
- package/src/subscribers/created-by-updated-by.subscriber.ts +0 -3
- package/src/subscribers/field-metadata.subscriber.ts +0 -3
- package/src/subscribers/scheduled-job.subscriber.ts +2 -3
- package/src/subscribers/security-rule.subscriber.ts +3 -8
- package/dist/helpers/nodemon-heartbeat.d.ts +0 -5
- package/dist/helpers/nodemon-heartbeat.d.ts.map +0 -1
- package/dist/helpers/nodemon-heartbeat.js +0 -67
- package/dist/helpers/nodemon-heartbeat.js.map +0 -1
- package/src/helpers/nodemon-heartbeat.ts +0 -59
|
@@ -290,10 +290,7 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
290
290
|
if (!mappingDto.modelId) {
|
|
291
291
|
throw new common_1.BadRequestException("Persist the model mapping first so the generated entity can be registered before creating migration artifacts.");
|
|
292
292
|
}
|
|
293
|
-
|
|
294
|
-
await fs.mkdir(path.dirname(plan.migration.filePath), { recursive: true });
|
|
295
|
-
await fs.writeFile(plan.migration.filePath, plan.migration.content, "utf8");
|
|
296
|
-
}
|
|
293
|
+
const migrationWritten = await this.writeMigrationFile(plan.migration);
|
|
297
294
|
const datasourceFile = await this.syncTypeormDatasourceFile(module.name, datasource, plan.modelPayload.singularName);
|
|
298
295
|
return {
|
|
299
296
|
data: {
|
|
@@ -301,7 +298,7 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
301
298
|
operation: plan.operation,
|
|
302
299
|
migration: {
|
|
303
300
|
...plan.migration,
|
|
304
|
-
written:
|
|
301
|
+
written: migrationWritten,
|
|
305
302
|
},
|
|
306
303
|
datasourceFile,
|
|
307
304
|
summary: plan.summary,
|
|
@@ -377,6 +374,8 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
377
374
|
if (!tableRecord) {
|
|
378
375
|
throw new common_1.NotFoundException(`Table "${mappingDto.tableName}" was not found on datasource "${datasource.name}".`);
|
|
379
376
|
}
|
|
377
|
+
const tableColumns = inventory.columnsByKey.get(tableKey) ?? [];
|
|
378
|
+
this.validateTablePrimaryKeyForMapping(tableRecord, tableColumns, mappingDto);
|
|
380
379
|
const existingModel = mappingDto.mapped && mappingDto.modelId
|
|
381
380
|
? await this.modelMetadataRepository.findOne({
|
|
382
381
|
where: { id: mappingDto.modelId },
|
|
@@ -391,14 +390,14 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
391
390
|
if (mappingDto.mapped && !existingModel) {
|
|
392
391
|
throw new common_1.NotFoundException(`Mapped model "${mappingDto.modelId}" was not found.`);
|
|
393
392
|
}
|
|
394
|
-
const reviewedModel = this.normalizeReviewedMetadataModel(mappingDto.reviewedModel, mappingDto);
|
|
393
|
+
const reviewedModel = this.normalizeReviewedMetadataModel(mappingDto.reviewedModel, mappingDto, tableColumns);
|
|
395
394
|
const modelPayload = reviewedModel
|
|
396
395
|
? this.buildModelPayloadFromReviewedModel(moduleId, mappingDto, existingModel, reviewedModel)
|
|
397
396
|
: this.buildModelPayload(moduleId, mappingDto, existingModel);
|
|
398
397
|
const metadataJson = reviewedModel
|
|
399
398
|
? await this.buildMetadataJsonPreviewFromReviewedModel(module.name, reviewedModel)
|
|
400
399
|
: await this.buildMetadataJsonPreview(module.name, mappingDto, existingModel);
|
|
401
|
-
const migration = await this.buildMigrationPreview(module.name, datasource, mappingDto,
|
|
400
|
+
const migration = await this.buildMigrationPreview(module.name, datasource, mappingDto, tableColumns);
|
|
402
401
|
const includedColumnNames = mappingDto.columns
|
|
403
402
|
.filter((column) => !column.handledBySuperclass && column.include)
|
|
404
403
|
.map((column) => column.columnName);
|
|
@@ -462,6 +461,7 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
462
461
|
};
|
|
463
462
|
}
|
|
464
463
|
buildModelPayloadFromReviewedModel(moduleId, mappingDto, existingModel, reviewedModel) {
|
|
464
|
+
const resolvedUserKeyFieldName = this.resolveReviewedUserKeyFieldName(reviewedModel.fields, reviewedModel.userKeyFieldUserKey, mappingDto.userKeyField);
|
|
465
465
|
const systemFieldPayloads = existingModel
|
|
466
466
|
? existingModel.fields
|
|
467
467
|
.filter((field) => field.isSystem)
|
|
@@ -472,7 +472,7 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
472
472
|
return {
|
|
473
473
|
...field,
|
|
474
474
|
...(matchedExistingField?.id ? { id: matchedExistingField.id } : {}),
|
|
475
|
-
isUserKey: field.name ===
|
|
475
|
+
isUserKey: field.name === resolvedUserKeyFieldName,
|
|
476
476
|
isSystem: field.isSystem ?? false,
|
|
477
477
|
};
|
|
478
478
|
});
|
|
@@ -500,6 +500,7 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
500
500
|
async buildMetadataJsonPreview(moduleName, mappingDto, existingModel) {
|
|
501
501
|
const filePath = await this.moduleMetadataHelperService.getModuleMetadataFilePath(moduleName);
|
|
502
502
|
const previewFields = await this.buildMetadataPreviewFields(mappingDto, existingModel);
|
|
503
|
+
const resolvedUserKeyFieldName = this.resolveReviewedUserKeyFieldName(previewFields, mappingDto.userKeyField, mappingDto.userKeyField) ?? mappingDto.userKeyField;
|
|
503
504
|
return {
|
|
504
505
|
filePath,
|
|
505
506
|
model: {
|
|
@@ -510,7 +511,7 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
510
511
|
dataSource: mappingDto.dataSource,
|
|
511
512
|
dataSourceType: mappingDto.dataSourceType,
|
|
512
513
|
tableName: mappingDto.tableName,
|
|
513
|
-
userKeyFieldUserKey:
|
|
514
|
+
userKeyFieldUserKey: resolvedUserKeyFieldName,
|
|
514
515
|
isChild: false,
|
|
515
516
|
legacyTableType: mappingDto.legacyTableType,
|
|
516
517
|
parentModelUserKey: "",
|
|
@@ -559,10 +560,6 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
559
560
|
}
|
|
560
561
|
const serialized = Array.from(finalFields.values())
|
|
561
562
|
.filter((field) => !field.isSystem)
|
|
562
|
-
.map((field) => ({
|
|
563
|
-
...field,
|
|
564
|
-
isUserKey: field.name === mappingDto.userKeyField,
|
|
565
|
-
}))
|
|
566
563
|
.sort((left, right) => {
|
|
567
564
|
const leftOrder = typeof left.id === "number" ? left.id : Number.MAX_SAFE_INTEGER;
|
|
568
565
|
const rightOrder = typeof right.id === "number" ? right.id : Number.MAX_SAFE_INTEGER;
|
|
@@ -575,6 +572,10 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
575
572
|
for (const field of serialized) {
|
|
576
573
|
previewFields.push(await this.fieldMetadataService.createFieldConfig(field));
|
|
577
574
|
}
|
|
575
|
+
const resolvedUserKeyFieldName = this.resolveReviewedUserKeyFieldName(previewFields, mappingDto.userKeyField, mappingDto.userKeyField);
|
|
576
|
+
for (const field of previewFields) {
|
|
577
|
+
field.isUserKey = field.name === resolvedUserKeyFieldName;
|
|
578
|
+
}
|
|
578
579
|
return previewFields;
|
|
579
580
|
}
|
|
580
581
|
async buildMigrationPreview(moduleName, datasource, mappingDto, tableColumns) {
|
|
@@ -626,7 +627,7 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
626
627
|
}
|
|
627
628
|
return this.sanitizeExistingFieldPayload(fieldConfig);
|
|
628
629
|
}
|
|
629
|
-
normalizeReviewedMetadataModel(reviewedModel, mappingDto) {
|
|
630
|
+
normalizeReviewedMetadataModel(reviewedModel, mappingDto, tableColumns) {
|
|
630
631
|
if (!reviewedModel) {
|
|
631
632
|
return null;
|
|
632
633
|
}
|
|
@@ -675,10 +676,14 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
675
676
|
}
|
|
676
677
|
fieldNames.add(loweredName);
|
|
677
678
|
}
|
|
678
|
-
const
|
|
679
|
-
|
|
679
|
+
const requestedUserKeyFieldUserKey = readString("userKeyFieldUserKey");
|
|
680
|
+
const resolvedUserKeyFieldName = this.resolveReviewedUserKeyFieldName(normalizedFields, requestedUserKeyFieldUserKey, mappingDto.userKeyField);
|
|
681
|
+
const inheritedGeneratedIdUserKey = this.isGeneratedIdInheritedUserKey(mappingDto.legacyTableType, requestedUserKeyFieldUserKey);
|
|
682
|
+
if (!resolvedUserKeyFieldName && !inheritedGeneratedIdUserKey) {
|
|
680
683
|
throw new common_1.BadRequestException("Reviewed metadata JSON must keep the selected userKeyFieldUserKey in the fields array.");
|
|
681
684
|
}
|
|
685
|
+
this.validateReviewedPrimaryKeyFields(normalizedFields, tableColumns);
|
|
686
|
+
const userKeyFieldUserKey = resolvedUserKeyFieldName ?? requestedUserKeyFieldUserKey;
|
|
682
687
|
return {
|
|
683
688
|
singularName: readString("singularName"),
|
|
684
689
|
pluralName: readString("pluralName"),
|
|
@@ -697,10 +702,39 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
697
702
|
internationalisation: readBoolean("internationalisation"),
|
|
698
703
|
fields: normalizedFields.map((field) => ({
|
|
699
704
|
...field,
|
|
700
|
-
isUserKey: field.name ===
|
|
705
|
+
isUserKey: field.name === resolvedUserKeyFieldName,
|
|
701
706
|
})),
|
|
702
707
|
};
|
|
703
708
|
}
|
|
709
|
+
resolveReviewedUserKeyFieldName(reviewedFields, requestedUserKeyFieldName, fallbackUserKeyFieldName) {
|
|
710
|
+
const activeFields = reviewedFields.filter((field) => !field.isMarkedForRemoval);
|
|
711
|
+
const normalizedRequested = `${requestedUserKeyFieldName ?? ""}`.trim().toLowerCase();
|
|
712
|
+
const normalizedFallback = `${fallbackUserKeyFieldName ?? ""}`.trim().toLowerCase();
|
|
713
|
+
const byExactRequested = activeFields.find((field) => field.name?.toLowerCase?.() === normalizedRequested);
|
|
714
|
+
if (byExactRequested) {
|
|
715
|
+
return byExactRequested.name;
|
|
716
|
+
}
|
|
717
|
+
const byExistingUserKeyFlag = activeFields.find((field) => field.isUserKey);
|
|
718
|
+
if (byExistingUserKeyFlag) {
|
|
719
|
+
return byExistingUserKeyFlag.name;
|
|
720
|
+
}
|
|
721
|
+
const byPrimaryKeyFallback = activeFields.find((field) => {
|
|
722
|
+
if (!field.isPrimaryKey) {
|
|
723
|
+
return false;
|
|
724
|
+
}
|
|
725
|
+
const normalizedName = `${field.name ?? ""}`.trim().toLowerCase();
|
|
726
|
+
return normalizedName === normalizedFallback || normalizedName === "id" || normalizedName === "legacyid";
|
|
727
|
+
});
|
|
728
|
+
if (byPrimaryKeyFallback) {
|
|
729
|
+
return byPrimaryKeyFallback.name;
|
|
730
|
+
}
|
|
731
|
+
const byFallbackFieldName = activeFields.find((field) => field.name?.toLowerCase?.() === normalizedFallback);
|
|
732
|
+
return byFallbackFieldName?.name ?? null;
|
|
733
|
+
}
|
|
734
|
+
isGeneratedIdInheritedUserKey(legacyTableType, requestedUserKeyFieldName) {
|
|
735
|
+
return legacyTableType === legacy_table_type_enum_1.LegacyTableType.GENERATED_ID
|
|
736
|
+
&& `${requestedUserKeyFieldName ?? ""}`.trim().toLowerCase() === "id";
|
|
737
|
+
}
|
|
704
738
|
normalizeReviewedField(field, index) {
|
|
705
739
|
if (!field || typeof field !== "object" || Array.isArray(field)) {
|
|
706
740
|
throw new common_1.BadRequestException(`Reviewed metadata JSON field at index ${index} is not a valid object.`);
|
|
@@ -1036,6 +1070,8 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
1036
1070
|
const suggestedIdColumn = this.getSuggestedIdColumn(datasource.type, tableColumns, suggestedLegacyTableType);
|
|
1037
1071
|
const mappedModel = this.resolveMappedModel(modelLookup, datasource.name, tableName);
|
|
1038
1072
|
const physicalColumns = tableColumns.filter((column) => !this.isHandledBySuperclass(column.columnName, suggestedLegacyTableType));
|
|
1073
|
+
const primaryKeyColumns = tableColumns.filter((column) => column.isPrimaryKey);
|
|
1074
|
+
const hasPrimaryKey = primaryKeyColumns.length > 0;
|
|
1039
1075
|
return {
|
|
1040
1076
|
schema,
|
|
1041
1077
|
tableName,
|
|
@@ -1052,6 +1088,12 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
1052
1088
|
suggestedUserKeyField: this.buildUserKeyCandidates(tableColumns)[0]?.name ?? "id",
|
|
1053
1089
|
columnCount: tableColumns.length,
|
|
1054
1090
|
physicalColumnCount: physicalColumns.length,
|
|
1091
|
+
hasPrimaryKey,
|
|
1092
|
+
primaryKeyColumnCount: primaryKeyColumns.length,
|
|
1093
|
+
primaryKeyColumnNames: primaryKeyColumns.map((column) => column.columnName),
|
|
1094
|
+
mappingBlockedReason: hasPrimaryKey
|
|
1095
|
+
? null
|
|
1096
|
+
: this.buildMissingPrimaryKeyMessage(tableName),
|
|
1055
1097
|
};
|
|
1056
1098
|
})
|
|
1057
1099
|
.filter((record) => Boolean(record))
|
|
@@ -1209,6 +1251,44 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
1209
1251
|
superclassFieldName,
|
|
1210
1252
|
};
|
|
1211
1253
|
}
|
|
1254
|
+
validateTablePrimaryKeyForMapping(tableRecord, tableColumns, mappingDto) {
|
|
1255
|
+
const detectedPrimaryKeyColumns = tableColumns.filter((column) => column.isPrimaryKey);
|
|
1256
|
+
if (!detectedPrimaryKeyColumns.length) {
|
|
1257
|
+
throw new common_1.BadRequestException(tableRecord.mappingBlockedReason ?? this.buildMissingPrimaryKeyMessage(tableRecord.tableName));
|
|
1258
|
+
}
|
|
1259
|
+
const requestColumnsByName = new Map(mappingDto.columns.map((column) => [column.columnName.trim().toLowerCase(), column]));
|
|
1260
|
+
for (const primaryKeyColumn of detectedPrimaryKeyColumns) {
|
|
1261
|
+
const matchingRequestColumn = requestColumnsByName.get(primaryKeyColumn.columnName.trim().toLowerCase());
|
|
1262
|
+
if (!matchingRequestColumn) {
|
|
1263
|
+
throw new common_1.BadRequestException(`Primary key column "${primaryKeyColumn.columnName}" must remain present in the mapping request for table "${tableRecord.tableName}".`);
|
|
1264
|
+
}
|
|
1265
|
+
if (!matchingRequestColumn.include) {
|
|
1266
|
+
throw new common_1.BadRequestException(`Primary key column "${primaryKeyColumn.columnName}" cannot be excluded from the mapping for table "${tableRecord.tableName}".`);
|
|
1267
|
+
}
|
|
1268
|
+
if (!matchingRequestColumn.isPrimaryKey) {
|
|
1269
|
+
throw new common_1.BadRequestException(`Primary key column "${primaryKeyColumn.columnName}" must stay marked as isPrimaryKey for table "${tableRecord.tableName}".`);
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
validateReviewedPrimaryKeyFields(reviewedFields, tableColumns) {
|
|
1274
|
+
const detectedPrimaryKeyColumns = tableColumns.filter((column) => column.isPrimaryKey);
|
|
1275
|
+
if (!detectedPrimaryKeyColumns.length) {
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
const activeReviewedFields = reviewedFields.filter((field) => !field.isMarkedForRemoval);
|
|
1279
|
+
for (const primaryKeyColumn of detectedPrimaryKeyColumns) {
|
|
1280
|
+
const matchingReviewedField = activeReviewedFields.find((field) => `${field.columnName ?? ""}`.trim().toLowerCase() === primaryKeyColumn.columnName.trim().toLowerCase());
|
|
1281
|
+
if (!matchingReviewedField) {
|
|
1282
|
+
throw new common_1.BadRequestException(`Reviewed metadata JSON must keep datasource primary key column "${primaryKeyColumn.columnName}" in the fields array.`);
|
|
1283
|
+
}
|
|
1284
|
+
if (!matchingReviewedField.isPrimaryKey) {
|
|
1285
|
+
throw new common_1.BadRequestException(`Reviewed metadata JSON must keep datasource primary key column "${primaryKeyColumn.columnName}" marked with isPrimaryKey: true.`);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
buildMissingPrimaryKeyMessage(tableName) {
|
|
1290
|
+
return `Table "${tableName}" cannot be mapped because the datasource table does not define any primary key. Add a real primary key to the table before continuing with SolidX mapping.`;
|
|
1291
|
+
}
|
|
1212
1292
|
getSuperclassFieldName(columnName, legacyTableType) {
|
|
1213
1293
|
return this.getLegacySuperclassFieldName(columnName, legacyTableType);
|
|
1214
1294
|
}
|
|
@@ -1411,6 +1491,18 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
|
|
|
1411
1491
|
migrationGlobRegistered: true,
|
|
1412
1492
|
};
|
|
1413
1493
|
}
|
|
1494
|
+
async writeMigrationFile(migration) {
|
|
1495
|
+
if (!migration.willGenerate || !migration.content || !migration.filePath) {
|
|
1496
|
+
return false;
|
|
1497
|
+
}
|
|
1498
|
+
await fs.mkdir(path.dirname(migration.filePath), { recursive: true });
|
|
1499
|
+
await fs.writeFile(migration.filePath, migration.content, "utf8");
|
|
1500
|
+
const writtenContent = await fs.readFile(migration.filePath, "utf8").catch(() => null);
|
|
1501
|
+
if (writtenContent !== migration.content) {
|
|
1502
|
+
throw new common_1.BadRequestException(`Migration file could not be verified after writing: ${migration.filePath}`);
|
|
1503
|
+
}
|
|
1504
|
+
return true;
|
|
1505
|
+
}
|
|
1414
1506
|
renderTypeormDatasourceTemplate(input) {
|
|
1415
1507
|
const { datasource, entityClassName, entityImportPath, migrationGlob } = input;
|
|
1416
1508
|
const envPrefix = datasource.envPrefix?.toUpperCase?.() || "DEFAULT";
|