diff --git a/integration-tests/__tests__/data-duplicator.spec.js b/integration-tests/__tests__/data-duplicator.spec.js
index 7d5c532e5..81444830a 100644
--- a/integration-tests/__tests__/data-duplicator.spec.js
+++ b/integration-tests/__tests__/data-duplicator.spec.js
@@ -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');
+ })
+ );
});
diff --git a/packages/datalib/src/DataDuplicator.ts b/packages/datalib/src/DataDuplicator.ts
index 421ada4ee..c2b4d6cce 100644
--- a/packages/datalib/src/DataDuplicator.ts
+++ b/packages/datalib/src/DataDuplicator.ts
@@ -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;
+ }
}
}
diff --git a/packages/web/src/tabs/DataDuplicatorTab.svelte b/packages/web/src/tabs/DataDuplicatorTab.svelte
index 562eaa5ae..12259b825 100644
--- a/packages/web/src/tabs/DataDuplicatorTab.svelte
+++ b/packages/web/src/tabs/DataDuplicatorTab.svelte
@@ -286,6 +286,29 @@
}}
/>
+
+ {
+ setEditorData(old => ({
+ ...old,
+ setNullForUnresolvedNullableRefs: !$editorState.value?.setNullForUnresolvedNullableRefs,
+ }));
+ },
+ }}
+ >
+ {
+ setEditorData(old => ({
+ ...old,
+ setNullForUnresolvedNullableRefs: e.target.checked,
+ }));
+ }}
+ />
+