dbcat 0.0.4 → 0.0.6

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.
Files changed (3) hide show
  1. package/README.md +10 -9
  2. package/package.json +5 -1
  3. package/src/index.ts +56 -11
package/README.md CHANGED
@@ -11,32 +11,33 @@ bunx dbcat ./data.db
11
11
  Connect to a database to browse all tables:
12
12
 
13
13
  ```sh
14
- # SQLite file
14
+ # No argument - uses DATABASE_URL environment variable
15
+ bunx dbcat
16
+
17
+ # SQLite
15
18
  bunx dbcat ./database.sqlite
19
+ bunx dbcat https://example.com/data.db
16
20
 
17
21
  # PostgreSQL
18
22
  bunx dbcat postgres://user:pass@localhost:5432/mydb
19
23
 
20
24
  # MySQL
21
25
  bunx dbcat mysql://user:pass@localhost:3306/mydb
22
-
23
- # No argument - uses DATABASE_URL environment variable
24
- bunx dbcat
25
26
  ```
26
27
 
27
28
  Run a query by piping SQL:
28
29
 
29
30
  ```sh
30
- echo "SELECT * FROM users WHERE active = true" | bunx dbcat ./data.db
31
+ echo "SELECT * FROM users" | bunx dbcat ./data.db
31
32
  ```
32
33
 
33
34
  ### Options
34
35
 
35
- | Flag | Description |
36
- |------|-------------|
36
+ | Flag | Description |
37
+ |----------------|---------------------------------------------------|
37
38
  | `--full`, `-f` | Show all rows when browsing tables (default: 100) |
38
- | `--json` | Output as JSON (indented if TTY) |
39
- | `--json=color` | Output as normal object console.log |
39
+ | `--json` | Output as JSON (indented if TTY) |
40
+ | `--json=color` | Output as normal object console.log |
40
41
 
41
42
  Piped queries always return all rows.
42
43
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dbcat",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "A simple CLI to view database tables. Supports PostgreSQL, MySQL, and SQLite.",
5
5
  "author": "RiskyMH",
6
6
  "license": "MIT",
@@ -12,6 +12,10 @@
12
12
  "bugs": {
13
13
  "url": "https://github.com/RiskyMH/dbcat/issues"
14
14
  },
15
+ "engines": {
16
+ "bun": ">=1.0.0"
17
+ },
18
+ "sideEffects": false,
15
19
  "keywords": [
16
20
  "database",
17
21
  "cli",
package/src/index.ts CHANGED
@@ -3,6 +3,11 @@
3
3
  if (typeof Bun !== "object") throw new Error("Please install & use bun!");
4
4
 
5
5
  import { printTable } from "./table.ts";
6
+ import { tmpdir } from "node:os";
7
+ import { join } from "node:path";
8
+
9
+ const SQLITE_EXTENSIONS = [".db", ".sqlite", ".sqlite3", ".db3", ".s3db"];
10
+ const REMOTE_PROTOCOLS = ["http://", "https://", "s3://"];
6
11
 
7
12
  export function createConnection(input?: string): InstanceType<typeof Bun.SQL> {
8
13
  if (!input) {
@@ -11,9 +16,7 @@ export function createConnection(input?: string): InstanceType<typeof Bun.SQL> {
11
16
 
12
17
  if (
13
18
  !input.includes("://") &&
14
- (input.endsWith(".db") ||
15
- input.endsWith(".sqlite") ||
16
- input.endsWith(".sqlite3"))
19
+ SQLITE_EXTENSIONS.some((ext) => input.endsWith(ext))
17
20
  ) {
18
21
  return new Bun.SQL(`sqlite://${input}`);
19
22
  }
@@ -21,6 +24,22 @@ export function createConnection(input?: string): InstanceType<typeof Bun.SQL> {
21
24
  return new Bun.SQL(input);
22
25
  }
23
26
 
27
+ async function downloadToTmp(url: string): Promise<string> {
28
+ const response = await fetch(url);
29
+ if (!response.ok) {
30
+ throw new Error(
31
+ `Failed to download: ${response.status} ${response.statusText}`
32
+ );
33
+ }
34
+
35
+ const urlPath = new URL(url).pathname;
36
+ const filename = urlPath.split("/").at(-1) || "downloaded.db";
37
+ const tmpPath = join(tmpdir(), `dbcat-${Bun.hash(url)}-${filename}`);
38
+ await Bun.write(tmpPath, response);
39
+
40
+ return tmpPath;
41
+ }
42
+
24
43
  export async function getDatabaseName(
25
44
  sql: InstanceType<typeof Bun.SQL>
26
45
  ): Promise<string | null> {
@@ -164,6 +183,7 @@ function showUsageAndExit(): never {
164
183
  console.error(" dbcat ./data.db");
165
184
  console.error(" dbcat postgres://user:pass@localhost/mydb");
166
185
  console.error(" dbcat mysql://user:pass@localhost/mydb");
186
+ console.error(" dbcat https://example.com/data.db");
167
187
  console.error("");
168
188
  console.error("Or set DATABASE_URL environment variable.");
169
189
  process.exit(1);
@@ -185,21 +205,46 @@ async function main() {
185
205
  showUsageAndExit();
186
206
  }
187
207
 
208
+ const isTTY = process.stdout.isTTY;
209
+ const dim = Bun.enableANSIColors ? "\x1b[2m" : "";
210
+ const reset = Bun.enableANSIColors ? "\x1b[0m" : "";
211
+ const bold = Bun.enableANSIColors ? "\x1b[1m" : "";
212
+ const clearLine = Bun.enableANSIColors ? "\x1b[2K\r" : "";
213
+
214
+ // Handle remote URLs pointing to SQLite files
215
+ let connectionInput = input;
216
+ if (
217
+ input &&
218
+ REMOTE_PROTOCOLS.some((p) => input.startsWith(p)) &&
219
+ SQLITE_EXTENSIONS.some((ext) => input.endsWith(ext))
220
+ ) {
221
+ if (Bun.enableANSIColors && isTTY && !json) {
222
+ process.stdout.write(`${dim}Downloading SQLite database...${reset}`);
223
+ }
224
+ try {
225
+ connectionInput = `sqlite://${await downloadToTmp(input)}`;
226
+ } catch (error) {
227
+ if (Bun.enableANSIColors && isTTY && !json) {
228
+ process.stdout.write("\n");
229
+ }
230
+ console.error("Failed to download:");
231
+ console.error(error instanceof Error ? error.message : String(error));
232
+ process.exit(1);
233
+ }
234
+ if (Bun.enableANSIColors && isTTY && !json) {
235
+ process.stdout.write(clearLine);
236
+ }
237
+ }
238
+
188
239
  let sql: InstanceType<typeof Bun.SQL>;
189
240
  try {
190
- sql = createConnection(input);
241
+ sql = createConnection(connectionInput);
191
242
  } catch (error) {
192
243
  console.error("Failed to connect:");
193
244
  console.error(error instanceof Error ? error.message : String(error));
194
245
  process.exit(1);
195
246
  }
196
247
 
197
- const isTTY = process.stdout.isTTY;
198
- const dim = Bun.enableANSIColors ? "\x1b[2m" : "";
199
- const reset = Bun.enableANSIColors ? "\x1b[0m" : "";
200
- const bold = Bun.enableANSIColors ? "\x1b[1m" : "";
201
- const clearLine = Bun.enableANSIColors ? "\x1b[2K\r" : "";
202
-
203
248
  try {
204
249
  const stdinQuery = await readStdin();
205
250
 
@@ -258,7 +303,7 @@ async function main() {
258
303
  }
259
304
  } catch (error) {
260
305
  if (Bun.enableANSIColors && isTTY && !json) {
261
- process.stdout.write(clearLine);
306
+ process.stdout.write("\n");
262
307
  }
263
308
  const message = error instanceof Error ? error.message : String(error);
264
309