@memberjunction/integration-schema-builder 0.0.1 → 5.9.0
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/dist/AccessControl.d.ts +26 -0
- package/dist/AccessControl.d.ts.map +1 -0
- package/dist/AccessControl.js +68 -0
- package/dist/AccessControl.js.map +1 -0
- package/dist/DDLGenerator.d.ts +37 -0
- package/dist/DDLGenerator.d.ts.map +1 -0
- package/dist/DDLGenerator.js +155 -0
- package/dist/DDLGenerator.js.map +1 -0
- package/dist/MetadataEmitter.d.ts +23 -0
- package/dist/MetadataEmitter.d.ts.map +1 -0
- package/dist/MetadataEmitter.js +52 -0
- package/dist/MetadataEmitter.js.map +1 -0
- package/dist/MigrationFileWriter.d.ts +25 -0
- package/dist/MigrationFileWriter.d.ts.map +1 -0
- package/dist/MigrationFileWriter.js +67 -0
- package/dist/MigrationFileWriter.js.map +1 -0
- package/dist/SchemaBuilder.d.ts +27 -0
- package/dist/SchemaBuilder.d.ts.map +1 -0
- package/dist/SchemaBuilder.js +177 -0
- package/dist/SchemaBuilder.js.map +1 -0
- package/dist/SchemaEvolution.d.ts +27 -0
- package/dist/SchemaEvolution.d.ts.map +1 -0
- package/dist/SchemaEvolution.js +91 -0
- package/dist/SchemaEvolution.js.map +1 -0
- package/dist/SoftFKConfigEmitter.d.ts +53 -0
- package/dist/SoftFKConfigEmitter.d.ts.map +1 -0
- package/dist/SoftFKConfigEmitter.js +140 -0
- package/dist/SoftFKConfigEmitter.js.map +1 -0
- package/dist/TypeMapper.d.ts +25 -0
- package/dist/TypeMapper.d.ts.map +1 -0
- package/dist/TypeMapper.js +72 -0
- package/dist/TypeMapper.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces.d.ts +182 -0
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/interfaces.js +8 -0
- package/dist/interfaces.js.map +1 -0
- package/package.json +28 -7
- package/README.md +0 -45
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { DDLGenerator } from './DDLGenerator.js';
|
|
2
|
+
import { MigrationFileWriter } from './MigrationFileWriter.js';
|
|
3
|
+
import { SoftFKConfigEmitter } from './SoftFKConfigEmitter.js';
|
|
4
|
+
import { MetadataEmitter } from './MetadataEmitter.js';
|
|
5
|
+
import { SchemaEvolution } from './SchemaEvolution.js';
|
|
6
|
+
import { IsIntegrationWriteAllowed } from './AccessControl.js';
|
|
7
|
+
/**
|
|
8
|
+
* Main entry point for the Integration Schema Builder.
|
|
9
|
+
* Coordinates DDL generation, soft FK emission, metadata emission, and evolution diffs.
|
|
10
|
+
*/
|
|
11
|
+
export class SchemaBuilder {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.DDL = new DDLGenerator();
|
|
14
|
+
this.MigrationWriter = new MigrationFileWriter();
|
|
15
|
+
this.SoftFKEmitter = new SoftFKConfigEmitter();
|
|
16
|
+
this.MetaEmitter = new MetadataEmitter();
|
|
17
|
+
this.Evolution = new SchemaEvolution();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Build all artifacts for a set of integration target tables.
|
|
21
|
+
*/
|
|
22
|
+
BuildSchema(input) {
|
|
23
|
+
const output = {
|
|
24
|
+
MigrationFiles: [],
|
|
25
|
+
AdditionalSchemaInfoUpdate: null,
|
|
26
|
+
MetadataFiles: [],
|
|
27
|
+
Warnings: [],
|
|
28
|
+
Errors: [],
|
|
29
|
+
};
|
|
30
|
+
// Step 1: Validate access control
|
|
31
|
+
const accessErrors = this.ValidateAccessControl(input);
|
|
32
|
+
if (accessErrors.length > 0) {
|
|
33
|
+
output.Errors.push(...accessErrors);
|
|
34
|
+
return output;
|
|
35
|
+
}
|
|
36
|
+
// Step 2: Pre-flight collision checks
|
|
37
|
+
const collisionWarnings = this.CheckCollisions(input);
|
|
38
|
+
output.Warnings.push(...collisionWarnings);
|
|
39
|
+
// Step 3: Separate new tables vs evolution
|
|
40
|
+
const { newConfigs, evolutionConfigs } = this.ClassifyConfigs(input);
|
|
41
|
+
// Step 4: Generate DDL — one migration file per integration
|
|
42
|
+
const now = new Date();
|
|
43
|
+
const ddlParts = [];
|
|
44
|
+
// Schema creation statements (deduplicate by schema name)
|
|
45
|
+
const schemasToCreate = this.GetUniqueSchemas(newConfigs);
|
|
46
|
+
for (const schemaName of schemasToCreate) {
|
|
47
|
+
ddlParts.push(this.DDL.GenerateCreateSchema(schemaName, input.Platform));
|
|
48
|
+
ddlParts.push(''); // blank line separator
|
|
49
|
+
}
|
|
50
|
+
// Table creation statements
|
|
51
|
+
for (const config of newConfigs) {
|
|
52
|
+
ddlParts.push(this.DDL.GenerateCreateTable(config, input.Platform));
|
|
53
|
+
ddlParts.push(''); // blank line separator
|
|
54
|
+
}
|
|
55
|
+
// Evolution statements (ALTER TABLE)
|
|
56
|
+
for (const { config, existing } of evolutionConfigs) {
|
|
57
|
+
const sourceObj = input.SourceSchema.Objects.find(o => o.ExternalName === config.SourceObjectName);
|
|
58
|
+
if (!sourceObj)
|
|
59
|
+
continue;
|
|
60
|
+
const diff = this.Evolution.DiffSchema(sourceObj, config, existing, input.Platform);
|
|
61
|
+
if (diff.AddedColumns.length === 0 && diff.ModifiedColumns.length === 0 && diff.RemovedColumns.length === 0) {
|
|
62
|
+
continue; // No changes
|
|
63
|
+
}
|
|
64
|
+
ddlParts.push(this.Evolution.GenerateEvolutionMigration(diff, config.SchemaName, config.TableName, input.Platform));
|
|
65
|
+
ddlParts.push(''); // blank line separator
|
|
66
|
+
}
|
|
67
|
+
// Emit a single migration file if there's any DDL
|
|
68
|
+
if (ddlParts.some(p => p.trim().length > 0)) {
|
|
69
|
+
const tableNames = [
|
|
70
|
+
...newConfigs.map(c => c.TableName),
|
|
71
|
+
...evolutionConfigs.map(({ config }) => config.TableName),
|
|
72
|
+
];
|
|
73
|
+
const action = newConfigs.length > 0 ? 'CreateTables' : 'AlterTables';
|
|
74
|
+
const meta = this.MakeMigrationMeta(input, action, tableNames.join(', '));
|
|
75
|
+
const timestamps = this.MigrationWriter.GenerateTimestampSequence(1, now);
|
|
76
|
+
const filePath = this.MigrationWriter.GenerateMigrationFileName(input.SourceType, action, input.MJVersion, input.MigrationsDir, timestamps[0]);
|
|
77
|
+
output.MigrationFiles = [this.MigrationWriter.WrapInMigrationFile(ddlParts.join('\n'), meta, filePath)];
|
|
78
|
+
}
|
|
79
|
+
// Step 5: Generate soft PK and FK config
|
|
80
|
+
const allConfigs = [...newConfigs, ...evolutionConfigs.map(ec => ec.config)];
|
|
81
|
+
const allSoftFKs = this.CollectSoftFKs(input, evolutionConfigs);
|
|
82
|
+
// Always emit additionalSchemaInfo — every integration table needs a soft PK
|
|
83
|
+
if (allConfigs.length > 0) {
|
|
84
|
+
const existingConfig = this.SoftFKEmitter.ParseExistingConfig(null); // Caller provides existing content via input
|
|
85
|
+
// First add soft PKs (natural PK field names from source system)
|
|
86
|
+
const withPKs = this.SoftFKEmitter.MergeSoftPKs(existingConfig, allConfigs);
|
|
87
|
+
// Then merge in soft FKs
|
|
88
|
+
const merged = allSoftFKs.length > 0
|
|
89
|
+
? this.SoftFKEmitter.MergeSchemaConfig(withPKs, allSoftFKs)
|
|
90
|
+
: withPKs;
|
|
91
|
+
output.AdditionalSchemaInfoUpdate = this.SoftFKEmitter.EmitConfigFile(input.AdditionalSchemaInfoPath, merged);
|
|
92
|
+
}
|
|
93
|
+
// Step 6: Generate metadata files for __mj entity targets
|
|
94
|
+
const mjTargets = input.TargetConfigs.filter(c => c.SchemaName === '__mj');
|
|
95
|
+
if (mjTargets.length > 0) {
|
|
96
|
+
const entityNames = mjTargets.map(c => c.EntityName);
|
|
97
|
+
output.MetadataFiles.push(this.MetaEmitter.EmitEntitySettingsFile(entityNames, input.MetadataDir));
|
|
98
|
+
output.MetadataFiles.push(this.MetaEmitter.EmitMjSyncConfig(input.MetadataDir));
|
|
99
|
+
}
|
|
100
|
+
return output;
|
|
101
|
+
}
|
|
102
|
+
ValidateAccessControl(input) {
|
|
103
|
+
const errors = [];
|
|
104
|
+
for (const config of input.TargetConfigs) {
|
|
105
|
+
if (config.SchemaName === '__mj') {
|
|
106
|
+
const settings = input.EntitySettingsForTargets[config.EntityName] ?? [];
|
|
107
|
+
const result = IsIntegrationWriteAllowed(config.EntityName, config.SchemaName, settings);
|
|
108
|
+
if (!result.Allowed) {
|
|
109
|
+
errors.push(result.Reason);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return errors;
|
|
114
|
+
}
|
|
115
|
+
CheckCollisions(input) {
|
|
116
|
+
const warnings = [];
|
|
117
|
+
const existingNames = new Set(input.ExistingTables.map(t => `${t.SchemaName}.${t.TableName}`.toLowerCase()));
|
|
118
|
+
for (const config of input.TargetConfigs) {
|
|
119
|
+
const key = `${config.SchemaName}.${config.TableName}`.toLowerCase();
|
|
120
|
+
if (existingNames.has(key)) {
|
|
121
|
+
// Not necessarily an error — could be an evolution scenario
|
|
122
|
+
warnings.push(`Table ${config.SchemaName}.${config.TableName} already exists — will generate ALTER TABLE if fields differ.`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return warnings;
|
|
126
|
+
}
|
|
127
|
+
ClassifyConfigs(input) {
|
|
128
|
+
const existingMap = new Map();
|
|
129
|
+
for (const t of input.ExistingTables) {
|
|
130
|
+
existingMap.set(`${t.SchemaName}.${t.TableName}`.toLowerCase(), t);
|
|
131
|
+
}
|
|
132
|
+
const newConfigs = [];
|
|
133
|
+
const evolutionConfigs = [];
|
|
134
|
+
for (const config of input.TargetConfigs) {
|
|
135
|
+
const key = `${config.SchemaName}.${config.TableName}`.toLowerCase();
|
|
136
|
+
const existing = existingMap.get(key);
|
|
137
|
+
if (existing) {
|
|
138
|
+
evolutionConfigs.push({ config, existing });
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
newConfigs.push(config);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return { newConfigs, evolutionConfigs };
|
|
145
|
+
}
|
|
146
|
+
GetUniqueSchemas(configs) {
|
|
147
|
+
const schemas = new Set();
|
|
148
|
+
for (const config of configs) {
|
|
149
|
+
schemas.add(config.SchemaName);
|
|
150
|
+
}
|
|
151
|
+
return Array.from(schemas);
|
|
152
|
+
}
|
|
153
|
+
CollectSoftFKs(input, evolutionConfigs) {
|
|
154
|
+
// From source relationships
|
|
155
|
+
const fromSource = this.SoftFKEmitter.GenerateConfigEntries(input.SourceSchema, input.TargetConfigs);
|
|
156
|
+
// From evolution (new FK columns)
|
|
157
|
+
for (const { config, existing } of evolutionConfigs) {
|
|
158
|
+
const sourceObj = input.SourceSchema.Objects.find(o => o.ExternalName === config.SourceObjectName);
|
|
159
|
+
if (!sourceObj)
|
|
160
|
+
continue;
|
|
161
|
+
const diff = this.Evolution.DiffSchema(sourceObj, config, existing, input.Platform);
|
|
162
|
+
const newFKs = this.Evolution.GenerateEvolutionSoftFKUpdates(diff, config);
|
|
163
|
+
fromSource.push(...newFKs);
|
|
164
|
+
}
|
|
165
|
+
return fromSource;
|
|
166
|
+
}
|
|
167
|
+
MakeMigrationMeta(input, action, objectName) {
|
|
168
|
+
return {
|
|
169
|
+
SourceType: input.SourceType,
|
|
170
|
+
ObjectName: objectName,
|
|
171
|
+
Action: action,
|
|
172
|
+
GeneratedBy: 'MJ Integration Schema Builder',
|
|
173
|
+
Timestamp: new Date().toISOString(),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=SchemaBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SchemaBuilder.js","sourceRoot":"","sources":["../src/SchemaBuilder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SchemaEvolution — diff engine for detecting changes between source and existing schema.
|
|
3
|
+
* Compares source fields against existing table columns, produces incremental DDL.
|
|
4
|
+
*/
|
|
5
|
+
import type { DatabasePlatform, ExistingTableInfo, SchemaDiff, SoftFKEntry, SourceObjectInfo, TargetTableConfig } from './interfaces.js';
|
|
6
|
+
/**
|
|
7
|
+
* Computes schema diffs and generates ALTER TABLE migration SQL.
|
|
8
|
+
*/
|
|
9
|
+
export declare class SchemaEvolution {
|
|
10
|
+
private readonly DDL;
|
|
11
|
+
private readonly Mapper;
|
|
12
|
+
/**
|
|
13
|
+
* Diff a source object against an existing target table.
|
|
14
|
+
* Returns added, modified, and removed columns.
|
|
15
|
+
*/
|
|
16
|
+
DiffSchema(source: SourceObjectInfo, targetConfig: TargetTableConfig, existing: ExistingTableInfo, platform: DatabasePlatform): SchemaDiff;
|
|
17
|
+
/**
|
|
18
|
+
* Generate ALTER TABLE SQL for a schema diff.
|
|
19
|
+
*/
|
|
20
|
+
GenerateEvolutionMigration(diff: SchemaDiff, schemaName: string, tableName: string, platform: DatabasePlatform): string;
|
|
21
|
+
/**
|
|
22
|
+
* Identify new soft FK entries from a diff (for added FK columns).
|
|
23
|
+
*/
|
|
24
|
+
GenerateEvolutionSoftFKUpdates(diff: SchemaDiff, targetConfig: TargetTableConfig): SoftFKEntry[];
|
|
25
|
+
private HasColumnChanged;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=SchemaEvolution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SchemaEvolution.d.ts","sourceRoot":"","sources":["../src/SchemaEvolution.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAER,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,gBAAgB,EAEhB,iBAAiB,EACpB,MAAM,iBAAiB,CAAC;AAIzB;;GAEG;AACH,qBAAa,eAAe;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAsB;IAC1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAE3C;;;OAGG;IACH,UAAU,CACN,MAAM,EAAE,gBAAgB,EACxB,YAAY,EAAE,iBAAiB,EAC/B,QAAQ,EAAE,iBAAiB,EAC3B,QAAQ,EAAE,gBAAgB,GAC3B,UAAU;IA6Cb;;OAEG;IACH,0BAA0B,CACtB,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,gBAAgB,GAC3B,MAAM;IAkBT;;OAEG;IACH,8BAA8B,CAC1B,IAAI,EAAE,UAAU,EAChB,YAAY,EAAE,iBAAiB,GAChC,WAAW,EAAE;IAMhB,OAAO,CAAC,gBAAgB;CAS3B"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { DDLGenerator } from './DDLGenerator.js';
|
|
2
|
+
import { TypeMapper } from './TypeMapper.js';
|
|
3
|
+
/**
|
|
4
|
+
* Computes schema diffs and generates ALTER TABLE migration SQL.
|
|
5
|
+
*/
|
|
6
|
+
export class SchemaEvolution {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.DDL = new DDLGenerator();
|
|
9
|
+
this.Mapper = new TypeMapper();
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Diff a source object against an existing target table.
|
|
13
|
+
* Returns added, modified, and removed columns.
|
|
14
|
+
*/
|
|
15
|
+
DiffSchema(source, targetConfig, existing, platform) {
|
|
16
|
+
const existingNames = new Set(existing.Columns.map(c => c.Name.toLowerCase()));
|
|
17
|
+
const sourceColMap = new Map(targetConfig.Columns.map(c => [c.TargetColumnName.toLowerCase(), c]));
|
|
18
|
+
// Standard columns to ignore in the diff (managed by Schema Builder / CodeGen)
|
|
19
|
+
const standardCols = new Set(['id', 'sourcerecordid', 'sourcejson', 'syncstatus', 'lastsyncedat',
|
|
20
|
+
'__mj_createdat', '__mj_updatedat']);
|
|
21
|
+
const added = [];
|
|
22
|
+
const modified = [];
|
|
23
|
+
const removed = [];
|
|
24
|
+
// Find added and modified columns
|
|
25
|
+
for (const col of targetConfig.Columns) {
|
|
26
|
+
const lowerName = col.TargetColumnName.toLowerCase();
|
|
27
|
+
if (standardCols.has(lowerName))
|
|
28
|
+
continue;
|
|
29
|
+
if (!existingNames.has(lowerName)) {
|
|
30
|
+
added.push(col);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
const existingCol = existing.Columns.find(c => c.Name.toLowerCase() === lowerName);
|
|
34
|
+
if (existingCol && this.HasColumnChanged(existingCol, col)) {
|
|
35
|
+
modified.push({
|
|
36
|
+
ColumnName: col.TargetColumnName,
|
|
37
|
+
OldType: existingCol.SqlType,
|
|
38
|
+
NewType: col.TargetSqlType,
|
|
39
|
+
OldNullable: existingCol.IsNullable,
|
|
40
|
+
NewNullable: col.IsNullable,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Find removed columns (in existing but not in source config)
|
|
46
|
+
for (const existingCol of existing.Columns) {
|
|
47
|
+
const lowerName = existingCol.Name.toLowerCase();
|
|
48
|
+
if (standardCols.has(lowerName))
|
|
49
|
+
continue;
|
|
50
|
+
if (!sourceColMap.has(lowerName)) {
|
|
51
|
+
removed.push(existingCol.Name);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { AddedColumns: added, ModifiedColumns: modified, RemovedColumns: removed };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Generate ALTER TABLE SQL for a schema diff.
|
|
58
|
+
*/
|
|
59
|
+
GenerateEvolutionMigration(diff, schemaName, tableName, platform) {
|
|
60
|
+
const statements = [];
|
|
61
|
+
for (const col of diff.AddedColumns) {
|
|
62
|
+
statements.push(this.DDL.GenerateAlterTableAddColumn(schemaName, tableName, col, platform));
|
|
63
|
+
}
|
|
64
|
+
for (const mod of diff.ModifiedColumns) {
|
|
65
|
+
statements.push(this.DDL.GenerateAlterTableAlterColumn(schemaName, tableName, mod, platform));
|
|
66
|
+
}
|
|
67
|
+
for (const colName of diff.RemovedColumns) {
|
|
68
|
+
statements.push(`-- DEPRECATED: Column [${colName}] no longer exists in source. Consider removing after grace period.`);
|
|
69
|
+
}
|
|
70
|
+
return statements.join('\n\n');
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Identify new soft FK entries from a diff (for added FK columns).
|
|
74
|
+
*/
|
|
75
|
+
GenerateEvolutionSoftFKUpdates(diff, targetConfig) {
|
|
76
|
+
// New FK entries come from added columns that have corresponding soft FK definitions
|
|
77
|
+
const addedNames = new Set(diff.AddedColumns.map(c => c.TargetColumnName));
|
|
78
|
+
return targetConfig.SoftForeignKeys.filter(fk => addedNames.has(fk.FieldName));
|
|
79
|
+
}
|
|
80
|
+
HasColumnChanged(existing, target) {
|
|
81
|
+
// Normalize types for comparison (case-insensitive, strip whitespace)
|
|
82
|
+
const normalizedExisting = existing.SqlType.toLowerCase().replace(/\s+/g, '');
|
|
83
|
+
const normalizedTarget = target.TargetSqlType.toLowerCase().replace(/\s+/g, '');
|
|
84
|
+
if (normalizedExisting !== normalizedTarget)
|
|
85
|
+
return true;
|
|
86
|
+
if (existing.IsNullable !== target.IsNullable)
|
|
87
|
+
return true;
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=SchemaEvolution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SchemaEvolution.js","sourceRoot":"","sources":["../src/SchemaEvolution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SoftFKConfigEmitter — reads/merges additionalSchemaInfo JSON for soft PKs and FKs.
|
|
3
|
+
* File-emission only — produces updated JSON content, never writes to disk directly.
|
|
4
|
+
*/
|
|
5
|
+
import type { EmittedFile, SoftFKEntry, SourceSchemaInfo, TargetTableConfig } from './interfaces.js';
|
|
6
|
+
/** Shape of one table entry in additionalSchemaInfo. */
|
|
7
|
+
interface SchemaInfoTableEntry {
|
|
8
|
+
TableName: string;
|
|
9
|
+
PrimaryKey?: Array<{
|
|
10
|
+
FieldName: string;
|
|
11
|
+
Description?: string;
|
|
12
|
+
}>;
|
|
13
|
+
ForeignKeys?: Array<{
|
|
14
|
+
FieldName: string;
|
|
15
|
+
SchemaName: string;
|
|
16
|
+
RelatedTable: string;
|
|
17
|
+
RelatedField: string;
|
|
18
|
+
}>;
|
|
19
|
+
}
|
|
20
|
+
/** The top-level additionalSchemaInfo structure: schema name → table entries. */
|
|
21
|
+
type AdditionalSchemaInfo = Record<string, SchemaInfoTableEntry[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Manages soft PK and FK definitions in the additionalSchemaInfo JSON file.
|
|
24
|
+
*/
|
|
25
|
+
export declare class SoftFKConfigEmitter {
|
|
26
|
+
/**
|
|
27
|
+
* Parse existing additionalSchemaInfo JSON content.
|
|
28
|
+
* Returns empty object if content is empty/null.
|
|
29
|
+
*/
|
|
30
|
+
ParseExistingConfig(jsonContent: string | null): AdditionalSchemaInfo;
|
|
31
|
+
/**
|
|
32
|
+
* Merge new soft FK entries into an existing config.
|
|
33
|
+
* Deduplicates — won't add the same FK twice.
|
|
34
|
+
*/
|
|
35
|
+
MergeSchemaConfig(existing: AdditionalSchemaInfo, newEntries: SoftFKEntry[]): AdditionalSchemaInfo;
|
|
36
|
+
/**
|
|
37
|
+
* Add soft PK entries for integration tables.
|
|
38
|
+
* Uses the natural PK field name(s) from the source system. Supports composite PKs.
|
|
39
|
+
*/
|
|
40
|
+
MergeSoftPKs(existing: AdditionalSchemaInfo, targetConfigs: TargetTableConfig[]): AdditionalSchemaInfo;
|
|
41
|
+
/**
|
|
42
|
+
* Extract soft FK entries from source schema relationships + target configs.
|
|
43
|
+
* Maps source relationship field names → target column names using the target config.
|
|
44
|
+
* FKs point to the natural PK field on target tables (first PK field for composite keys).
|
|
45
|
+
*/
|
|
46
|
+
GenerateConfigEntries(sourceSchema: SourceSchemaInfo, targetConfigs: TargetTableConfig[]): SoftFKEntry[];
|
|
47
|
+
/**
|
|
48
|
+
* Produce an EmittedFile with the updated additionalSchemaInfo JSON.
|
|
49
|
+
*/
|
|
50
|
+
EmitConfigFile(configPath: string, mergedConfig: AdditionalSchemaInfo): EmittedFile;
|
|
51
|
+
}
|
|
52
|
+
export {};
|
|
53
|
+
//# sourceMappingURL=SoftFKConfigEmitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SoftFKConfigEmitter.d.ts","sourceRoot":"","sources":["../src/SoftFKConfigEmitter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAErG,wDAAwD;AACxD,UAAU,oBAAoB;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChE,WAAW,CAAC,EAAE,KAAK,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;KACxB,CAAC,CAAC;CACN;AAED,iFAAiF;AACjF,KAAK,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,oBAAoB,EAAE,CAAC,CAAC;AAEnE;;GAEG;AACH,qBAAa,mBAAmB;IAC5B;;;OAGG;IACH,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,oBAAoB;IAOrE;;;OAGG;IACH,iBAAiB,CAAC,QAAQ,EAAE,oBAAoB,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,oBAAoB;IAyClG;;;OAGG;IACH,YAAY,CAAC,QAAQ,EAAE,oBAAoB,EAAE,aAAa,EAAE,iBAAiB,EAAE,GAAG,oBAAoB;IA4BtG;;;;OAIG;IACH,qBAAqB,CACjB,YAAY,EAAE,gBAAgB,EAC9B,aAAa,EAAE,iBAAiB,EAAE,GACnC,WAAW,EAAE;IAyDhB;;OAEG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,oBAAoB,GAAG,WAAW;CAOtF"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages soft PK and FK definitions in the additionalSchemaInfo JSON file.
|
|
3
|
+
*/
|
|
4
|
+
export class SoftFKConfigEmitter {
|
|
5
|
+
/**
|
|
6
|
+
* Parse existing additionalSchemaInfo JSON content.
|
|
7
|
+
* Returns empty object if content is empty/null.
|
|
8
|
+
*/
|
|
9
|
+
ParseExistingConfig(jsonContent) {
|
|
10
|
+
if (!jsonContent || jsonContent.trim() === '') {
|
|
11
|
+
return {};
|
|
12
|
+
}
|
|
13
|
+
return JSON.parse(jsonContent);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Merge new soft FK entries into an existing config.
|
|
17
|
+
* Deduplicates — won't add the same FK twice.
|
|
18
|
+
*/
|
|
19
|
+
MergeSchemaConfig(existing, newEntries) {
|
|
20
|
+
const result = JSON.parse(JSON.stringify(existing));
|
|
21
|
+
for (const entry of newEntries) {
|
|
22
|
+
if (!result[entry.SchemaName]) {
|
|
23
|
+
result[entry.SchemaName] = [];
|
|
24
|
+
}
|
|
25
|
+
const schemaEntries = result[entry.SchemaName];
|
|
26
|
+
let tableEntry = schemaEntries.find(t => t.TableName === entry.TableName);
|
|
27
|
+
if (!tableEntry) {
|
|
28
|
+
tableEntry = { TableName: entry.TableName, ForeignKeys: [] };
|
|
29
|
+
schemaEntries.push(tableEntry);
|
|
30
|
+
}
|
|
31
|
+
if (!tableEntry.ForeignKeys) {
|
|
32
|
+
tableEntry.ForeignKeys = [];
|
|
33
|
+
}
|
|
34
|
+
// Deduplicate: skip if this exact FK already exists
|
|
35
|
+
const exists = tableEntry.ForeignKeys.some(fk => fk.FieldName === entry.FieldName &&
|
|
36
|
+
fk.SchemaName === entry.TargetSchemaName &&
|
|
37
|
+
fk.RelatedTable === entry.TargetTableName &&
|
|
38
|
+
fk.RelatedField === entry.TargetFieldName);
|
|
39
|
+
if (!exists) {
|
|
40
|
+
tableEntry.ForeignKeys.push({
|
|
41
|
+
FieldName: entry.FieldName,
|
|
42
|
+
SchemaName: entry.TargetSchemaName,
|
|
43
|
+
RelatedTable: entry.TargetTableName,
|
|
44
|
+
RelatedField: entry.TargetFieldName,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Add soft PK entries for integration tables.
|
|
52
|
+
* Uses the natural PK field name(s) from the source system. Supports composite PKs.
|
|
53
|
+
*/
|
|
54
|
+
MergeSoftPKs(existing, targetConfigs) {
|
|
55
|
+
const result = JSON.parse(JSON.stringify(existing));
|
|
56
|
+
for (const config of targetConfigs) {
|
|
57
|
+
if (config.PrimaryKeyFields.length === 0)
|
|
58
|
+
continue;
|
|
59
|
+
if (!result[config.SchemaName]) {
|
|
60
|
+
result[config.SchemaName] = [];
|
|
61
|
+
}
|
|
62
|
+
const schemaEntries = result[config.SchemaName];
|
|
63
|
+
let tableEntry = schemaEntries.find(t => t.TableName === config.TableName);
|
|
64
|
+
if (!tableEntry) {
|
|
65
|
+
tableEntry = { TableName: config.TableName };
|
|
66
|
+
schemaEntries.push(tableEntry);
|
|
67
|
+
}
|
|
68
|
+
// Set soft PK to the natural PK field(s) from the source system
|
|
69
|
+
tableEntry.PrimaryKey = config.PrimaryKeyFields.map(fieldName => ({
|
|
70
|
+
FieldName: fieldName,
|
|
71
|
+
Description: `Primary key from source system`,
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Extract soft FK entries from source schema relationships + target configs.
|
|
78
|
+
* Maps source relationship field names → target column names using the target config.
|
|
79
|
+
* FKs point to the natural PK field on target tables (first PK field for composite keys).
|
|
80
|
+
*/
|
|
81
|
+
GenerateConfigEntries(sourceSchema, targetConfigs) {
|
|
82
|
+
const entries = [];
|
|
83
|
+
// Also collect entries already defined directly on TargetTableConfig
|
|
84
|
+
for (const config of targetConfigs) {
|
|
85
|
+
if (config.SoftForeignKeys) {
|
|
86
|
+
entries.push(...config.SoftForeignKeys);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Build a map of source object name → target config for FK resolution
|
|
90
|
+
const sourceToTarget = new Map();
|
|
91
|
+
for (const config of targetConfigs) {
|
|
92
|
+
sourceToTarget.set(config.SourceObjectName, config);
|
|
93
|
+
}
|
|
94
|
+
// Walk source relationships and map them to target columns
|
|
95
|
+
for (const sourceObj of sourceSchema.Objects) {
|
|
96
|
+
const targetConfig = sourceToTarget.get(sourceObj.ExternalName);
|
|
97
|
+
if (!targetConfig)
|
|
98
|
+
continue;
|
|
99
|
+
for (const rel of sourceObj.Relationships) {
|
|
100
|
+
const targetOfFK = sourceToTarget.get(rel.TargetObject);
|
|
101
|
+
if (!targetOfFK)
|
|
102
|
+
continue; // Target object not being imported
|
|
103
|
+
// Find the mapped column name for this FK field
|
|
104
|
+
const columnConfig = targetConfig.Columns.find(c => c.SourceFieldName === rel.FieldName);
|
|
105
|
+
const columnName = columnConfig ? columnConfig.TargetColumnName : rel.FieldName;
|
|
106
|
+
// FK points to the natural PK field on the target table
|
|
107
|
+
const targetPKField = targetOfFK.PrimaryKeyFields[0];
|
|
108
|
+
if (!targetPKField)
|
|
109
|
+
continue; // Target has no PK — skip FK
|
|
110
|
+
const entry = {
|
|
111
|
+
SchemaName: targetConfig.SchemaName,
|
|
112
|
+
TableName: targetConfig.TableName,
|
|
113
|
+
FieldName: columnName,
|
|
114
|
+
TargetSchemaName: targetOfFK.SchemaName,
|
|
115
|
+
TargetTableName: targetOfFK.TableName,
|
|
116
|
+
TargetFieldName: targetPKField,
|
|
117
|
+
};
|
|
118
|
+
// Deduplicate against already-added entries
|
|
119
|
+
const alreadyAdded = entries.some(e => e.SchemaName === entry.SchemaName &&
|
|
120
|
+
e.TableName === entry.TableName &&
|
|
121
|
+
e.FieldName === entry.FieldName);
|
|
122
|
+
if (!alreadyAdded) {
|
|
123
|
+
entries.push(entry);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return entries;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Produce an EmittedFile with the updated additionalSchemaInfo JSON.
|
|
131
|
+
*/
|
|
132
|
+
EmitConfigFile(configPath, mergedConfig) {
|
|
133
|
+
return {
|
|
134
|
+
FilePath: configPath,
|
|
135
|
+
Content: JSON.stringify(mergedConfig, null, 4) + '\n',
|
|
136
|
+
Description: 'Updated additionalSchemaInfo with soft PK and FK definitions for integration tables',
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=SoftFKConfigEmitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SoftFKConfigEmitter.js","sourceRoot":"","sources":["../src/SoftFKConfigEmitter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeMapper — converts generic source types to platform-specific SQL types.
|
|
3
|
+
*/
|
|
4
|
+
import type { DatabasePlatform, SourceFieldInfo, TypeMappingEntry } from './interfaces.js';
|
|
5
|
+
/**
|
|
6
|
+
* Maps generic source field types to platform-specific SQL types.
|
|
7
|
+
*/
|
|
8
|
+
export declare class TypeMapper {
|
|
9
|
+
/**
|
|
10
|
+
* Convert a source field's type to the appropriate SQL type for the given platform.
|
|
11
|
+
*/
|
|
12
|
+
MapSourceType(sourceType: string, platform: DatabasePlatform, field: SourceFieldInfo): string;
|
|
13
|
+
/**
|
|
14
|
+
* Get the MJ EntityField.Type value for a source type (informational only).
|
|
15
|
+
*/
|
|
16
|
+
GetMJFieldType(sourceType: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Get all supported type mappings.
|
|
19
|
+
*/
|
|
20
|
+
GetAllMappings(): ReadonlyArray<TypeMappingEntry>;
|
|
21
|
+
private ApplyPrecision;
|
|
22
|
+
private ApplyStringLength;
|
|
23
|
+
private ApplyDecimalPrecision;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=TypeMapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypeMapper.d.ts","sourceRoot":"","sources":["../src/TypeMapper.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAiB3F;;GAEG;AACH,qBAAa,UAAU;IACnB;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM;IAa7F;;OAEG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAM1C;;OAEG;IACH,cAAc,IAAI,aAAa,CAAC,gBAAgB,CAAC;IAIjD,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,qBAAqB;CAKhC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const TYPE_MAP = [
|
|
2
|
+
{ SourceType: 'string', SqlServerType: 'NVARCHAR', PostgresType: 'VARCHAR', MJFieldType: 'nvarchar' },
|
|
3
|
+
{ SourceType: 'text', SqlServerType: 'NVARCHAR(MAX)', PostgresType: 'TEXT', MJFieldType: 'nvarchar' },
|
|
4
|
+
{ SourceType: 'integer', SqlServerType: 'INT', PostgresType: 'INTEGER', MJFieldType: 'int' },
|
|
5
|
+
{ SourceType: 'bigint', SqlServerType: 'BIGINT', PostgresType: 'BIGINT', MJFieldType: 'bigint' },
|
|
6
|
+
{ SourceType: 'decimal', SqlServerType: 'DECIMAL', PostgresType: 'NUMERIC', MJFieldType: 'decimal' },
|
|
7
|
+
{ SourceType: 'boolean', SqlServerType: 'BIT', PostgresType: 'BOOLEAN', MJFieldType: 'bit' },
|
|
8
|
+
{ SourceType: 'datetime', SqlServerType: 'DATETIMEOFFSET', PostgresType: 'TIMESTAMPTZ', MJFieldType: 'datetimeoffset' },
|
|
9
|
+
{ SourceType: 'date', SqlServerType: 'DATE', PostgresType: 'DATE', MJFieldType: 'date' },
|
|
10
|
+
{ SourceType: 'uuid', SqlServerType: 'UNIQUEIDENTIFIER', PostgresType: 'UUID', MJFieldType: 'uniqueidentifier' },
|
|
11
|
+
{ SourceType: 'json', SqlServerType: 'NVARCHAR(MAX)', PostgresType: 'JSONB', MJFieldType: 'nvarchar' },
|
|
12
|
+
{ SourceType: 'float', SqlServerType: 'FLOAT', PostgresType: 'DOUBLE PRECISION', MJFieldType: 'float' },
|
|
13
|
+
{ SourceType: 'time', SqlServerType: 'TIME', PostgresType: 'TIME', MJFieldType: 'time' },
|
|
14
|
+
];
|
|
15
|
+
/**
|
|
16
|
+
* Maps generic source field types to platform-specific SQL types.
|
|
17
|
+
*/
|
|
18
|
+
export class TypeMapper {
|
|
19
|
+
/**
|
|
20
|
+
* Convert a source field's type to the appropriate SQL type for the given platform.
|
|
21
|
+
*/
|
|
22
|
+
MapSourceType(sourceType, platform, field) {
|
|
23
|
+
const normalized = sourceType.toLowerCase().trim();
|
|
24
|
+
const entry = TYPE_MAP.find(t => t.SourceType === normalized);
|
|
25
|
+
if (!entry) {
|
|
26
|
+
// Unknown type — fall back to text
|
|
27
|
+
return platform === 'sqlserver' ? 'NVARCHAR(MAX)' : 'TEXT';
|
|
28
|
+
}
|
|
29
|
+
const baseType = platform === 'sqlserver' ? entry.SqlServerType : entry.PostgresType;
|
|
30
|
+
return this.ApplyPrecision(baseType, normalized, field, platform);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get the MJ EntityField.Type value for a source type (informational only).
|
|
34
|
+
*/
|
|
35
|
+
GetMJFieldType(sourceType) {
|
|
36
|
+
const normalized = sourceType.toLowerCase().trim();
|
|
37
|
+
const entry = TYPE_MAP.find(t => t.SourceType === normalized);
|
|
38
|
+
return entry ? entry.MJFieldType : 'nvarchar';
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get all supported type mappings.
|
|
42
|
+
*/
|
|
43
|
+
GetAllMappings() {
|
|
44
|
+
return TYPE_MAP;
|
|
45
|
+
}
|
|
46
|
+
ApplyPrecision(baseType, sourceType, field, platform) {
|
|
47
|
+
if (sourceType === 'string') {
|
|
48
|
+
return this.ApplyStringLength(baseType, field, platform);
|
|
49
|
+
}
|
|
50
|
+
if (sourceType === 'decimal') {
|
|
51
|
+
return this.ApplyDecimalPrecision(baseType, field);
|
|
52
|
+
}
|
|
53
|
+
return baseType;
|
|
54
|
+
}
|
|
55
|
+
ApplyStringLength(baseType, field, platform) {
|
|
56
|
+
if (field.MaxLength != null && field.MaxLength > 0) {
|
|
57
|
+
// SQL Server NVARCHAR max is 4000 before switching to MAX; PG VARCHAR has no practical limit
|
|
58
|
+
if (platform === 'sqlserver' && field.MaxLength > 4000) {
|
|
59
|
+
return 'NVARCHAR(MAX)';
|
|
60
|
+
}
|
|
61
|
+
return `${baseType}(${field.MaxLength})`;
|
|
62
|
+
}
|
|
63
|
+
// Default string length
|
|
64
|
+
return `${baseType}(255)`;
|
|
65
|
+
}
|
|
66
|
+
ApplyDecimalPrecision(baseType, field) {
|
|
67
|
+
const precision = field.Precision ?? 18;
|
|
68
|
+
const scale = field.Scale ?? 2;
|
|
69
|
+
return `${baseType}(${precision},${scale})`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=TypeMapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypeMapper.js","sourceRoot":"","sources":["../src/TypeMapper.ts"],"names":[],"mappings":"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"}
|