dbml-metaquery 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.bun.js +17285 -0
- package/dist/index.bun.js +17056 -0
- package/package.json +8 -5
- package/src/cli.ts +0 -271
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dbml-metaquery",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Parse DBML into a navigable graph with rich metadata -- FK path finding, table info, groups, and schema search.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"dbml-metaquery": "./dist/cli.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"build": "rm -rf dist && bun build src/index.ts src/cli.ts --outdir dist --target node --format esm --sourcemap=linked && printf '#!/usr/bin/env node\\n' | cat - dist/cli.js > dist/cli.tmp && mv dist/cli.tmp dist/cli.js && bunx tsc --project tsconfig.build.json",
|
|
10
|
+
"build": "rm -rf dist && bun build src/index.ts src/cli.ts --outdir dist --target node --format esm --sourcemap=linked && bun build src/index.ts src/cli.ts --outdir dist --target bun --format esm --entry-naming '[dir]/[name].bun.[ext]' && printf '#!/usr/bin/env node\\n' | cat - dist/cli.js > dist/cli.tmp && mv dist/cli.tmp dist/cli.js && bunx tsc --project tsconfig.build.json",
|
|
11
11
|
"cli": "bun run src/cli.ts",
|
|
12
12
|
"test": "bun test",
|
|
13
13
|
"typecheck": "tsc --noEmit"
|
|
@@ -16,14 +16,17 @@
|
|
|
16
16
|
"types": "./dist/index.d.ts",
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
19
|
-
"README.md"
|
|
20
|
-
"src/cli.ts"
|
|
19
|
+
"README.md"
|
|
21
20
|
],
|
|
22
21
|
"exports": {
|
|
23
22
|
".": {
|
|
24
|
-
"bun": "./
|
|
23
|
+
"bun": "./dist/index.bun.js",
|
|
25
24
|
"import": "./dist/index.js",
|
|
26
25
|
"types": "./dist/index.d.ts"
|
|
26
|
+
},
|
|
27
|
+
"./cli": {
|
|
28
|
+
"bun": "./dist/cli.bun.js",
|
|
29
|
+
"import": "./dist/cli.js"
|
|
27
30
|
}
|
|
28
31
|
},
|
|
29
32
|
"dependencies": {
|
package/src/cli.ts
DELETED
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLI for dbml-metaquery.
|
|
3
|
-
*
|
|
4
|
-
* Usage:
|
|
5
|
-
* dbml-metaquery <dbml-path> find-path <from> <to>
|
|
6
|
-
* dbml-metaquery <dbml-path> info <table>
|
|
7
|
-
* dbml-metaquery <dbml-path> neighbors <table>
|
|
8
|
-
* dbml-metaquery <dbml-path> refs-to <table>
|
|
9
|
-
* dbml-metaquery <dbml-path> rels <table>
|
|
10
|
-
* dbml-metaquery <dbml-path> search <query>
|
|
11
|
-
* dbml-metaquery <dbml-path> summary
|
|
12
|
-
* dbml-metaquery <dbml-path> tables
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { readFileSync, existsSync } from "node:fs"
|
|
16
|
-
import { resolve } from "node:path"
|
|
17
|
-
import { DbmlGraph } from "./graph"
|
|
18
|
-
|
|
19
|
-
const args = process.argv.slice(2)
|
|
20
|
-
|
|
21
|
-
if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
|
|
22
|
-
console.log("Usage: dbml-metaquery <dbml-path> <command> [args]")
|
|
23
|
-
console.log()
|
|
24
|
-
console.log("Parse DBML into a navigable graph with rich metadata.")
|
|
25
|
-
console.log()
|
|
26
|
-
console.log("Commands:")
|
|
27
|
-
console.log(" find-path <from> <to> Find shortest FK path between tables")
|
|
28
|
-
console.log(" info <table> Show table metadata (note, columns, group)")
|
|
29
|
-
console.log(" neighbors <table> Show tables directly connected via FK")
|
|
30
|
-
console.log(" refs-to <table> Show tables that reference this table")
|
|
31
|
-
console.log(" rels <table> Show all FK relationships for a table")
|
|
32
|
-
console.log(" search <query> Search table/column names and notes")
|
|
33
|
-
console.log(" summary Show schema overview (groups and table counts)")
|
|
34
|
-
console.log(" tables List all table names")
|
|
35
|
-
process.exit(0)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const dbmlPath = resolve(args[0]!)
|
|
39
|
-
if (!existsSync(dbmlPath)) {
|
|
40
|
-
console.error(`DBML file not found: ${dbmlPath}`)
|
|
41
|
-
process.exit(1)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const command = args[1]
|
|
45
|
-
if (!command) {
|
|
46
|
-
console.error("No command provided. Use --help for usage.")
|
|
47
|
-
process.exit(1)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const dbml = readFileSync(dbmlPath, "utf-8")
|
|
51
|
-
const graph = new DbmlGraph(dbml)
|
|
52
|
-
const cmdArgs = args.slice(2)
|
|
53
|
-
|
|
54
|
-
switch (command) {
|
|
55
|
-
case "tables": {
|
|
56
|
-
const tables = graph.getTables()
|
|
57
|
-
console.log(`${tables.length} tables:\n`)
|
|
58
|
-
for (const t of tables) {
|
|
59
|
-
console.log(` ${t}`)
|
|
60
|
-
}
|
|
61
|
-
break
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
case "summary": {
|
|
65
|
-
const summary = graph.getSummary()
|
|
66
|
-
const total = summary.reduce((n, g) => n + g.tableCount, 0)
|
|
67
|
-
console.log(`${total} tables in ${summary.length} groups:\n`)
|
|
68
|
-
for (const group of summary) {
|
|
69
|
-
const color = graph.getGroupColor(group.name)
|
|
70
|
-
const colorStr = color ? ` \x1b[2m${color}\x1b[0m` : ""
|
|
71
|
-
console.log(` \x1b[1m${group.name}\x1b[0m (${group.tableCount})${colorStr}`)
|
|
72
|
-
for (const t of group.tables) {
|
|
73
|
-
console.log(` ${t}`)
|
|
74
|
-
}
|
|
75
|
-
console.log()
|
|
76
|
-
}
|
|
77
|
-
break
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
case "info": {
|
|
81
|
-
if (!cmdArgs[0]) {
|
|
82
|
-
console.error("Usage: dbml-metaquery <dbml-path> info <table>")
|
|
83
|
-
process.exit(1)
|
|
84
|
-
}
|
|
85
|
-
const table = graph.getTable(cmdArgs[0])
|
|
86
|
-
if (!table) {
|
|
87
|
-
console.error(`Table "${cmdArgs[0]}" not found`)
|
|
88
|
-
process.exit(1)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
console.log(`\x1b[1m${table.name}\x1b[0m`)
|
|
92
|
-
if (table.note) {
|
|
93
|
-
console.log(` ${table.note}`)
|
|
94
|
-
}
|
|
95
|
-
const color = graph.getTableColor(table.name)
|
|
96
|
-
if (color) {
|
|
97
|
-
console.log(` \x1b[2mcolor:\x1b[0m ${color}`)
|
|
98
|
-
}
|
|
99
|
-
const group = graph.getGroup(table.name)
|
|
100
|
-
if (group) {
|
|
101
|
-
console.log(` \x1b[2mgroup:\x1b[0m ${group.name} (${group.tables.length} tables)`)
|
|
102
|
-
}
|
|
103
|
-
console.log()
|
|
104
|
-
console.log(` \x1b[2mColumns:\x1b[0m`)
|
|
105
|
-
for (const col of table.columns) {
|
|
106
|
-
let line = ` ${col.name} \x1b[2m${col.type}\x1b[0m`
|
|
107
|
-
if (col.fk) {
|
|
108
|
-
line += ` \x1b[33m-> ${col.fk.table}.${col.fk.column}\x1b[0m`
|
|
109
|
-
}
|
|
110
|
-
if (col.note) {
|
|
111
|
-
line += `\n \x1b[2m${col.note}\x1b[0m`
|
|
112
|
-
}
|
|
113
|
-
console.log(line)
|
|
114
|
-
}
|
|
115
|
-
break
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
case "neighbors": {
|
|
119
|
-
if (!cmdArgs[0]) {
|
|
120
|
-
console.error("Usage: dbml-metaquery <dbml-path> neighbors <table>")
|
|
121
|
-
process.exit(1)
|
|
122
|
-
}
|
|
123
|
-
if (!graph.getTable(cmdArgs[0])) {
|
|
124
|
-
console.error(`Table "${cmdArgs[0]}" not found`)
|
|
125
|
-
process.exit(1)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const n = graph.getNeighbors(cmdArgs[0])
|
|
129
|
-
console.log(`\x1b[1m${cmdArgs[0]}\x1b[0m\n`)
|
|
130
|
-
|
|
131
|
-
if (n.parents.length > 0) {
|
|
132
|
-
console.log(` \x1b[2mParents (tables I reference):\x1b[0m`)
|
|
133
|
-
for (const p of n.parents) {
|
|
134
|
-
console.log(` \x1b[33m${p.via}\x1b[0m -> ${p.table}`)
|
|
135
|
-
}
|
|
136
|
-
console.log()
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (n.children.length > 0) {
|
|
140
|
-
console.log(` \x1b[2mChildren (tables that reference me):\x1b[0m`)
|
|
141
|
-
for (const c of n.children) {
|
|
142
|
-
console.log(` ${c.table}.\x1b[33m${c.via}\x1b[0m`)
|
|
143
|
-
}
|
|
144
|
-
console.log()
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (n.parents.length === 0 && n.children.length === 0) {
|
|
148
|
-
console.log(" No FK connections.")
|
|
149
|
-
}
|
|
150
|
-
break
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
case "refs-to": {
|
|
154
|
-
if (!cmdArgs[0]) {
|
|
155
|
-
console.error("Usage: dbml-metaquery <dbml-path> refs-to <table>")
|
|
156
|
-
process.exit(1)
|
|
157
|
-
}
|
|
158
|
-
const refs = graph.getReferencingTables(cmdArgs[0])
|
|
159
|
-
|
|
160
|
-
if (refs.length === 0) {
|
|
161
|
-
console.log(`No tables reference "${cmdArgs[0]}"`)
|
|
162
|
-
} else {
|
|
163
|
-
console.log(`${refs.length} tables reference \x1b[1m${cmdArgs[0]}\x1b[0m:\n`)
|
|
164
|
-
for (const r of refs) {
|
|
165
|
-
console.log(` ${r.table}.\x1b[33m${r.column}\x1b[0m -> ${cmdArgs[0]}.\x1b[33m${r.myColumn}\x1b[0m`)
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
break
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
case "rels": {
|
|
172
|
-
if (!cmdArgs[0]) {
|
|
173
|
-
console.error("Usage: dbml-metaquery <dbml-path> rels <table>")
|
|
174
|
-
process.exit(1)
|
|
175
|
-
}
|
|
176
|
-
const rels = graph.getRelationships(cmdArgs[0])
|
|
177
|
-
if (rels.length === 0) {
|
|
178
|
-
console.log(`No relationships found for "${cmdArgs[0]}"`)
|
|
179
|
-
} else {
|
|
180
|
-
console.log(`${rels.length} relationships for "${cmdArgs[0]}":\n`)
|
|
181
|
-
for (const r of rels) {
|
|
182
|
-
const direction =
|
|
183
|
-
r.childTable === cmdArgs[0]
|
|
184
|
-
? ` ${r.childTable}.${r.childColumn} -> ${r.parentTable}.${r.parentColumn}`
|
|
185
|
-
: ` ${r.parentTable}.${r.parentColumn} <- ${r.childTable}.${r.childColumn}`
|
|
186
|
-
console.log(direction)
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
break
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
case "search": {
|
|
193
|
-
if (!cmdArgs[0]) {
|
|
194
|
-
console.error("Usage: dbml-metaquery <dbml-path> search <query>")
|
|
195
|
-
process.exit(1)
|
|
196
|
-
}
|
|
197
|
-
const results = graph.searchSchema(cmdArgs[0])
|
|
198
|
-
|
|
199
|
-
if (results.length === 0) {
|
|
200
|
-
console.log(`No matches for "${cmdArgs[0]}"`)
|
|
201
|
-
} else {
|
|
202
|
-
console.log(`${results.length} matches for "\x1b[1m${cmdArgs[0]}\x1b[0m":\n`)
|
|
203
|
-
for (const r of results) {
|
|
204
|
-
switch (r.match) {
|
|
205
|
-
case "table_name":
|
|
206
|
-
console.log(` \x1b[1m${r.table}\x1b[0m \x1b[2m(table)\x1b[0m`)
|
|
207
|
-
break
|
|
208
|
-
case "table_note":
|
|
209
|
-
console.log(` \x1b[1m${r.table}\x1b[0m \x1b[2m(note: ${r.text})\x1b[0m`)
|
|
210
|
-
break
|
|
211
|
-
case "column_name":
|
|
212
|
-
console.log(` ${r.table}.\x1b[33m${r.column}\x1b[0m \x1b[2m(column)\x1b[0m`)
|
|
213
|
-
break
|
|
214
|
-
case "column_note":
|
|
215
|
-
console.log(` ${r.table}.\x1b[33m${r.column}\x1b[0m \x1b[2m(note: ${r.text})\x1b[0m`)
|
|
216
|
-
break
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
break
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
case "find-path": {
|
|
224
|
-
const [fromTable, toTable] = cmdArgs
|
|
225
|
-
if (!fromTable || !toTable) {
|
|
226
|
-
console.error("Usage: dbml-metaquery <dbml-path> find-path <from> <to>")
|
|
227
|
-
process.exit(1)
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
try {
|
|
231
|
-
const path = graph.findPath(fromTable, toTable)
|
|
232
|
-
|
|
233
|
-
if (path === null) {
|
|
234
|
-
console.log(`No path found from "${fromTable}" to "${toTable}"`)
|
|
235
|
-
process.exit(1)
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (path.length === 0) {
|
|
239
|
-
console.log(`"${fromTable}" and "${toTable}" are the same table.`)
|
|
240
|
-
break
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
console.log(
|
|
244
|
-
`Path from \x1b[1m${fromTable}\x1b[0m to \x1b[1m${toTable}\x1b[0m (${path.length} hop${path.length > 1 ? "s" : ""}):\n`,
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
for (const step of path) {
|
|
248
|
-
console.log(
|
|
249
|
-
` ${step.from.table}.\x1b[33m${step.from.column}\x1b[0m -> ${step.to.table}.\x1b[33m${step.to.column}\x1b[0m`,
|
|
250
|
-
)
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
console.log()
|
|
254
|
-
console.log("\x1b[2mSQL:\x1b[0m")
|
|
255
|
-
console.log(` \x1b[2mFROM\x1b[0m ${fromTable}`)
|
|
256
|
-
for (const step of path) {
|
|
257
|
-
console.log(
|
|
258
|
-
` \x1b[2mJOIN\x1b[0m ${step.to.table} \x1b[2mON\x1b[0m ${step.from.table}.${step.from.column} = ${step.to.table}.${step.to.column}`,
|
|
259
|
-
)
|
|
260
|
-
}
|
|
261
|
-
} catch (err) {
|
|
262
|
-
console.error(err instanceof Error ? err.message : String(err))
|
|
263
|
-
process.exit(1)
|
|
264
|
-
}
|
|
265
|
-
break
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
default:
|
|
269
|
-
console.error(`Unknown command: ${command}. Use --help for usage.`)
|
|
270
|
-
process.exit(1)
|
|
271
|
-
}
|