Skip to content

Commit 92c6f96

Browse files
committed
feat: partially add types to exporter and model structures
1 parent eb96e11 commit 92c6f96

31 files changed

Lines changed: 1499 additions & 628 deletions

packages/dbml-core/src/export/DbmlExporter.ts

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,24 @@ import { groupBy, isEmpty, reduce } from 'lodash-es';
22
import { addDoubleQuoteIfNeeded, formatRecordValue } from '@dbml/parse';
33
import { shouldPrintSchema } from './utils';
44
import { DEFAULT_SCHEMA_NAME } from '../model_structure/config';
5+
import { NormalizedModel } from '../model_structure/database';
6+
import { NormalizedTable } from '../model_structure/table';
7+
import { NormalizedTableGroup } from '../model_structure/tableGroup';
58

69
class DbmlExporter {
7-
static hasWhiteSpace (str) {
10+
static hasWhiteSpace (str: string): boolean {
811
return /\s/g.test(str);
912
}
1013

11-
static hasSquareBracket (str) {
14+
static hasSquareBracket (str: string): boolean {
1215
return /\[|\]/.test(str);
1316
}
1417

15-
static isExpression (str) {
18+
static isExpression (str: string): boolean {
1619
return /\s*(\*|\+|-|\([A-Za-z0-9_]+\)|\(\))/g.test(str);
1720
}
1821

19-
static escapeNote (str) {
22+
static escapeNote (str: string | null): string {
2023
if (str === null) {
2124
return '';
2225
}
@@ -30,7 +33,7 @@ class DbmlExporter {
3033
return `'''${newStr}'''`;
3134
}
3235

33-
static exportEnums (enumIds, model) {
36+
static exportEnums (enumIds: number[], model: NormalizedModel): string {
3437
const enumStrs = enumIds.map((enumId) => {
3538
const _enum = model.enums[enumId];
3639
const schema = model.schemas[_enum.schemaId];
@@ -46,7 +49,7 @@ class DbmlExporter {
4649
return enumStrs.length ? enumStrs.join('\n') : '';
4750
}
4851

49-
static getFieldLines (tableId, model) {
52+
static getFieldLines (tableId: number, model: NormalizedModel): string[] {
5053
const table = model.tables[tableId];
5154

5255
const lines = table.fieldIds.map((fieldId) => {
@@ -61,7 +64,7 @@ class DbmlExporter {
6164
? `"${field.type.type_name}"`
6265
: field.type.type_name}`;
6366

64-
const constraints = [];
67+
const constraints: string[] = [];
6568
if (field.unique) {
6669
constraints.push('unique');
6770
}
@@ -93,7 +96,7 @@ class DbmlExporter {
9396
break;
9497

9598
case 'string': {
96-
const quote = field.dbdefault.value.includes('\n') ? '\'\'\'' : '\'';
99+
const quote = (field.dbdefault.value as string).includes('\n') ? '\'\'\'' : '\'';
97100
value += `${quote}${field.dbdefault.value}${quote}`;
98101
break;
99102
}
@@ -122,7 +125,7 @@ class DbmlExporter {
122125
return lines;
123126
}
124127

125-
static getIndexLines (tableId, model) {
128+
static getIndexLines (tableId: number, model: NormalizedModel): string[] {
126129
const table = model.tables[tableId];
127130

128131
const lines = table.indexIds.map((indexId) => {
@@ -144,7 +147,7 @@ class DbmlExporter {
144147
: column.value;
145148
}
146149

147-
const indexSettings = [];
150+
const indexSettings: string[] = [];
148151
if (index.pk) {
149152
indexSettings.push('pk');
150153
}
@@ -169,7 +172,7 @@ class DbmlExporter {
169172
return lines;
170173
}
171174

172-
static getCheckLines (tableId, model) {
175+
static getCheckLines (tableId: number, model: NormalizedModel): string[] {
173176
const table = model.tables[tableId];
174177

175178
const lines = table.checkIds.map((checkId) => {
@@ -185,7 +188,12 @@ class DbmlExporter {
185188
return lines;
186189
}
187190

188-
static getTableContentArr (tableIds, model) {
191+
static getTableContentArr (tableIds: number[], model: NormalizedModel): Array<{
192+
tableId: number;
193+
fieldContents: string[];
194+
checkContents: string[];
195+
indexContents: string[];
196+
}> {
189197
const tableContentArr = tableIds.map((tableId) => {
190198
const fieldContents = DbmlExporter.getFieldLines(tableId, model);
191199
const checkContents = DbmlExporter.getCheckLines(tableId, model);
@@ -202,7 +210,7 @@ class DbmlExporter {
202210
return tableContentArr;
203211
}
204212

205-
static getTableSettings (table) {
213+
static getTableSettings (table: NormalizedTable): string {
206214
let settingStr = '';
207215
const settingSep = ', ';
208216
if (table.headerColor) {
@@ -214,7 +222,7 @@ class DbmlExporter {
214222
return settingStr ? ` [${settingStr}]` : '';
215223
}
216224

217-
static exportTables (tableIds, model) {
225+
static exportTables (tableIds: number[], model: NormalizedModel): string {
218226
const tableContentArr = DbmlExporter.getTableContentArr(tableIds, model);
219227

220228
const tableStrs = tableContentArr.map((tableContent) => {
@@ -250,12 +258,12 @@ class DbmlExporter {
250258
return tableStrs.length ? tableStrs.join('\n') : '';
251259
}
252260

253-
static buildFieldName (fieldIds, model) {
261+
static buildFieldName (fieldIds: number[], model: NormalizedModel): string {
254262
const fieldNames = fieldIds.map((fieldId) => `"${model.fields[fieldId].name}"`).join(', ');
255263
return fieldIds.length === 1 ? fieldNames : `(${fieldNames})`;
256264
}
257265

258-
static exportRefs (refIds, model) {
266+
static exportRefs (refIds: number[], model: NormalizedModel): string {
259267
const strArr = refIds.map((refId) => {
260268
const ref = model.refs[refId];
261269
const oneRelationEndpointIndex = ref.endpointIds.findIndex((endpointId) => model.endpoints[endpointId].relation === '1');
@@ -270,7 +278,7 @@ class DbmlExporter {
270278
const refEndpointField = model.fields[refEndpoint.fieldIds[0]];
271279
const refEndpointTable = model.tables[refEndpointField.tableId];
272280
const refEndpointSchema = model.schemas[refEndpointTable.schemaId];
273-
const refEndpointFieldName = this.buildFieldName(refEndpoint.fieldIds, model, 'dbml');
281+
const refEndpointFieldName = this.buildFieldName(refEndpoint.fieldIds, model);
274282

275283
if (ref.name) {
276284
line += ` ${shouldPrintSchema(model.schemas[ref.schemaId], model)
@@ -285,7 +293,7 @@ class DbmlExporter {
285293
const foreignEndpointField = model.fields[foreignEndpoint.fieldIds[0]];
286294
const foreignEndpointTable = model.tables[foreignEndpointField.tableId];
287295
const foreignEndpointSchema = model.schemas[foreignEndpointTable.schemaId];
288-
const foreignEndpointFieldName = this.buildFieldName(foreignEndpoint.fieldIds, model, 'dbml');
296+
const foreignEndpointFieldName = this.buildFieldName(foreignEndpoint.fieldIds, model);
289297

290298
if (isManyToMany) line += '<> ';
291299
else
@@ -295,7 +303,7 @@ class DbmlExporter {
295303
? `"${foreignEndpointSchema.name}".`
296304
: ''}"${foreignEndpointTable.name}".${foreignEndpointFieldName}`;
297305

298-
const refActions = [];
306+
const refActions: string[] = [];
299307
if (ref.onUpdate) {
300308
refActions.push(`update: ${ref.onUpdate.toLowerCase()}`);
301309
}
@@ -313,15 +321,15 @@ class DbmlExporter {
313321
return strArr.length ? strArr.join('\n') : '';
314322
}
315323

316-
static getTableGroupSettings (tableGroup) {
317-
const settings = [];
324+
static getTableGroupSettings (tableGroup: NormalizedTableGroup): string {
325+
const settings: string[] = [];
318326

319327
if (tableGroup.color) settings.push(`color: ${tableGroup.color}`);
320328

321329
return settings.length ? ` [${settings.join(', ')}]` : '';
322330
}
323331

324-
static exportTableGroups (tableGroupIds, model) {
332+
static exportTableGroups (tableGroupIds: number[], model: NormalizedModel): string {
325333
const tableGroupStrs = tableGroupIds.map((groupId) => {
326334
const group = model.tableGroups[groupId];
327335
const groupSchema = model.schemas[group.schemaId];
@@ -345,7 +353,7 @@ class DbmlExporter {
345353
return tableGroupStrs.length ? tableGroupStrs.join('\n') : '';
346354
}
347355

348-
static exportStickyNotes (model) {
356+
static exportStickyNotes (model: NormalizedModel): string {
349357
return reduce(model.notes, (result, note) => {
350358
const escapedContent = ` ${DbmlExporter.escapeNote(note.content)}`;
351359
const stickyNote = `Note ${note.name} {\n${escapedContent}\n}\n`;
@@ -355,7 +363,7 @@ class DbmlExporter {
355363
}, '');
356364
}
357365

358-
static exportRecords (model) {
366+
static exportRecords (model: NormalizedModel): string {
359367
const records = model.records;
360368
if (!records || isEmpty(records)) {
361369
return '';
@@ -380,7 +388,7 @@ class DbmlExporter {
380388
// Merge all rows
381389
const allRows = groupRecords.flatMap((record) => {
382390
const allColumnIndexes = allColumns.map((col) => record.columns.indexOf(col));
383-
return record.values.map((row) => allColumnIndexes.map((colIdx) => colIdx === -1 ? { value: null, type: 'expression' } : row[colIdx]));
391+
return record.values.map((row: any[]) => allColumnIndexes.map((colIdx) => colIdx === -1 ? { value: null, type: 'expression' } : row[colIdx]));
384392
});
385393

386394
// Build data rows
@@ -394,8 +402,8 @@ class DbmlExporter {
394402
return recordStrs.join('\n');
395403
}
396404

397-
static export (model, flags = {}) {
398-
const elementStrs = [];
405+
static export (model: NormalizedModel, flags: { includeRecords?: boolean } = {}): string {
406+
const elementStrs: string[] = [];
399407
const database = model.database['1'];
400408
// includeRecords defaults to true; set to false to omit TableData blocks from the output
401409
const includeRecords = flags.includeRecords !== false;

packages/dbml-core/src/export/JsonExporter.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1+
import Database, { NormalizedModel } from 'model_structure/database';
2+
13
class JsonExporter {
2-
static export (model, flags = {}) {
4+
static export (
5+
model: Database | NormalizedModel,
6+
flags: { isNormalized?: boolean } | boolean = {},
7+
) {
38
// Backwards compatibility: if a boolean is passed, treat it as the isNormalized flag
49
const resolvedFlags = typeof flags === 'boolean' ? { isNormalized: flags } : flags;
10+
511
// isNormalized defaults to true; when false, the model is normalized before exporting
6-
const isNormalized = resolvedFlags.isNormalized !== false;
12+
const { isNormalized = true } = resolvedFlags;
713

8-
if (!isNormalized) {
14+
if (!isNormalized && model instanceof Database) {
915
return JSON.stringify(model.export(), null, 2);
1016
}
1117

packages/dbml-core/src/export/ModelExporter.ts

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,51 @@ import PostgresExporter from './PostgresExporter';
44
import JsonExporter from './JsonExporter';
55
import SqlServerExporter from './SqlServerExporter';
66
import OracleExporter from './OracleExporter';
7+
import Database, { NormalizedModel } from '../model_structure/database';
8+
9+
export type ExportFormatOption = 'dbml' | 'mysql' | 'postgres' | 'json' | 'mssql' | 'oracle';
10+
11+
export interface ExportFlags {
12+
isNormalized?: boolean;
13+
includeRecords?: boolean;
14+
}
715

816
class ModelExporter {
9-
static export (model = {}, format = '', flags = {}) {
17+
/**
18+
* @deprecated Passing a boolean as the third argument is deprecated. Use `{ isNormalized: boolean }` instead.
19+
*/
20+
static export (
21+
model: Database | NormalizedModel,
22+
format: ExportFormatOption,
23+
isNormalized: boolean,
24+
): string;
25+
26+
static export (
27+
model: Database | NormalizedModel,
28+
format: ExportFormatOption,
29+
flags?: ExportFlags,
30+
): string;
31+
32+
static export (
33+
model: Database | NormalizedModel,
34+
format: ExportFormatOption,
35+
flags: ExportFlags | boolean = {},
36+
) {
1037
let res = '';
1138
// Backwards compatibility: if a boolean is passed, treat it as the isNormalized flag
12-
const resolvedFlags = typeof flags === 'boolean' ? { isNormalized: flags } : flags;
39+
const resolvedFlags: ExportFlags = typeof flags === 'boolean' ? { isNormalized: flags } : flags;
1340
// isNormalized defaults to true; when false, the model is normalized before exporting
14-
const isNormalized = resolvedFlags.isNormalized !== false;
15-
const normalizedModel = isNormalized ? model : model.normalize();
41+
42+
const {
43+
isNormalized = true,
44+
includeRecords = true,
45+
} = resolvedFlags;
46+
47+
const normalizedModel = isNormalized ? model as NormalizedModel : (model as Database).normalize();
48+
1649
switch (format) {
1750
case 'dbml':
18-
res = DbmlExporter.export(normalizedModel, resolvedFlags);
51+
res = DbmlExporter.export(normalizedModel, { includeRecords });
1952
break;
2053

2154
case 'mysql':
@@ -27,7 +60,7 @@ class ModelExporter {
2760
break;
2861

2962
case 'json':
30-
res = JsonExporter.export(model, resolvedFlags);
63+
res = JsonExporter.export(model, { isNormalized });
3164
break;
3265

3366
case 'mssql':

0 commit comments

Comments
 (0)