mirror of
				https://github.com/chartdb/chartdb.git
				synced 2025-11-04 05:53:15 +00:00 
			
		
		
		
	fix(dbml): support multiple relationships on same field in inline DBML (#822)
This commit is contained in:
		@@ -286,9 +286,14 @@ const convertToInlineRefs = (dbml: string): string => {
 | 
			
		||||
    // Create a map for faster table lookup
 | 
			
		||||
    const tableMap = new Map(Object.entries(tables));
 | 
			
		||||
 | 
			
		||||
    // 1. Add inline refs to table contents
 | 
			
		||||
    // 1. First, collect all refs per field
 | 
			
		||||
    const fieldRefs = new Map<
 | 
			
		||||
        string,
 | 
			
		||||
        { table: string; refs: string[]; relatedTables: string[] }
 | 
			
		||||
    >();
 | 
			
		||||
 | 
			
		||||
    refs.forEach((ref) => {
 | 
			
		||||
        let targetTableName, fieldNameToModify, inlineRefSyntax;
 | 
			
		||||
        let targetTableName, fieldNameToModify, inlineRefSyntax, relatedTable;
 | 
			
		||||
 | 
			
		||||
        if (ref.direction === '<') {
 | 
			
		||||
            targetTableName = ref.targetSchema
 | 
			
		||||
@@ -299,6 +304,7 @@ const convertToInlineRefs = (dbml: string): string => {
 | 
			
		||||
                ? `"${ref.sourceSchema}"."${ref.sourceTable}"."${ref.sourceField}"`
 | 
			
		||||
                : `"${ref.sourceTable}"."${ref.sourceField}"`;
 | 
			
		||||
            inlineRefSyntax = `ref: < ${sourceRef}`;
 | 
			
		||||
            relatedTable = ref.sourceTable;
 | 
			
		||||
        } else {
 | 
			
		||||
            targetTableName = ref.sourceSchema
 | 
			
		||||
                ? `${ref.sourceSchema}.${ref.sourceTable}`
 | 
			
		||||
@@ -308,13 +314,32 @@ const convertToInlineRefs = (dbml: string): string => {
 | 
			
		||||
                ? `"${ref.targetSchema}"."${ref.targetTable}"."${ref.targetField}"`
 | 
			
		||||
                : `"${ref.targetTable}"."${ref.targetField}"`;
 | 
			
		||||
            inlineRefSyntax = `ref: > ${targetRef}`;
 | 
			
		||||
            relatedTable = ref.targetTable;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const tableData = tableMap.get(targetTableName);
 | 
			
		||||
        const fieldKey = `${targetTableName}.${fieldNameToModify}`;
 | 
			
		||||
        const existing = fieldRefs.get(fieldKey) || {
 | 
			
		||||
            table: targetTableName,
 | 
			
		||||
            refs: [],
 | 
			
		||||
            relatedTables: [],
 | 
			
		||||
        };
 | 
			
		||||
        existing.refs.push(inlineRefSyntax);
 | 
			
		||||
        existing.relatedTables.push(relatedTable);
 | 
			
		||||
        fieldRefs.set(fieldKey, existing);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // 2. Apply all refs to fields
 | 
			
		||||
    fieldRefs.forEach((fieldData, fieldKey) => {
 | 
			
		||||
        // fieldKey might be "schema.table.field" or just "table.field"
 | 
			
		||||
        const lastDotIndex = fieldKey.lastIndexOf('.');
 | 
			
		||||
        const tableName = fieldKey.substring(0, lastDotIndex);
 | 
			
		||||
        const fieldName = fieldKey.substring(lastDotIndex + 1);
 | 
			
		||||
        const tableData = tableMap.get(tableName);
 | 
			
		||||
 | 
			
		||||
        if (tableData) {
 | 
			
		||||
            // Updated pattern to capture field definition and all existing attributes in brackets
 | 
			
		||||
            const fieldPattern = new RegExp(
 | 
			
		||||
                `^([ \t]*"${fieldNameToModify}"[^\\n]*?)(?:\\s*(\\[[^\\]]*\\]))*\\s*(//.*)?$`,
 | 
			
		||||
                `^([ \t]*"${fieldName}"[^\\n]*?)(?:\\s*(\\[[^\\]]*\\]))*\\s*(//.*)?$`,
 | 
			
		||||
                'gm'
 | 
			
		||||
            );
 | 
			
		||||
            let newContent = tableData.content;
 | 
			
		||||
@@ -322,11 +347,6 @@ const convertToInlineRefs = (dbml: string): string => {
 | 
			
		||||
            newContent = newContent.replace(
 | 
			
		||||
                fieldPattern,
 | 
			
		||||
                (lineMatch, fieldPart, existingBrackets, commentPart) => {
 | 
			
		||||
                    // Avoid adding duplicate refs
 | 
			
		||||
                    if (lineMatch.includes('ref:')) {
 | 
			
		||||
                        return lineMatch;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Collect all attributes from existing brackets
 | 
			
		||||
                    const allAttributes: string[] = [];
 | 
			
		||||
                    if (existingBrackets) {
 | 
			
		||||
@@ -344,8 +364,8 @@ const convertToInlineRefs = (dbml: string): string => {
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Add the new ref
 | 
			
		||||
                    allAttributes.push(inlineRefSyntax);
 | 
			
		||||
                    // Add all refs for this field
 | 
			
		||||
                    allAttributes.push(...fieldData.refs);
 | 
			
		||||
 | 
			
		||||
                    // Combine all attributes into a single bracket
 | 
			
		||||
                    const combinedAttributes = allAttributes.join(', ');
 | 
			
		||||
@@ -353,6 +373,7 @@ const convertToInlineRefs = (dbml: string): string => {
 | 
			
		||||
                    // Preserve original spacing from fieldPart
 | 
			
		||||
                    const leadingSpaces = fieldPart.match(/^(\s*)/)?.[1] || '';
 | 
			
		||||
                    const fieldDefWithoutSpaces = fieldPart.trim();
 | 
			
		||||
 | 
			
		||||
                    return `${leadingSpaces}${fieldDefWithoutSpaces} [${combinedAttributes}]${commentPart || ''}`;
 | 
			
		||||
                }
 | 
			
		||||
            );
 | 
			
		||||
@@ -360,7 +381,7 @@ const convertToInlineRefs = (dbml: string): string => {
 | 
			
		||||
            // Update the table content if modified
 | 
			
		||||
            if (newContent !== tableData.content) {
 | 
			
		||||
                tableData.content = newContent;
 | 
			
		||||
                tableMap.set(targetTableName, tableData);
 | 
			
		||||
                tableMap.set(tableName, tableData);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
@@ -376,9 +397,18 @@ const convertToInlineRefs = (dbml: string): string => {
 | 
			
		||||
        reconstructedDbml += dbml.substring(lastIndex, tableData.start);
 | 
			
		||||
        // Preserve the original table definition format but with updated content
 | 
			
		||||
        const originalTableDef = tableData.fullMatch;
 | 
			
		||||
 | 
			
		||||
        // Ensure the content ends with proper whitespace before the closing brace
 | 
			
		||||
        let content = tableData.content;
 | 
			
		||||
        // Check if content ends with a field that has inline refs
 | 
			
		||||
        if (content.match(/\[.*ref:.*\]\s*$/)) {
 | 
			
		||||
            // Ensure there's a newline before the closing brace
 | 
			
		||||
            content = content.trimEnd() + '\n';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const updatedTableDef = originalTableDef.replace(
 | 
			
		||||
            /{[^}]*}/,
 | 
			
		||||
            `{${tableData.content}}`
 | 
			
		||||
            `{${content}}`
 | 
			
		||||
        );
 | 
			
		||||
        reconstructedDbml += updatedTableDef;
 | 
			
		||||
        lastIndex = tableData.end;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user