mirror of
https://github.com/chartdb/chartdb.git
synced 2026-01-06 03:39:57 -06:00
fix(dbml): import dbml notes (table + fields) (#827)
This commit is contained in:
@@ -199,6 +199,7 @@ const buildSourceMappings = (sourceDiagram: Diagram) => {
|
||||
const updateTables = ({
|
||||
targetTables,
|
||||
sourceTables,
|
||||
defaultDatabaseSchema,
|
||||
}: {
|
||||
targetTables: DBTable[] | undefined;
|
||||
sourceTables: DBTable[] | undefined;
|
||||
@@ -225,6 +226,24 @@ const updateTables = ({
|
||||
const targetKey = createObjectKeyFromTable(targetTable);
|
||||
let sourceTable = sourceTablesByKey.get(targetKey);
|
||||
|
||||
if (!sourceTable && defaultDatabaseSchema) {
|
||||
if (!targetTable.schema) {
|
||||
// If target table has no schema, try matching with default schema
|
||||
const defaultKey = createObjectKeyFromTable({
|
||||
...targetTable,
|
||||
schema: defaultDatabaseSchema,
|
||||
});
|
||||
sourceTable = sourceTablesByKey.get(defaultKey);
|
||||
} else if (targetTable.schema === defaultDatabaseSchema) {
|
||||
// If target table's schema matches default, try matching without schema
|
||||
const noSchemaKey = createObjectKeyFromTable({
|
||||
...targetTable,
|
||||
schema: undefined,
|
||||
});
|
||||
sourceTable = sourceTablesByKey.get(noSchemaKey);
|
||||
}
|
||||
}
|
||||
|
||||
// If no exact match, try matching by name only
|
||||
if (!sourceTable) {
|
||||
sourceTable = sourceTables.find(
|
||||
@@ -285,6 +304,7 @@ const updateTables = ({
|
||||
...sourceTable,
|
||||
fields: updatedFields,
|
||||
indexes: updatedIndexes,
|
||||
comments: targetTable.comments,
|
||||
};
|
||||
|
||||
// Update nullable, unique, primaryKey from target fields
|
||||
|
||||
@@ -1244,4 +1244,47 @@ Table "public_3"."comments" {
|
||||
expect(relationshipsHaveSchemas).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Notes Support', () => {
|
||||
it('should import table with note', async () => {
|
||||
const dbmlWithTableNote = `
|
||||
Table products {
|
||||
id integer [pk]
|
||||
name varchar(100)
|
||||
Note: 'This table stores product information'
|
||||
}`;
|
||||
|
||||
const diagram = await importDBMLToDiagram(dbmlWithTableNote);
|
||||
|
||||
expect(diagram.tables).toHaveLength(1);
|
||||
const productsTable = diagram.tables?.[0];
|
||||
expect(productsTable?.name).toBe('products');
|
||||
expect(productsTable?.comments).toBe(
|
||||
'This table stores product information'
|
||||
);
|
||||
});
|
||||
|
||||
it('should import field with note', async () => {
|
||||
const dbmlWithFieldNote = `
|
||||
Table orders {
|
||||
id integer [pk]
|
||||
total numeric(10,2) [note: 'Order total including tax']
|
||||
}`;
|
||||
|
||||
const diagram = await importDBMLToDiagram(dbmlWithFieldNote);
|
||||
|
||||
expect(diagram.tables).toHaveLength(1);
|
||||
const ordersTable = diagram.tables?.[0];
|
||||
expect(ordersTable?.fields).toHaveLength(2);
|
||||
|
||||
const totalField = ordersTable?.fields.find(
|
||||
(f) => f.name === 'total'
|
||||
);
|
||||
|
||||
// Field notes should be imported
|
||||
expect(totalField).toBeDefined();
|
||||
expect(totalField?.name).toBe('total');
|
||||
expect(totalField?.comments).toBe('Order total including tax');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -86,6 +86,7 @@ interface DBMLField {
|
||||
characterMaximumLength?: string | null;
|
||||
precision?: number | null;
|
||||
scale?: number | null;
|
||||
note?: string | { value: string } | null;
|
||||
}
|
||||
|
||||
interface DBMLIndexColumn {
|
||||
@@ -311,6 +312,7 @@ export const importDBMLToDiagram = async (
|
||||
pk: field.pk,
|
||||
not_null: field.not_null,
|
||||
increment: field.increment,
|
||||
note: field.note,
|
||||
...getFieldExtraAttributes(field, allEnums),
|
||||
} satisfies DBMLField;
|
||||
}),
|
||||
@@ -424,21 +426,37 @@ export const importDBMLToDiagram = async (
|
||||
const tableSpacing = 300;
|
||||
|
||||
// Create fields first so we have their IDs
|
||||
const fields: DBField[] = table.fields.map((field) => ({
|
||||
id: generateId(),
|
||||
name: field.name.replace(/['"]/g, ''),
|
||||
type: mapDBMLTypeToDataType(field.type.type_name, {
|
||||
...options,
|
||||
enums: extractedData.enums,
|
||||
}),
|
||||
nullable: !field.not_null,
|
||||
primaryKey: field.pk || false,
|
||||
unique: field.unique || false,
|
||||
createdAt: Date.now(),
|
||||
characterMaximumLength: field.characterMaximumLength,
|
||||
precision: field.precision,
|
||||
scale: field.scale,
|
||||
}));
|
||||
const fields: DBField[] = table.fields.map((field) => {
|
||||
// Extract field note/comment
|
||||
let fieldComment: string | undefined;
|
||||
if (field.note) {
|
||||
if (typeof field.note === 'string') {
|
||||
fieldComment = field.note;
|
||||
} else if (
|
||||
typeof field.note === 'object' &&
|
||||
'value' in field.note
|
||||
) {
|
||||
fieldComment = field.note.value;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: generateId(),
|
||||
name: field.name.replace(/['"]/g, ''),
|
||||
type: mapDBMLTypeToDataType(field.type.type_name, {
|
||||
...options,
|
||||
enums: extractedData.enums,
|
||||
}),
|
||||
nullable: !field.not_null,
|
||||
primaryKey: field.pk || false,
|
||||
unique: field.unique || false,
|
||||
createdAt: Date.now(),
|
||||
characterMaximumLength: field.characterMaximumLength,
|
||||
precision: field.precision,
|
||||
scale: field.scale,
|
||||
...(fieldComment ? { comments: fieldComment } : {}),
|
||||
};
|
||||
});
|
||||
|
||||
// Convert DBML indexes to ChartDB indexes
|
||||
const indexes: DBIndex[] =
|
||||
|
||||
Reference in New Issue
Block a user