fix(dbml field comments): support export field comments in dbml (#796)

* fix(dbml field comments): support export field comments in dbml

* add tests
This commit is contained in:
Guy Ben-Aharon
2025-07-27 20:53:55 +03:00
committed by GitHub
parent 4bc71c52ff
commit 0ca7008735
3 changed files with 177 additions and 1 deletions

View File

@@ -43,12 +43,19 @@ export const setupDBMLLanguage = (monaco: Monaco) => {
root: [ root: [
[/\b(Table|Ref|Indexes)\b/, 'keyword'], [/\b(Table|Ref|Indexes)\b/, 'keyword'],
[/\[.*?\]/, 'annotation'], [/\[.*?\]/, 'annotation'],
[/'''/, 'string', '@tripleQuoteString'],
[/".*?"/, 'string'], [/".*?"/, 'string'],
[/'.*?'/, 'string'], [/'.*?'/, 'string'],
[/`.*?`/, 'string'],
[/[{}]/, 'delimiter'], [/[{}]/, 'delimiter'],
[/[<>]/, 'operator'], [/[<>]/, 'operator'],
[new RegExp(`\\b(${datatypePattern})\\b`, 'i'), 'type'], // Added 'i' flag for case-insensitive matching [new RegExp(`\\b(${datatypePattern})\\b`, 'i'), 'type'], // Added 'i' flag for case-insensitive matching
], ],
tripleQuoteString: [
[/[^']+/, 'string'],
[/'''/, 'string', '@pop'],
[/'/, 'string'],
],
}, },
}); });
}; };

View File

@@ -348,4 +348,174 @@ describe('DBML Export - Issue Fixes', () => {
'"user id" bigint [not null, ref: < "user profile"."user id"]' '"user id" bigint [not null, ref: < "user profile"."user id"]'
); );
}); });
it('should export table and field comments to DBML', () => {
const diagram: Diagram = {
id: 'test-diagram',
name: 'Test',
databaseType: DatabaseType.POSTGRESQL,
createdAt: new Date(),
updatedAt: new Date(),
tables: [
{
id: 'table1',
name: 'users',
comments: 'Stores user information',
x: 0,
y: 0,
fields: [
{
id: 'field1',
name: 'id',
type: { id: 'bigint', name: 'bigint' },
primaryKey: true,
nullable: false,
unique: false,
comments: 'Unique identifier for the user',
collation: null,
default: null,
characterMaximumLength: null,
createdAt: Date.now(),
},
{
id: 'field2',
name: 'email',
type: { id: 'varchar', name: 'varchar' },
primaryKey: false,
nullable: false,
unique: true,
comments: 'User email address',
collation: null,
default: null,
characterMaximumLength: '255',
createdAt: Date.now(),
},
{
id: 'field3',
name: 'created_at',
type: { id: 'timestamp', name: 'timestamp' },
primaryKey: false,
nullable: false,
unique: false,
collation: null,
default: null,
characterMaximumLength: null,
createdAt: Date.now(),
},
],
indexes: [],
color: 'blue',
isView: false,
createdAt: Date.now(),
},
{
id: 'table2',
name: 'posts',
comments: 'Blog posts created by users',
x: 0,
y: 0,
fields: [
{
id: 'field4',
name: 'id',
type: { id: 'bigint', name: 'bigint' },
primaryKey: true,
nullable: false,
unique: false,
collation: null,
default: null,
characterMaximumLength: null,
createdAt: Date.now(),
},
{
id: 'field5',
name: 'user_id',
type: { id: 'bigint', name: 'bigint' },
primaryKey: false,
nullable: false,
unique: false,
comments:
'Reference to the user who created the post',
collation: null,
default: null,
characterMaximumLength: null,
createdAt: Date.now(),
},
{
id: 'field6',
name: 'title',
type: { id: 'varchar', name: 'varchar' },
primaryKey: false,
nullable: false,
unique: false,
collation: null,
default: null,
characterMaximumLength: '500',
createdAt: Date.now(),
},
],
indexes: [],
color: 'blue',
isView: false,
createdAt: Date.now(),
},
],
relationships: [
{
id: 'rel1',
name: 'fk_posts_user',
sourceTableId: 'table2',
sourceFieldId: 'field5',
targetTableId: 'table1',
targetFieldId: 'field1',
sourceCardinality: 'many',
targetCardinality: 'one',
createdAt: Date.now(),
},
],
};
const result = generateDBMLFromDiagram(diagram);
// Check table comments in standard DBML
expect(result.standardDbml).toContain('Table "users" {');
expect(result.standardDbml).toContain(
"Note: 'Stores user information'"
);
expect(result.standardDbml).toContain('Table "posts" {');
expect(result.standardDbml).toContain(
"Note: 'Blog posts created by users'"
);
// Check field comments in both inline and standard DBML
// In inline DBML, comments should appear after field definitions
expect(result.inlineDbml).toContain(
'"id" bigint [pk, not null, note: \'Unique identifier for the user\']'
);
expect(result.inlineDbml).toContain(
'"email" varchar(255) [unique, not null, note: \'User email address\']'
);
expect(result.inlineDbml).toContain(
'"user_id" bigint [not null, note: \'Reference to the user who created the post\', ref: < "users"."id"]'
);
// In standard DBML, field comments should use the note attribute syntax
expect(result.standardDbml).toContain(
'"id" bigint [pk, not null, note: \'Unique identifier for the user\']'
);
expect(result.standardDbml).toContain(
'"email" varchar(255) [unique, not null, note: \'User email address\']'
);
expect(result.standardDbml).toContain(
'"user_id" bigint [not null, note: \'Reference to the user who created the post\']'
);
// Verify fields without comments don't have note attribute
expect(result.standardDbml).not.toContain(
'"created_at" timestamp [not null, note:'
);
expect(result.standardDbml).not.toContain(
'"title" varchar(500) [not null, note:'
);
});
}); });

View File

@@ -643,7 +643,6 @@ export function generateDBMLFromDiagram(diagram: Diagram): DBMLExportResult {
...field, ...field,
name: finalSafeName, name: finalSafeName,
}; };
delete sanitizedField.comments;
// Rename field if SQL keyword (PostgreSQL only) // Rename field if SQL keyword (PostgreSQL only)
if (shouldRenameKeywords && isSQLKeyword(field.name)) { if (shouldRenameKeywords && isSQLKeyword(field.name)) {