duplicator wek refs WIP

This commit is contained in:
SPRINX0\prochazka
2024-11-07 13:15:33 +01:00
parent 7aaf6bb024
commit cb450a0313
3 changed files with 106 additions and 5 deletions

View File

@@ -91,4 +91,65 @@ describe('Data duplicator', () => {
expect(res2.rows[0].cnt.toString()).toEqual('6');
})
);
test.each(engines.filter(x => !x.skipDataDuplicator).map(engine => [engine.label, engine]))(
'Skip nullable weak refs - %s',
testWrapper(async (conn, driver, engine) => {
runCommandOnDriver(conn, driver, dmp =>
dmp.createTable({
pureName: 't1',
columns: [
{ columnName: 'id', dataType: 'int', notNull: true },
{ columnName: 'val', dataType: 'varchar(50)' },
],
primaryKey: {
columns: [{ columnName: 'id' }],
},
})
);
runCommandOnDriver(conn, driver, dmp =>
dmp.createTable({
pureName: 't2',
columns: [
{ columnName: 'id', dataType: 'int', autoIncrement: true, notNull: true },
{ columnName: 'val', dataType: 'varchar(50)' },
{ columnName: 'valfk', dataType: 'int', notNull: false },
],
primaryKey: {
columns: [{ columnName: 'id' }],
},
foreignKeys: [{ refTableName: 't1', columns: [{ columnName: 'valfk', refColumnName: 'id' }] }],
})
);
runCommandOnDriver(conn, driver, dmp => dmp.put("insert into ~t1 (~id, ~val) ~values (1, 'first')"));
const gett2 = () =>
stream.Readable.from([
{ __isStreamHeader: true, __isDynamicStructure: true },
{ id: 1, val: 'v1', valfk: 1 },
{ id: 2, val: 'v2', valfk: 2 },
]);
await dataDuplicator({
systemConnection: conn,
driver,
items: [
{
name: 't2',
operation: 'copy',
openStream: gett2,
},
],
options: {
setNullForUnresolvedNullableRefs: true,
},
});
const res1 = await driver.query(conn, `select count(*) as cnt from t1`);
expect(res1.rows[0].cnt.toString()).toEqual('1');
const res2 = await driver.query(conn, `select count(*) as cnt from t2`);
expect(res2.rows[0].cnt.toString()).toEqual('1');
})
);
});

View File

@@ -21,6 +21,7 @@ export interface DataDuplicatorItem {
export interface DataDuplicatorOptions {
rollbackAfterFinish?: boolean;
skipRowsWithUnresolvedRefs?: boolean;
setNullForUnresolvedNullableRefs?: boolean;
}
class DuplicatorReference {
@@ -36,9 +37,19 @@ class DuplicatorReference {
}
}
class DuplicatorWeakReference {
constructor(public base: DuplicatorItemHolder, public ref: TableInfo, public foreignKey: ForeignKeyInfo) {}
get columnName() {
return this.foreignKey.columns[0].columnName;
}
}
class DuplicatorItemHolder {
references: DuplicatorReference[] = [];
backReferences: DuplicatorReference[] = [];
// not mandatory references to entities out of the model
weakReferences: DuplicatorWeakReference[] = [];
table: TableInfo;
isPlanned = false;
idMap = {};
@@ -65,13 +76,19 @@ class DuplicatorItemHolder {
for (const fk of this.table.foreignKeys) {
if (fk.columns?.length != 1) continue;
const refHolder = this.duplicator.itemHolders.find(y => y.name.toUpperCase() == fk.refTableName.toUpperCase());
if (refHolder == null) continue;
const isMandatory = this.table.columns.find(x => x.columnName == fk.columns[0]?.columnName)?.notNull;
const newref = new DuplicatorReference(this, refHolder, isMandatory, fk);
this.references.push(newref);
this.refByColumn[newref.columnName] = newref;
if (refHolder == null) {
if (!isMandatory) {
const weakref = new DuplicatorWeakReference(this, this.duplicator.db.tables.find(x => x.pureName == fk.refTableName), fk);
this.weakReferences.push(weakref);
}
} else {
const newref = new DuplicatorReference(this, refHolder, isMandatory, fk);
this.references.push(newref);
this.refByColumn[newref.columnName] = newref;
refHolder.isReferenced = true;
refHolder.isReferenced = true;
}
}
}

View File

@@ -286,6 +286,29 @@
}}
/>
</FormFieldTemplateLarge>
<FormFieldTemplateLarge
label="Set NULL for nullable unresolved references"
type="checkbox"
labelProps={{
onClick: () => {
setEditorData(old => ({
...old,
setNullForUnresolvedNullableRefs: !$editorState.value?.setNullForUnresolvedNullableRefs,
}));
},
}}
>
<CheckboxField
checked={$editorState.value?.setNullForUnresolvedNullableRefs}
on:change={e => {
setEditorData(old => ({
...old,
setNullForUnresolvedNullableRefs: e.target.checked,
}));
}}
/>
</FormFieldTemplateLarge>
</ObjectConfigurationControl>
<ObjectConfigurationControl title="Imported files">