dbcat 0.0.2 → 0.0.3

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/README.md CHANGED
@@ -56,6 +56,14 @@ Connected to demo.sqlite
56
56
  ╰──────────────────────────────────────────────────────────────╯
57
57
  ```
58
58
 
59
+ ### Scrollable Output
60
+
61
+ Pipe to `less -R` for scrollable output with colors:
62
+
63
+ ```sh
64
+ bunx dbcat ./data.db --full | less -R
65
+ ```
66
+
59
67
  ## Requirements
60
68
 
61
69
  [Bun](https://bun.sh) v1.3+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dbcat",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "A simple CLI to view database tables. Supports PostgreSQL, MySQL, and SQLite.",
5
5
  "author": "RiskyMH",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -1,13 +1,12 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
- import { SQL } from "bun";
4
- import { printTable } from "./table.ts";
5
-
6
3
  if (typeof Bun !== "object") throw new Error("Please install & use bun!");
7
4
 
8
- export function createConnection(input?: string): InstanceType<typeof SQL> {
5
+ import { printTable } from "./table.ts";
6
+
7
+ export function createConnection(input?: string): InstanceType<typeof Bun.SQL> {
9
8
  if (!input) {
10
- return new SQL();
9
+ return new Bun.SQL();
11
10
  }
12
11
 
13
12
  if (
@@ -16,14 +15,14 @@ export function createConnection(input?: string): InstanceType<typeof SQL> {
16
15
  input.endsWith(".sqlite") ||
17
16
  input.endsWith(".sqlite3"))
18
17
  ) {
19
- return new SQL(`sqlite://${input}`);
18
+ return new Bun.SQL(`sqlite://${input}`);
20
19
  }
21
20
 
22
- return new SQL(input);
21
+ return new Bun.SQL(input);
23
22
  }
24
23
 
25
24
  export async function getDatabaseName(
26
- sql: InstanceType<typeof SQL>
25
+ sql: InstanceType<typeof Bun.SQL>
27
26
  ): Promise<string | null> {
28
27
  const adapter = sql.options.adapter;
29
28
 
@@ -38,17 +37,17 @@ export async function getDatabaseName(
38
37
  return result[0]?.name ?? null;
39
38
  }
40
39
  case "sqlite": {
41
- const filename = (sql.options as { filename?: string }).filename;
40
+ const filename = sql.options.filename;
42
41
  if (!filename || filename === ":memory:") return null;
43
42
 
44
- return filename.split("/").pop() ?? null;
43
+ return filename.toString().split("/").at(-1) ?? null;
45
44
  }
46
45
  default:
47
46
  return null;
48
47
  }
49
48
  }
50
49
 
51
- export function getAllTables(sql: InstanceType<typeof SQL>) {
50
+ export function getAllTables(sql: InstanceType<typeof Bun.SQL>) {
52
51
  const adapter = sql.options.adapter;
53
52
 
54
53
  switch (adapter) {
@@ -83,7 +82,7 @@ export function getAllTables(sql: InstanceType<typeof SQL>) {
83
82
  }
84
83
 
85
84
  export async function getTableCount(
86
- sql: InstanceType<typeof SQL>,
85
+ sql: InstanceType<typeof Bun.SQL>,
87
86
  tableName: string
88
87
  ): Promise<number> {
89
88
  const result = await sql`SELECT COUNT(*) as count FROM ${sql(tableName)}`;
@@ -91,72 +90,20 @@ export async function getTableCount(
91
90
  }
92
91
 
93
92
  export function getTableData(
94
- sql: InstanceType<typeof SQL>,
93
+ sql: InstanceType<typeof Bun.SQL>,
95
94
  tableName: string,
96
95
  limit?: number
97
- ) {
96
+ ): Promise<Record<string, unknown>[]> {
98
97
  if (limit === undefined) {
99
- return sql`SELECT * FROM ${sql(tableName)}` as Promise<
100
- Record<string, unknown>[]
101
- >;
98
+ return sql`SELECT * FROM ${sql(tableName)}`;
102
99
  }
103
- return sql`SELECT * FROM ${sql(tableName)} LIMIT ${limit}` as Promise<
104
- Record<string, unknown>[]
105
- >;
100
+ return sql`SELECT * FROM ${sql(tableName)} LIMIT ${limit}`;
106
101
  }
107
102
 
108
- export function runQuery(sql: InstanceType<typeof SQL>, query: string) {
103
+ export function runQuery(sql: InstanceType<typeof Bun.SQL>, query: string) {
109
104
  return sql.unsafe(query) as Promise<Record<string, unknown>[]>;
110
105
  }
111
106
 
112
- export function formatTableOutput(
113
- tableName: string,
114
- rows: Record<string, unknown>[]
115
- ): string {
116
- const lines: string[] = [];
117
- lines.push(`\n=== ${tableName} ===`);
118
-
119
- if (rows.length === 0) {
120
- lines.push("(empty table)");
121
- return lines.join("\n");
122
- }
123
-
124
- const maxRows = 100;
125
- const displayRows = rows.slice(0, maxRows);
126
-
127
- if (displayRows.length > 0) {
128
- const keys = Object.keys(displayRows[0]!);
129
- lines.push(keys.join(" | "));
130
- lines.push("-".repeat(keys.join(" | ").length));
131
- for (const row of displayRows) {
132
- lines.push(keys.map((k) => String(row[k] ?? "NULL")).join(" | "));
133
- }
134
- }
135
-
136
- if (rows.length > maxRows) {
137
- lines.push(`... and ${rows.length - maxRows} more rows`);
138
- }
139
-
140
- return lines.join("\n");
141
- }
142
-
143
- export function formatQueryResult(rows: Record<string, unknown>[]): string {
144
- if (rows.length === 0) {
145
- return "(no results)";
146
- }
147
-
148
- const lines: string[] = [];
149
- const keys = Object.keys(rows[0]!);
150
- lines.push(keys.join(" | "));
151
- lines.push("-".repeat(keys.join(" | ").length));
152
- for (const row of rows) {
153
- lines.push(keys.map((k) => String(row[k] ?? "NULL")).join(" | "));
154
- }
155
- lines.push(`\n${rows.length} row(s)`);
156
-
157
- return lines.join("\n");
158
- }
159
-
160
107
  function displayTable(
161
108
  tableName: string,
162
109
  rows: Record<string, unknown>[],
@@ -184,13 +131,11 @@ async function readStdin(): Promise<string | null> {
184
131
  }
185
132
  }
186
133
 
187
- type JsonMode = false | "plain" | "color";
188
-
189
134
  function parseArgs() {
190
135
  const args = process.argv.slice(2);
191
136
  let input: string | undefined;
192
137
  let full = false;
193
- let json: JsonMode = false;
138
+ let json: false | "plain" | "color" = false;
194
139
 
195
140
  for (const arg of args) {
196
141
  if (arg === "--full" || arg === "-f") {
@@ -237,7 +182,7 @@ async function main() {
237
182
  showUsageAndExit();
238
183
  }
239
184
 
240
- let sql: InstanceType<typeof SQL>;
185
+ let sql: InstanceType<typeof Bun.SQL>;
241
186
  try {
242
187
  sql = createConnection(input);
243
188
  } catch (error) {
@@ -250,7 +195,7 @@ async function main() {
250
195
  const dim = Bun.enableANSIColors ? "\x1b[2m" : "";
251
196
  const reset = Bun.enableANSIColors ? "\x1b[0m" : "";
252
197
  const bold = Bun.enableANSIColors ? "\x1b[1m" : "";
253
- const clearLine = "\x1b[2K\r";
198
+ const clearLine = Bun.enableANSIColors ? "\x1b[2K\r" : "";
254
199
 
255
200
  try {
256
201
  const stdinQuery = await readStdin();
@@ -263,7 +208,7 @@ async function main() {
263
208
  displayQueryResult(results);
264
209
  }
265
210
  } else {
266
- if (isTTY && !json) {
211
+ if (Bun.enableANSIColors && isTTY && !json) {
267
212
  process.stdout.write(
268
213
  `${dim}Connecting to ${sql.options.adapter}...${reset}`
269
214
  );
@@ -284,16 +229,11 @@ async function main() {
284
229
  }
285
230
  outputJson(result, json === "color");
286
231
  } else {
232
+ if (Bun.enableANSIColors && isTTY) process.stdout.write(clearLine);
287
233
  const dbDisplay = dbName
288
234
  ? `${bold}${dbName}${reset}`
289
235
  : `${bold}${sql.options.adapter}${reset} ${dim}database${reset}`;
290
- if (isTTY) {
291
- process.stdout.write(
292
- `${clearLine}${dim}Connected to${reset} ${dbDisplay}\n`
293
- );
294
- } else {
295
- console.log(`Connected to ${dbName || sql.options.adapter}`);
296
- }
236
+ console.log(`${dim}Connected to${reset} ${dbDisplay}`);
297
237
 
298
238
  if (tables.length === 0) {
299
239
  console.log(`${dim}No tables found.${reset}`);
@@ -314,7 +254,7 @@ async function main() {
314
254
  }
315
255
  }
316
256
  } catch (error) {
317
- if (isTTY && !json) {
257
+ if (Bun.enableANSIColors && isTTY && !json) {
318
258
  process.stdout.write(clearLine);
319
259
  }
320
260
  const message = error instanceof Error ? error.message : String(error);
package/src/table.ts CHANGED
@@ -17,7 +17,7 @@ const BOX = {
17
17
  };
18
18
 
19
19
  function getTerminalWidth(): number {
20
- return process.stdout.columns || 120;
20
+ return process.stdout.columns || process.stderr.columns || 120;
21
21
  }
22
22
 
23
23
  function formatValue(value: unknown): string {
@@ -87,10 +87,7 @@ export function printTable(
87
87
 
88
88
  if (rows.length === 0) {
89
89
  if (title) {
90
- const contentWidth = Math.max(
91
- Bun.stringWidth("(empty)"),
92
- Bun.stringWidth(title)
93
- );
90
+ const contentWidth = Math.max("(empty)".length, Bun.stringWidth(title));
94
91
  const innerWidth = contentWidth + 2;
95
92
  const titleDisplay = ` ${title} `;
96
93
  const titleWidth = Bun.stringWidth(titleDisplay);