mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-29 06:26:00 +00:00
duplicator wek refs WIP
This commit is contained in:
@@ -91,4 +91,65 @@ describe('Data duplicator', () => {
|
|||||||
expect(res2.rows[0].cnt.toString()).toEqual('6');
|
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');
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export interface DataDuplicatorItem {
|
|||||||
export interface DataDuplicatorOptions {
|
export interface DataDuplicatorOptions {
|
||||||
rollbackAfterFinish?: boolean;
|
rollbackAfterFinish?: boolean;
|
||||||
skipRowsWithUnresolvedRefs?: boolean;
|
skipRowsWithUnresolvedRefs?: boolean;
|
||||||
|
setNullForUnresolvedNullableRefs?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class DuplicatorReference {
|
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 {
|
class DuplicatorItemHolder {
|
||||||
references: DuplicatorReference[] = [];
|
references: DuplicatorReference[] = [];
|
||||||
backReferences: DuplicatorReference[] = [];
|
backReferences: DuplicatorReference[] = [];
|
||||||
|
// not mandatory references to entities out of the model
|
||||||
|
weakReferences: DuplicatorWeakReference[] = [];
|
||||||
table: TableInfo;
|
table: TableInfo;
|
||||||
isPlanned = false;
|
isPlanned = false;
|
||||||
idMap = {};
|
idMap = {};
|
||||||
@@ -65,8 +76,13 @@ class DuplicatorItemHolder {
|
|||||||
for (const fk of this.table.foreignKeys) {
|
for (const fk of this.table.foreignKeys) {
|
||||||
if (fk.columns?.length != 1) continue;
|
if (fk.columns?.length != 1) continue;
|
||||||
const refHolder = this.duplicator.itemHolders.find(y => y.name.toUpperCase() == fk.refTableName.toUpperCase());
|
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 isMandatory = this.table.columns.find(x => x.columnName == fk.columns[0]?.columnName)?.notNull;
|
||||||
|
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);
|
const newref = new DuplicatorReference(this, refHolder, isMandatory, fk);
|
||||||
this.references.push(newref);
|
this.references.push(newref);
|
||||||
this.refByColumn[newref.columnName] = newref;
|
this.refByColumn[newref.columnName] = newref;
|
||||||
@@ -74,6 +90,7 @@ class DuplicatorItemHolder {
|
|||||||
refHolder.isReferenced = true;
|
refHolder.isReferenced = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
createInsertObject(chunk) {
|
createInsertObject(chunk) {
|
||||||
const res = _omit(
|
const res = _omit(
|
||||||
|
|||||||
@@ -286,6 +286,29 @@
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</FormFieldTemplateLarge>
|
</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>
|
||||||
|
|
||||||
<ObjectConfigurationControl title="Imported files">
|
<ObjectConfigurationControl title="Imported files">
|
||||||
|
|||||||
Reference in New Issue
Block a user