PHP Classes

File: resources/js/dbml-export.js

Recommend this page to a friend!
  Packages of Alberto Arena   Laravel Truss   resources/js/dbml-export.js   Download  
File: resources/js/dbml-export.js
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Laravel Truss
View a diagram of a Laravel application models
Author: By
Last change:
Date: 8 days ago
Size: 3,007 bytes
 

Contents

Class file image Download
// Pure DBML serializer for the in-browser schema snapshot. Structure only, // never row data. Whole-schema: a Table block per table, then Ref lines for the // foreign keys. Opens in dbdiagram.io and other DBML tools. Unit-tested in // tests/js/dbml-export.test.js. // // Type mapping is deliberately lossy: the native type is passed through, quoted // only when it would otherwise misparse (same stance as the native-vs-Laravel // label caveat in docs/DESIGN.md). function typeToken(type) { const t = type == null ? '' : String(type); return /[\s,"']/.test(t) ? `"${t.replace(/"/g, '\\"')}"` : t; } function defaultToken(value) { const s = String(value); if (/^-?\d+(\.\d+)?$/.test(s)) return s; // number, bare if (/^(true|false|null)$/i.test(s)) return s.toLowerCase(); // boolean/null keyword if (/^current_timestamp/i.test(s) || /\(/.test(s)) return `\`${s}\``; // SQL expression return `'${s.replace(/'/g, "\\'")}'`; // string literal } function columnLine(table, col) { const pk = table.primary_key ?? []; const solePk = pk.length === 1 && pk[0] === col.name; const parts = []; // A composite PK is expressed in the indexes block, not on the column, so only // a sole PK gets [pk]; pk implies not null, so do not also emit it there. if (solePk) parts.push('pk'); else if (!col.nullable) parts.push('not null'); if (col.default != null) parts.push(`default: ${defaultToken(col.default)}`); const settings = parts.length ? ` [${parts.join(', ')}]` : ''; return ` ${col.name} ${typeToken(col.type)}${settings}`; } function tableToDbml(table) { const lines = [`Table ${table.name} {`]; for (const c of table.columns ?? []) lines.push(columnLine(table, c)); const idx = []; const pk = table.primary_key ?? []; if (pk.length > 1) idx.push(` (${pk.join(', ')}) [pk]`); for (const i of table.indexes ?? []) { const cols = i.columns.length > 1 ? `(${i.columns.join(', ')})` : i.columns[0]; idx.push(` ${cols}${i.unique ? ' [unique]' : ''}`); } if (idx.length) lines.push('', ' indexes {', ...idx, ' }'); lines.push('}'); return lines.join('\n'); } // Ref lines are emitted only when the referenced table is also in the export // set, so a filtered/focused export never produces a dangling (invalid) Ref. function refLines(tables) { const present = new Set(tables.map((t) => t.name)); const refs = []; for (const t of tables) { for (const f of t.foreign_keys ?? []) { if (!present.has(f.references_table)) continue; const src = f.columns.length > 1 ? `(${f.columns.join(', ')})` : f.columns[0]; const tgt = f.references_columns.length > 1 ? `(${f.references_columns.join(', ')})` : f.references_columns[0]; refs.push(`Ref: ${t.name}.${src} > ${f.references_table}.${tgt}`); } } return refs; } export function schemaToDbml(tables) { const list = tables ?? []; return [...list.map(tableToDbml), ...refLines(list)].join('\n\n') + '\n'; }