mirror of
				https://github.com/chartdb/chartdb.git
				synced 2025-11-04 14:03:15 +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