mirror of
https://github.com/chartdb/chartdb.git
synced 2025-11-09 08:25:57 +00:00
Compare commits
1 Commits
v1.14.0
...
jf/fix_fk_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1377bd524b |
@@ -232,14 +232,50 @@ export function exportMSSQL(diagram: Diagram): string {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const sourceTableName = sourceTable.schema
|
// Determine which table should have the foreign key based on cardinality
|
||||||
? `[${sourceTable.schema}].[${sourceTable.name}]`
|
let fkTable, fkField, refTable, refField;
|
||||||
: `[${sourceTable.name}]`;
|
|
||||||
const targetTableName = targetTable.schema
|
|
||||||
? `[${targetTable.schema}].[${targetTable.name}]`
|
|
||||||
: `[${targetTable.name}]`;
|
|
||||||
|
|
||||||
return `ALTER TABLE ${sourceTableName}\nADD CONSTRAINT [${r.name}] FOREIGN KEY([${sourceField.name}]) REFERENCES ${targetTableName}([${targetField.name}]);\n`;
|
if (
|
||||||
|
r.sourceCardinality === 'one' &&
|
||||||
|
r.targetCardinality === 'many'
|
||||||
|
) {
|
||||||
|
// FK goes on target table
|
||||||
|
fkTable = targetTable;
|
||||||
|
fkField = targetField;
|
||||||
|
refTable = sourceTable;
|
||||||
|
refField = sourceField;
|
||||||
|
} else if (
|
||||||
|
r.sourceCardinality === 'many' &&
|
||||||
|
r.targetCardinality === 'one'
|
||||||
|
) {
|
||||||
|
// FK goes on source table
|
||||||
|
fkTable = sourceTable;
|
||||||
|
fkField = sourceField;
|
||||||
|
refTable = targetTable;
|
||||||
|
refField = targetField;
|
||||||
|
} else if (
|
||||||
|
r.sourceCardinality === 'one' &&
|
||||||
|
r.targetCardinality === 'one'
|
||||||
|
) {
|
||||||
|
// For 1:1, FK can go on either side, but typically goes on the table that references the other
|
||||||
|
// We'll keep the current behavior for 1:1
|
||||||
|
fkTable = sourceTable;
|
||||||
|
fkField = sourceField;
|
||||||
|
refTable = targetTable;
|
||||||
|
refField = targetField;
|
||||||
|
} else {
|
||||||
|
// Many-to-many relationships need a junction table, skip for now
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const fkTableName = fkTable.schema
|
||||||
|
? `[${fkTable.schema}].[${fkTable.name}]`
|
||||||
|
: `[${fkTable.name}]`;
|
||||||
|
const refTableName = refTable.schema
|
||||||
|
? `[${refTable.schema}].[${refTable.name}]`
|
||||||
|
: `[${refTable.name}]`;
|
||||||
|
|
||||||
|
return `ALTER TABLE ${fkTableName}\nADD CONSTRAINT [${r.name}] FOREIGN KEY([${fkField.name}]) REFERENCES ${refTableName}([${refField.name}]);\n`;
|
||||||
})
|
})
|
||||||
.filter(Boolean) // Remove empty strings
|
.filter(Boolean) // Remove empty strings
|
||||||
.join('\n')}`;
|
.join('\n')}`;
|
||||||
|
|||||||
@@ -425,18 +425,54 @@ export function exportMySQL(diagram: Diagram): string {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const sourceTableName = sourceTable.schema
|
// Determine which table should have the foreign key based on cardinality
|
||||||
? `\`${sourceTable.schema}\`.\`${sourceTable.name}\``
|
let fkTable, fkField, refTable, refField;
|
||||||
: `\`${sourceTable.name}\``;
|
|
||||||
const targetTableName = targetTable.schema
|
if (
|
||||||
? `\`${targetTable.schema}\`.\`${targetTable.name}\``
|
r.sourceCardinality === 'one' &&
|
||||||
: `\`${targetTable.name}\``;
|
r.targetCardinality === 'many'
|
||||||
|
) {
|
||||||
|
// FK goes on target table
|
||||||
|
fkTable = targetTable;
|
||||||
|
fkField = targetField;
|
||||||
|
refTable = sourceTable;
|
||||||
|
refField = sourceField;
|
||||||
|
} else if (
|
||||||
|
r.sourceCardinality === 'many' &&
|
||||||
|
r.targetCardinality === 'one'
|
||||||
|
) {
|
||||||
|
// FK goes on source table
|
||||||
|
fkTable = sourceTable;
|
||||||
|
fkField = sourceField;
|
||||||
|
refTable = targetTable;
|
||||||
|
refField = targetField;
|
||||||
|
} else if (
|
||||||
|
r.sourceCardinality === 'one' &&
|
||||||
|
r.targetCardinality === 'one'
|
||||||
|
) {
|
||||||
|
// For 1:1, FK can go on either side, but typically goes on the table that references the other
|
||||||
|
// We'll keep the current behavior for 1:1
|
||||||
|
fkTable = sourceTable;
|
||||||
|
fkField = sourceField;
|
||||||
|
refTable = targetTable;
|
||||||
|
refField = targetField;
|
||||||
|
} else {
|
||||||
|
// Many-to-many relationships need a junction table, skip for now
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const fkTableName = fkTable.schema
|
||||||
|
? `\`${fkTable.schema}\`.\`${fkTable.name}\``
|
||||||
|
: `\`${fkTable.name}\``;
|
||||||
|
const refTableName = refTable.schema
|
||||||
|
? `\`${refTable.schema}\`.\`${refTable.name}\``
|
||||||
|
: `\`${refTable.name}\``;
|
||||||
|
|
||||||
// Create a descriptive constraint name
|
// Create a descriptive constraint name
|
||||||
const constraintName = `\`fk_${sourceTable.name}_${sourceField.name}\``;
|
const constraintName = `\`fk_${fkTable.name}_${fkField.name}\``;
|
||||||
|
|
||||||
// MySQL supports ON DELETE and ON UPDATE actions
|
// MySQL supports ON DELETE and ON UPDATE actions
|
||||||
return `ALTER TABLE ${sourceTableName}\nADD CONSTRAINT ${constraintName} FOREIGN KEY(\`${sourceField.name}\`) REFERENCES ${targetTableName}(\`${targetField.name}\`)\nON UPDATE CASCADE ON DELETE RESTRICT;\n`;
|
return `ALTER TABLE ${fkTableName}\nADD CONSTRAINT ${constraintName} FOREIGN KEY(\`${fkField.name}\`) REFERENCES ${refTableName}(\`${refField.name}\`)\nON UPDATE CASCADE ON DELETE RESTRICT;\n`;
|
||||||
})
|
})
|
||||||
.filter(Boolean) // Remove empty strings
|
.filter(Boolean) // Remove empty strings
|
||||||
.join('\n');
|
.join('\n');
|
||||||
|
|||||||
@@ -417,17 +417,53 @@ export function exportPostgreSQL(diagram: Diagram): string {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const sourceTableName = sourceTable.schema
|
// Determine which table should have the foreign key based on cardinality
|
||||||
? `"${sourceTable.schema}"."${sourceTable.name}"`
|
let fkTable, fkField, refTable, refField;
|
||||||
: `"${sourceTable.name}"`;
|
|
||||||
const targetTableName = targetTable.schema
|
if (
|
||||||
? `"${targetTable.schema}"."${targetTable.name}"`
|
r.sourceCardinality === 'one' &&
|
||||||
: `"${targetTable.name}"`;
|
r.targetCardinality === 'many'
|
||||||
|
) {
|
||||||
|
// FK goes on target table
|
||||||
|
fkTable = targetTable;
|
||||||
|
fkField = targetField;
|
||||||
|
refTable = sourceTable;
|
||||||
|
refField = sourceField;
|
||||||
|
} else if (
|
||||||
|
r.sourceCardinality === 'many' &&
|
||||||
|
r.targetCardinality === 'one'
|
||||||
|
) {
|
||||||
|
// FK goes on source table
|
||||||
|
fkTable = sourceTable;
|
||||||
|
fkField = sourceField;
|
||||||
|
refTable = targetTable;
|
||||||
|
refField = targetField;
|
||||||
|
} else if (
|
||||||
|
r.sourceCardinality === 'one' &&
|
||||||
|
r.targetCardinality === 'one'
|
||||||
|
) {
|
||||||
|
// For 1:1, FK can go on either side, but typically goes on the table that references the other
|
||||||
|
// We'll keep the current behavior for 1:1
|
||||||
|
fkTable = sourceTable;
|
||||||
|
fkField = sourceField;
|
||||||
|
refTable = targetTable;
|
||||||
|
refField = targetField;
|
||||||
|
} else {
|
||||||
|
// Many-to-many relationships need a junction table, skip for now
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const fkTableName = fkTable.schema
|
||||||
|
? `"${fkTable.schema}"."${fkTable.name}"`
|
||||||
|
: `"${fkTable.name}"`;
|
||||||
|
const refTableName = refTable.schema
|
||||||
|
? `"${refTable.schema}"."${refTable.name}"`
|
||||||
|
: `"${refTable.name}"`;
|
||||||
|
|
||||||
// Create a unique constraint name by combining table and field names
|
// Create a unique constraint name by combining table and field names
|
||||||
// Ensure it stays within PostgreSQL's 63-character limit for identifiers
|
// Ensure it stays within PostgreSQL's 63-character limit for identifiers
|
||||||
// and doesn't get truncated in a way that breaks SQL syntax
|
// and doesn't get truncated in a way that breaks SQL syntax
|
||||||
const baseName = `fk_${sourceTable.name}_${sourceField.name}_${targetTable.name}_${targetField.name}`;
|
const baseName = `fk_${fkTable.name}_${fkField.name}_${refTable.name}_${refField.name}`;
|
||||||
// Limit to 60 chars (63 minus quotes) to ensure the whole identifier stays within limits
|
// Limit to 60 chars (63 minus quotes) to ensure the whole identifier stays within limits
|
||||||
const safeConstraintName =
|
const safeConstraintName =
|
||||||
baseName.length > 60
|
baseName.length > 60
|
||||||
@@ -436,7 +472,7 @@ export function exportPostgreSQL(diagram: Diagram): string {
|
|||||||
|
|
||||||
const constraintName = `"${safeConstraintName}"`;
|
const constraintName = `"${safeConstraintName}"`;
|
||||||
|
|
||||||
return `ALTER TABLE ${sourceTableName}\nADD CONSTRAINT ${constraintName} FOREIGN KEY("${sourceField.name}") REFERENCES ${targetTableName}("${targetField.name}");\n`;
|
return `ALTER TABLE ${fkTableName}\nADD CONSTRAINT ${constraintName} FOREIGN KEY("${fkField.name}") REFERENCES ${refTableName}("${refField.name}");\n`;
|
||||||
})
|
})
|
||||||
.filter(Boolean) // Remove empty strings
|
.filter(Boolean) // Remove empty strings
|
||||||
.join('\n')}`;
|
.join('\n')}`;
|
||||||
|
|||||||
@@ -347,8 +347,44 @@ export function exportSQLite(diagram: Diagram): string {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine which table should have the foreign key based on cardinality
|
||||||
|
let fkTable, fkField, refTable, refField;
|
||||||
|
|
||||||
|
if (
|
||||||
|
r.sourceCardinality === 'one' &&
|
||||||
|
r.targetCardinality === 'many'
|
||||||
|
) {
|
||||||
|
// FK goes on target table
|
||||||
|
fkTable = targetTable;
|
||||||
|
fkField = targetField;
|
||||||
|
refTable = sourceTable;
|
||||||
|
refField = sourceField;
|
||||||
|
} else if (
|
||||||
|
r.sourceCardinality === 'many' &&
|
||||||
|
r.targetCardinality === 'one'
|
||||||
|
) {
|
||||||
|
// FK goes on source table
|
||||||
|
fkTable = sourceTable;
|
||||||
|
fkField = sourceField;
|
||||||
|
refTable = targetTable;
|
||||||
|
refField = targetField;
|
||||||
|
} else if (
|
||||||
|
r.sourceCardinality === 'one' &&
|
||||||
|
r.targetCardinality === 'one'
|
||||||
|
) {
|
||||||
|
// For 1:1, FK can go on either side, but typically goes on the table that references the other
|
||||||
|
// We'll keep the current behavior for 1:1
|
||||||
|
fkTable = sourceTable;
|
||||||
|
fkField = sourceField;
|
||||||
|
refTable = targetTable;
|
||||||
|
refField = targetField;
|
||||||
|
} else {
|
||||||
|
// Many-to-many relationships need a junction table, skip for now
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Create commented out version of what would be ALTER TABLE statement
|
// Create commented out version of what would be ALTER TABLE statement
|
||||||
sqlScript += `-- ALTER TABLE "${sourceTable.name}" ADD CONSTRAINT "fk_${sourceTable.name}_${sourceField.name}" FOREIGN KEY("${sourceField.name}") REFERENCES "${targetTable.name}"("${targetField.name}");\n`;
|
sqlScript += `-- ALTER TABLE "${fkTable.name}" ADD CONSTRAINT "fk_${fkTable.name}_${fkField.name}" FOREIGN KEY("${fkField.name}") REFERENCES "${refTable.name}"("${refField.name}");\n`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -373,13 +373,52 @@ export const exportBaseSQL = ({
|
|||||||
sourceTableField &&
|
sourceTableField &&
|
||||||
targetTableField
|
targetTableField
|
||||||
) {
|
) {
|
||||||
const sourceTableName = sourceTable.schema
|
// Determine which table should have the foreign key based on cardinality
|
||||||
? `${sourceTable.schema}.${sourceTable.name}`
|
// In a 1:many relationship, the foreign key goes on the "many" side
|
||||||
: sourceTable.name;
|
// If source is "one" and target is "many", FK goes on target table
|
||||||
const targetTableName = targetTable.schema
|
// If source is "many" and target is "one", FK goes on source table
|
||||||
? `${targetTable.schema}.${targetTable.name}`
|
let fkTable, fkField, refTable, refField;
|
||||||
: targetTable.name;
|
|
||||||
sqlScript += `ALTER TABLE ${sourceTableName} ADD CONSTRAINT ${relationship.name} FOREIGN KEY (${sourceTableField.name}) REFERENCES ${targetTableName} (${targetTableField.name});\n`;
|
if (
|
||||||
|
relationship.sourceCardinality === 'one' &&
|
||||||
|
relationship.targetCardinality === 'many'
|
||||||
|
) {
|
||||||
|
// FK goes on target table
|
||||||
|
fkTable = targetTable;
|
||||||
|
fkField = targetTableField;
|
||||||
|
refTable = sourceTable;
|
||||||
|
refField = sourceTableField;
|
||||||
|
} else if (
|
||||||
|
relationship.sourceCardinality === 'many' &&
|
||||||
|
relationship.targetCardinality === 'one'
|
||||||
|
) {
|
||||||
|
// FK goes on source table
|
||||||
|
fkTable = sourceTable;
|
||||||
|
fkField = sourceTableField;
|
||||||
|
refTable = targetTable;
|
||||||
|
refField = targetTableField;
|
||||||
|
} else if (
|
||||||
|
relationship.sourceCardinality === 'one' &&
|
||||||
|
relationship.targetCardinality === 'one'
|
||||||
|
) {
|
||||||
|
// For 1:1, FK can go on either side, but typically goes on the table that references the other
|
||||||
|
// We'll keep the current behavior for 1:1
|
||||||
|
fkTable = sourceTable;
|
||||||
|
fkField = sourceTableField;
|
||||||
|
refTable = targetTable;
|
||||||
|
refField = targetTableField;
|
||||||
|
} else {
|
||||||
|
// Many-to-many relationships need a junction table, skip for now
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fkTableName = fkTable.schema
|
||||||
|
? `${fkTable.schema}.${fkTable.name}`
|
||||||
|
: fkTable.name;
|
||||||
|
const refTableName = refTable.schema
|
||||||
|
? `${refTable.schema}.${refTable.name}`
|
||||||
|
: refTable.name;
|
||||||
|
sqlScript += `ALTER TABLE ${fkTableName} ADD CONSTRAINT ${relationship.name} FOREIGN KEY (${fkField.name}) REFERENCES ${refTableName} (${refField.name});\n`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user