mirror of
https://github.com/chartdb/chartdb.git
synced 2025-11-03 13:33:25 +00:00
fix: handle bidirectional relationships in DBML export (#924)
This commit is contained in:
129
src/lib/dbml/dbml-export/__tests__/cases/5.inline.dbml
Normal file
129
src/lib/dbml/dbml-export/__tests__/cases/5.inline.dbml
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
Enum "cbhpm_entradas_tipo" {
|
||||||
|
"grupo"
|
||||||
|
"subgrupo"
|
||||||
|
"procedimento"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "cid_entradas_tipo" {
|
||||||
|
"capitulo"
|
||||||
|
"agrupamento"
|
||||||
|
"categoria"
|
||||||
|
"subcategoria"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "digital_signature_provider" {
|
||||||
|
"soluti"
|
||||||
|
"valid"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "impresso_posicao" {
|
||||||
|
"start"
|
||||||
|
"center"
|
||||||
|
"end"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "otp_provider" {
|
||||||
|
"clinic"
|
||||||
|
"soluti_bird_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "tipo_cobranca" {
|
||||||
|
"valor"
|
||||||
|
"porte"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "tipo_contato_movel" {
|
||||||
|
"celular"
|
||||||
|
"telefone_residencial"
|
||||||
|
"telefone_comercial"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "tipo_contrato" {
|
||||||
|
"trial"
|
||||||
|
"common"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "tipo_endereco" {
|
||||||
|
"residencial"
|
||||||
|
"comercial"
|
||||||
|
"cobranca"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "tipo_espectro_autista" {
|
||||||
|
"leve"
|
||||||
|
"moderado"
|
||||||
|
"severo"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "tipo_estado_civil" {
|
||||||
|
"nao_infomado"
|
||||||
|
"solteiro"
|
||||||
|
"casado"
|
||||||
|
"divorciado"
|
||||||
|
"viuvo"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "tipo_etnia" {
|
||||||
|
"nao_infomado"
|
||||||
|
"branca"
|
||||||
|
"preta"
|
||||||
|
"parda"
|
||||||
|
"amarela"
|
||||||
|
"indigena"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "tipo_excecao" {
|
||||||
|
"bloqueio"
|
||||||
|
"compromisso"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "tipo_metodo_reajuste" {
|
||||||
|
"percentual"
|
||||||
|
"valor"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "tipo_pessoa" {
|
||||||
|
"fisica"
|
||||||
|
"juridica"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "tipo_procedimento" {
|
||||||
|
"consulta"
|
||||||
|
"exame_laboratorial"
|
||||||
|
"exame_imagem"
|
||||||
|
"procedimento_clinico"
|
||||||
|
"procedimento_cirurgico"
|
||||||
|
"terapia"
|
||||||
|
"outros"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "tipo_relacionamento" {
|
||||||
|
"pai"
|
||||||
|
"mae"
|
||||||
|
"conjuge"
|
||||||
|
"filho_a"
|
||||||
|
"tutor_legal"
|
||||||
|
"contato_emergencia"
|
||||||
|
"outro"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "tipo_sexo" {
|
||||||
|
"nao_infomado"
|
||||||
|
"masculino"
|
||||||
|
"feminino"
|
||||||
|
"intersexo"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum "tipo_status_agendamento" {
|
||||||
|
"em espera"
|
||||||
|
"faltou"
|
||||||
|
"ok"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table "public"."organizacao_cfg_impressos" {
|
||||||
|
"id_organizacao" integer [pk, not null, ref: < "public"."organizacao"."id"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Table "public"."organizacao" {
|
||||||
|
"id" integer [pk, not null]
|
||||||
|
}
|
||||||
1
src/lib/dbml/dbml-export/__tests__/cases/5.json
Normal file
1
src/lib/dbml/dbml-export/__tests__/cases/5.json
Normal file
File diff suppressed because one or more lines are too long
@@ -14,14 +14,36 @@ const testCase = (caseNumber: string) => {
|
|||||||
|
|
||||||
// Generate DBML from the diagram
|
// Generate DBML from the diagram
|
||||||
const result = generateDBMLFromDiagram(diagram);
|
const result = generateDBMLFromDiagram(diagram);
|
||||||
const generatedDBML = result.standardDbml;
|
|
||||||
|
|
||||||
// Read the expected DBML file
|
// Check for both regular and inline DBML files
|
||||||
const dbmlPath = path.join(__dirname, 'cases', `${caseNumber}.dbml`);
|
const regularDbmlPath = path.join(__dirname, 'cases', `${caseNumber}.dbml`);
|
||||||
const expectedDBML = fs.readFileSync(dbmlPath, 'utf-8');
|
const inlineDbmlPath = path.join(
|
||||||
|
__dirname,
|
||||||
|
'cases',
|
||||||
|
`${caseNumber}.inline.dbml`
|
||||||
|
);
|
||||||
|
|
||||||
// Compare the generated DBML with the expected DBML
|
const hasRegularDbml = fs.existsSync(regularDbmlPath);
|
||||||
expect(generatedDBML).toBe(expectedDBML);
|
const hasInlineDbml = fs.existsSync(inlineDbmlPath);
|
||||||
|
|
||||||
|
// Test regular DBML if file exists
|
||||||
|
if (hasRegularDbml) {
|
||||||
|
const expectedRegularDBML = fs.readFileSync(regularDbmlPath, 'utf-8');
|
||||||
|
expect(result.standardDbml).toBe(expectedRegularDBML);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test inline DBML if file exists
|
||||||
|
if (hasInlineDbml) {
|
||||||
|
const expectedInlineDBML = fs.readFileSync(inlineDbmlPath, 'utf-8');
|
||||||
|
expect(result.inlineDbml).toBe(expectedInlineDBML);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure at least one DBML file exists
|
||||||
|
if (!hasRegularDbml && !hasInlineDbml) {
|
||||||
|
throw new Error(
|
||||||
|
`No DBML file found for test case ${caseNumber}. Expected either ${caseNumber}.dbml or ${caseNumber}.inline.dbml`
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('DBML Export cases', () => {
|
describe('DBML Export cases', () => {
|
||||||
@@ -40,4 +62,8 @@ describe('DBML Export cases', () => {
|
|||||||
it('should handle case 4 diagram', { timeout: 30000 }, async () => {
|
it('should handle case 4 diagram', { timeout: 30000 }, async () => {
|
||||||
testCase('4');
|
testCase('4');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle case 5 diagram', { timeout: 30000 }, async () => {
|
||||||
|
testCase('5');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -506,15 +506,30 @@ const deduplicateRelationships = (diagram: Diagram): Diagram => {
|
|||||||
if (!diagram.relationships) return diagram;
|
if (!diagram.relationships) return diagram;
|
||||||
|
|
||||||
const seenRelationships = new Set<string>();
|
const seenRelationships = new Set<string>();
|
||||||
|
const seenBidirectional = new Set<string>();
|
||||||
const uniqueRelationships = diagram.relationships.filter((rel) => {
|
const uniqueRelationships = diagram.relationships.filter((rel) => {
|
||||||
// Create a unique key based on the relationship endpoints
|
// Create a unique key based on the relationship endpoints
|
||||||
const relationshipKey = `${rel.sourceTableId}-${rel.sourceFieldId}->${rel.targetTableId}-${rel.targetFieldId}`;
|
const relationshipKey = `${rel.sourceTableId}-${rel.sourceFieldId}->${rel.targetTableId}-${rel.targetFieldId}`;
|
||||||
|
|
||||||
|
// Create a normalized key that's the same for both directions
|
||||||
|
const normalizedKey = [
|
||||||
|
`${rel.sourceTableId}-${rel.sourceFieldId}`,
|
||||||
|
`${rel.targetTableId}-${rel.targetFieldId}`,
|
||||||
|
]
|
||||||
|
.sort()
|
||||||
|
.join('<->');
|
||||||
|
|
||||||
if (seenRelationships.has(relationshipKey)) {
|
if (seenRelationships.has(relationshipKey)) {
|
||||||
return false; // Skip duplicate
|
return false; // Skip exact duplicate
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seenBidirectional.has(normalizedKey)) {
|
||||||
|
// This is a bidirectional relationship, skip the second one
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
seenRelationships.add(relationshipKey);
|
seenRelationships.add(relationshipKey);
|
||||||
|
seenBidirectional.add(normalizedKey);
|
||||||
return true; // Keep unique relationship
|
return true; // Keep unique relationship
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user