diff --git a/src/components/code-snippet/languages/dbml-language.ts b/src/components/code-snippet/languages/dbml-language.ts index ab934b6a..1502c44d 100644 --- a/src/components/code-snippet/languages/dbml-language.ts +++ b/src/components/code-snippet/languages/dbml-language.ts @@ -43,12 +43,19 @@ export const setupDBMLLanguage = (monaco: Monaco) => { root: [ [/\b(Table|Ref|Indexes)\b/, 'keyword'], [/\[.*?\]/, 'annotation'], + [/'''/, 'string', '@tripleQuoteString'], [/".*?"/, 'string'], [/'.*?'/, 'string'], + [/`.*?`/, 'string'], [/[{}]/, 'delimiter'], [/[<>]/, 'operator'], [new RegExp(`\\b(${datatypePattern})\\b`, 'i'), 'type'], // Added 'i' flag for case-insensitive matching ], + tripleQuoteString: [ + [/[^']+/, 'string'], + [/'''/, 'string', '@pop'], + [/'/, 'string'], + ], }, }); }; diff --git a/src/lib/dbml/dbml-export/__tests__/dbml-export-issue-fix.test.ts b/src/lib/dbml/dbml-export/__tests__/dbml-export-issue-fix.test.ts index f68e2cb8..1f486ac8 100644 --- a/src/lib/dbml/dbml-export/__tests__/dbml-export-issue-fix.test.ts +++ b/src/lib/dbml/dbml-export/__tests__/dbml-export-issue-fix.test.ts @@ -348,4 +348,174 @@ describe('DBML Export - Issue Fixes', () => { '"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:' + ); + }); }); diff --git a/src/lib/dbml/dbml-export/dbml-export.ts b/src/lib/dbml/dbml-export/dbml-export.ts index 1fae82e8..901dd602 100644 --- a/src/lib/dbml/dbml-export/dbml-export.ts +++ b/src/lib/dbml/dbml-export/dbml-export.ts @@ -643,7 +643,6 @@ export function generateDBMLFromDiagram(diagram: Diagram): DBMLExportResult { ...field, name: finalSafeName, }; - delete sanitizedField.comments; // Rename field if SQL keyword (PostgreSQL only) if (shouldRenameKeywords && isSQLKeyword(field.name)) {