quickerquery 0.0.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/index.d.ts +2 -0
- package/dist/index.js +102 -0
- package/package.json +40 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import { render, Box, Text, useApp, useInput } from 'ink';
|
|
5
|
+
import TextInput from 'ink-mini-code-editor';
|
|
6
|
+
import pg from 'pg';
|
|
7
|
+
function parseJdbcUrl(url) {
|
|
8
|
+
// Parse jdbc:postgresql://host:port/database
|
|
9
|
+
const match = url.match(/^jdbc:postgresql:\/\/([^:]+):(\d+)\/(.+)$/);
|
|
10
|
+
if (!match) {
|
|
11
|
+
throw new Error(`Invalid JDBC URL format. Expected: jdbc:postgresql://host:port/database`);
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
host: match[1],
|
|
15
|
+
port: parseInt(match[2], 10),
|
|
16
|
+
database: match[3],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const App = ({ config }) => {
|
|
20
|
+
const { exit } = useApp();
|
|
21
|
+
const [state, setState] = useState('username');
|
|
22
|
+
const [username, setUsername] = useState('');
|
|
23
|
+
const [password, setPassword] = useState('');
|
|
24
|
+
const [error, setError] = useState('');
|
|
25
|
+
const [client, setClient] = useState(null);
|
|
26
|
+
const [query, setQuery] = useState('SELECT 1');
|
|
27
|
+
useInput((input, key) => {
|
|
28
|
+
if (key.ctrl && input === 'c') {
|
|
29
|
+
if (client) {
|
|
30
|
+
client.end();
|
|
31
|
+
}
|
|
32
|
+
exit();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
const handleUsernameSubmit = () => {
|
|
36
|
+
setState('password');
|
|
37
|
+
};
|
|
38
|
+
const handlePasswordSubmit = () => {
|
|
39
|
+
setState('connecting');
|
|
40
|
+
};
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (state !== 'connecting')
|
|
43
|
+
return;
|
|
44
|
+
const newClient = new pg.Client({
|
|
45
|
+
host: config.host,
|
|
46
|
+
port: config.port,
|
|
47
|
+
database: config.database,
|
|
48
|
+
user: username,
|
|
49
|
+
password: password,
|
|
50
|
+
});
|
|
51
|
+
newClient
|
|
52
|
+
.connect()
|
|
53
|
+
.then(() => {
|
|
54
|
+
setClient(newClient);
|
|
55
|
+
setState('connected');
|
|
56
|
+
})
|
|
57
|
+
.catch((err) => {
|
|
58
|
+
setError(err.message);
|
|
59
|
+
setState('error');
|
|
60
|
+
});
|
|
61
|
+
return () => {
|
|
62
|
+
if (newClient) {
|
|
63
|
+
newClient.end().catch(() => { });
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}, [state, config, username, password]);
|
|
67
|
+
const handleQuerySubmit = async () => {
|
|
68
|
+
// Query execution will be implemented next
|
|
69
|
+
console.log('Query:', query);
|
|
70
|
+
};
|
|
71
|
+
// Error state
|
|
72
|
+
if (state === 'error') {
|
|
73
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Text, { bold: true, color: "red", children: "Connection Failed" }), _jsx(Text, { color: "red", children: error }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Press Ctrl+C to exit" }) })] }));
|
|
74
|
+
}
|
|
75
|
+
// Connecting state
|
|
76
|
+
if (state === 'connecting') {
|
|
77
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Text, { bold: true, children: "QuickQuery" }), _jsxs(Text, { dimColor: true, children: [config.host, ":", config.port, "/", config.database] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: "Connecting..." }) })] }));
|
|
78
|
+
}
|
|
79
|
+
// Connected - show query editor
|
|
80
|
+
if (state === 'connected') {
|
|
81
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "green", children: "Connected" }), _jsxs(Text, { dimColor: true, children: [" ", username, "@", config.host, ":", config.port, "/", config.database] })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "Enter SQL query (press Enter to execute):" }), _jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: "> " }), _jsx(TextInput, { value: query, onChange: setQuery, onSubmit: handleQuerySubmit, language: "sql", placeholder: "SELECT * FROM ..." })] })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Ctrl+C to exit" }) })] }));
|
|
82
|
+
}
|
|
83
|
+
// Login prompts
|
|
84
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Text, { bold: true, children: "QuickQuery" }), _jsxs(Text, { dimColor: true, children: [config.host, ":", config.port, "/", config.database] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { children: "Username: " }), state === 'username' ? (_jsx(TextInput, { value: username, onChange: setUsername, onSubmit: handleUsernameSubmit, placeholder: "Enter username" })) : (_jsx(Text, { children: username }))] }), state === 'password' && (_jsxs(Box, { children: [_jsx(Text, { children: "Password: " }), _jsx(TextInput, { value: password, onChange: setPassword, onSubmit: handlePasswordSubmit, placeholder: "Enter password", mask: "*" })] }))] })] }));
|
|
85
|
+
};
|
|
86
|
+
// Parse CLI arguments
|
|
87
|
+
const args = process.argv.slice(2);
|
|
88
|
+
const databaseUrl = args[0];
|
|
89
|
+
if (!databaseUrl) {
|
|
90
|
+
console.error('Usage: qq <database-url>');
|
|
91
|
+
console.error('Example: qq jdbc:postgresql://localhost:5432/postgres');
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
let config;
|
|
95
|
+
try {
|
|
96
|
+
config = parseJdbcUrl(databaseUrl);
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
console.error(err.message);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
render(_jsx(App, { config: config }));
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "quickerquery",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A terminal-based database query tool inspired by JetBrains DataGrip",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"qq": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"database",
|
|
15
|
+
"sql",
|
|
16
|
+
"postgresql",
|
|
17
|
+
"tui",
|
|
18
|
+
"cli",
|
|
19
|
+
"terminal",
|
|
20
|
+
"query"
|
|
21
|
+
],
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"ink": "^6.6.0",
|
|
24
|
+
"ink-mini-code-editor": "^0.0.1",
|
|
25
|
+
"pg": "^8.16.3",
|
|
26
|
+
"react": "^19.2.3"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^25.0.5",
|
|
30
|
+
"@types/pg": "^8.16.0",
|
|
31
|
+
"@types/react": "^19.2.7",
|
|
32
|
+
"tsx": "^4.21.0",
|
|
33
|
+
"typescript": "^5.9.3"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"dev": "tsx src/index.tsx",
|
|
37
|
+
"start": "tsx src/index.tsx",
|
|
38
|
+
"build": "tsc"
|
|
39
|
+
}
|
|
40
|
+
}
|