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.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
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
+ }