@deaquinodev/querky 0.4.6 → 0.4.8
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.js +131 -114
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.tsx
|
|
4
|
-
import { useState as
|
|
4
|
+
import { useState as useState6, useEffect as useEffect5 } from "react";
|
|
5
5
|
import { parseArgs } from "util";
|
|
6
6
|
import { render, Box as Box9, Text as Text9 } from "ink";
|
|
7
7
|
|
|
@@ -193,11 +193,11 @@ async function connectDsn(dsn) {
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
// src/ui/components/App.tsx
|
|
196
|
-
import { useState as
|
|
196
|
+
import { useState as useState4, useEffect as useEffect4, useRef as useRef2 } from "react";
|
|
197
197
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
198
198
|
import { homedir as homedir4 } from "os";
|
|
199
|
-
import { join as
|
|
200
|
-
import { Box as Box7, Text as Text7,
|
|
199
|
+
import { join as join5 } from "path";
|
|
200
|
+
import { Box as Box7, Text as Text7, useApp, useInput as useInput2, useStdin as useStdin2, Static } from "ink";
|
|
201
201
|
|
|
202
202
|
// src/db/query.ts
|
|
203
203
|
async function runQuery(client, sql) {
|
|
@@ -1050,7 +1050,7 @@ async function fetchSchema(client, driver) {
|
|
|
1050
1050
|
}
|
|
1051
1051
|
|
|
1052
1052
|
// src/ui/components/QueryInput.tsx
|
|
1053
|
-
import { useEffect as useEffect2 } from "react";
|
|
1053
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
1054
1054
|
import { Box, Text } from "ink";
|
|
1055
1055
|
|
|
1056
1056
|
// src/ui/hooks/useVimInput.ts
|
|
@@ -1620,8 +1620,13 @@ function QueryInput({ onSubmit, isLoading, onModeChange, onShellModeChange, vimE
|
|
|
1620
1620
|
const isShellMode = value.startsWith("!");
|
|
1621
1621
|
const isCommand = !isShellMode && value.startsWith("/");
|
|
1622
1622
|
const partial = isCommand ? value.slice(1) : "";
|
|
1623
|
-
const
|
|
1623
|
+
const liveSuggestions = isCommand ? getCompletions(partial, aliases) : !isShellMode && schema ? getSqlCompletions(value, cursorPos, schema) : [];
|
|
1624
1624
|
const sqlToken = isCommand ? "" : getCurrentToken(value, cursorPos);
|
|
1625
|
+
const [suggestions, setSuggestions] = useState2([]);
|
|
1626
|
+
useEffect2(() => {
|
|
1627
|
+
const t = setTimeout(() => setSuggestions(liveSuggestions), 150);
|
|
1628
|
+
return () => clearTimeout(t);
|
|
1629
|
+
}, [value, cursorPos]);
|
|
1625
1630
|
const descMap = {
|
|
1626
1631
|
...BUILTIN_DESC_MAP,
|
|
1627
1632
|
...Object.fromEntries(
|
|
@@ -1644,7 +1649,7 @@ function QueryInput({ onSubmit, isLoading, onModeChange, onShellModeChange, vimE
|
|
|
1644
1649
|
const isMultiLine = !isEmpty && !isShellMode && !isCommand && value.includes("\n");
|
|
1645
1650
|
const dOff = isShellMode ? 2 : 0;
|
|
1646
1651
|
const placeholder = "Type a SQL query\u2026";
|
|
1647
|
-
const previewResult = !isMultiLine && suggestionIndex >= 0 &&
|
|
1652
|
+
const previewResult = !isMultiLine && suggestionIndex >= 0 && liveSuggestions.length > 0 ? handleSuggestionAccept(value, cursorPos, liveSuggestions[suggestionIndex]) : null;
|
|
1648
1653
|
const renderValue = previewResult?.value ?? value;
|
|
1649
1654
|
const renderCursor = previewResult?.cursor ?? cursorPos;
|
|
1650
1655
|
const lineWidth = innerWidth - 4;
|
|
@@ -1667,6 +1672,17 @@ function QueryInput({ onSubmit, isLoading, onModeChange, onShellModeChange, vimE
|
|
|
1667
1672
|
0
|
|
1668
1673
|
);
|
|
1669
1674
|
const hintsInline = totalHintsWidth <= termWidth;
|
|
1675
|
+
const STRIP_VISIBLE = 4;
|
|
1676
|
+
const stripPrefixW = isCommand ? 1 : 0;
|
|
1677
|
+
const stripAvailW = termWidth - 2 - 3 - (STRIP_VISIBLE - 1) * 3 - STRIP_VISIBLE * stripPrefixW;
|
|
1678
|
+
const stripMaxPerItem = Math.max(6, Math.floor(stripAvailW / STRIP_VISIBLE));
|
|
1679
|
+
const hasSuggestions = !isEmpty && !isShellMode && !isMultiLine && suggestions.length > 0;
|
|
1680
|
+
const stripWinStart = hasSuggestions ? Math.min(Math.max(0, suggestionIndex - 1), Math.max(0, suggestions.length - STRIP_VISIBLE)) : 0;
|
|
1681
|
+
const stripWindow = hasSuggestions ? suggestions.slice(stripWinStart, stripWinStart + STRIP_VISIBLE) : [];
|
|
1682
|
+
const stripNavHint = hasSuggestions ? `Tab/\u2191\u2193 navigate Enter select ${suggestionIndex + 1}/${suggestions.length}` : " ";
|
|
1683
|
+
function truncateSugg(s) {
|
|
1684
|
+
return s.length > stripMaxPerItem ? s.slice(0, stripMaxPerItem - 1) + "\u2026" : s;
|
|
1685
|
+
}
|
|
1670
1686
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1671
1687
|
isMultiLine ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1672
1688
|
/* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: emptyLine }),
|
|
@@ -1707,35 +1723,30 @@ function QueryInput({ onSubmit, isLoading, onModeChange, onShellModeChange, vimE
|
|
|
1707
1723
|
] }),
|
|
1708
1724
|
/* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: emptyLine })
|
|
1709
1725
|
] }),
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1720
|
-
" \u2014 ",
|
|
1721
|
-
descMap[name]
|
|
1722
|
-
] })
|
|
1726
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
1727
|
+
/* @__PURE__ */ jsx(Box, { marginLeft: 2, children: hasSuggestions ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1728
|
+
stripWindow.map((name, i) => {
|
|
1729
|
+
const realIdx = stripWinStart + i;
|
|
1730
|
+
const selected = realIdx === suggestionIndex;
|
|
1731
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
1732
|
+
i > 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
|
|
1733
|
+
isCommand && /* @__PURE__ */ jsx(Text, { dimColor: !selected, color: selected ? ACCENT : void 0, children: "/" }),
|
|
1734
|
+
/* @__PURE__ */ jsx(FuzzyHighlight, { text: truncateSugg(name), token: isCommand ? partial : sqlToken, selected })
|
|
1723
1735
|
] }, name);
|
|
1724
|
-
}
|
|
1725
|
-
|
|
1726
|
-
}),
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
/* @__PURE__ */ jsx(Text, {
|
|
1732
|
-
|
|
1733
|
-
] }, desc)) })
|
|
1736
|
+
}),
|
|
1737
|
+
suggestions.length > STRIP_VISIBLE && /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u2026" })
|
|
1738
|
+
] }) : /* @__PURE__ */ jsx(Box, { flexDirection: hintsInline ? "row" : "column", children: allHints.map(([key, desc], i) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
1739
|
+
hintsInline && i > 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: " | " }),
|
|
1740
|
+
/* @__PURE__ */ jsx(Text, { color: ACCENT, bold: true, children: desc }),
|
|
1741
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `: ${key}` })
|
|
1742
|
+
] }, desc)) }) }),
|
|
1743
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: stripNavHint })
|
|
1744
|
+
] })
|
|
1734
1745
|
] });
|
|
1735
1746
|
}
|
|
1736
1747
|
|
|
1737
1748
|
// src/ui/components/QueryResult.tsx
|
|
1738
|
-
import { useState as
|
|
1749
|
+
import { useState as useState3, useEffect as useEffect3 } from "react";
|
|
1739
1750
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
1740
1751
|
|
|
1741
1752
|
// src/ui/components/Table.tsx
|
|
@@ -1743,7 +1754,7 @@ import { Box as Box2, Text as Text2 } from "ink";
|
|
|
1743
1754
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1744
1755
|
var COL_PAD = 1;
|
|
1745
1756
|
var INDIGO = "#818cf8";
|
|
1746
|
-
var
|
|
1757
|
+
var BORDER = "white";
|
|
1747
1758
|
var NULL_COLOR = "#6366f1";
|
|
1748
1759
|
var NULL_MARKER = "\u2205";
|
|
1749
1760
|
function isNull(val) {
|
|
@@ -1774,10 +1785,10 @@ function hline(widths, left, mid, right) {
|
|
|
1774
1785
|
function ExpandedTable({ columns, rows }) {
|
|
1775
1786
|
const keyWidth = columns.reduce((max, col) => Math.max(max, col.length), 0);
|
|
1776
1787
|
return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: rows.map((row, i) => /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: i < rows.length - 1 ? 1 : 0, children: [
|
|
1777
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1788
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: `\u2500[ Record ${i + 1} ]${"\u2500".repeat(Math.max(0, keyWidth + 14 - String(i + 1).length))}` }),
|
|
1778
1789
|
columns.map((col) => /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1779
1790
|
/* @__PURE__ */ jsx2(Text2, { color: INDIGO, bold: true, children: col.padEnd(keyWidth) }),
|
|
1780
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1791
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: " \u2502 " }),
|
|
1781
1792
|
isNull(row[col]) ? /* @__PURE__ */ jsx2(Text2, { color: NULL_COLOR, dimColor: true, children: NULL_MARKER }) : /* @__PURE__ */ jsx2(Text2, { children: cellValue(row[col]) })
|
|
1782
1793
|
] }, col))
|
|
1783
1794
|
] }, i)) });
|
|
@@ -1790,31 +1801,31 @@ function Table({ columns, rows, expanded = false }) {
|
|
|
1790
1801
|
const botLine = hline(widths, "\u2570", "\u2534", "\u256F");
|
|
1791
1802
|
function renderHeaderRow(cols) {
|
|
1792
1803
|
return /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1793
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1804
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" }),
|
|
1794
1805
|
cols.map((v, i) => /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1795
1806
|
/* @__PURE__ */ jsx2(Text2, { color: INDIGO, bold: true, children: " ".repeat(COL_PAD) + pad(v, widths[i]) + " ".repeat(COL_PAD) }),
|
|
1796
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1807
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" })
|
|
1797
1808
|
] }, i))
|
|
1798
1809
|
] });
|
|
1799
1810
|
}
|
|
1800
1811
|
function renderDataRow(row) {
|
|
1801
1812
|
return /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1802
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1813
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" }),
|
|
1803
1814
|
columns.map((col, i) => /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1804
1815
|
isNull(row[col]) ? /* @__PURE__ */ jsx2(Text2, { color: NULL_COLOR, dimColor: true, children: " ".repeat(COL_PAD) + pad(NULL_MARKER, widths[i]) + " ".repeat(COL_PAD) }) : /* @__PURE__ */ jsx2(Text2, { children: " ".repeat(COL_PAD) + pad(cellValue(row[col]), widths[i]) + " ".repeat(COL_PAD) }),
|
|
1805
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1816
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" })
|
|
1806
1817
|
] }, i))
|
|
1807
1818
|
] });
|
|
1808
1819
|
}
|
|
1809
1820
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
1810
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1821
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: topLine }),
|
|
1811
1822
|
renderHeaderRow(columns),
|
|
1812
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1823
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: midLine }),
|
|
1813
1824
|
rows.map((row, i) => /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
1814
1825
|
renderDataRow(row),
|
|
1815
|
-
i < rows.length - 1 && /* @__PURE__ */ jsx2(Text2, { color:
|
|
1826
|
+
i < rows.length - 1 && /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: midLine })
|
|
1816
1827
|
] }, i)),
|
|
1817
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1828
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: botLine })
|
|
1818
1829
|
] });
|
|
1819
1830
|
}
|
|
1820
1831
|
|
|
@@ -1833,7 +1844,7 @@ function formatDuration(ms) {
|
|
|
1833
1844
|
return `${(ms / 1e3).toFixed(2)}s`;
|
|
1834
1845
|
}
|
|
1835
1846
|
function useTerminalWidth() {
|
|
1836
|
-
const [width, setWidth] =
|
|
1847
|
+
const [width, setWidth] = useState3(process.stdout.columns ?? 80);
|
|
1837
1848
|
useEffect3(() => {
|
|
1838
1849
|
const handler = () => setWidth(process.stdout.columns ?? 80);
|
|
1839
1850
|
process.stdout.on("resize", handler);
|
|
@@ -1902,16 +1913,8 @@ function QueryResult({ state, elapsed, page, pageSize }) {
|
|
|
1902
1913
|
|
|
1903
1914
|
// src/ui/components/Banner.tsx
|
|
1904
1915
|
import { Box as Box4, Text as Text4 } from "ink";
|
|
1905
|
-
import { readFileSync as readFileSync5 } from "fs";
|
|
1906
|
-
import { fileURLToPath } from "url";
|
|
1907
|
-
import { dirname, join as join5 } from "path";
|
|
1908
1916
|
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1909
|
-
var
|
|
1910
|
-
var pkg = { version: "unknown" };
|
|
1911
|
-
try {
|
|
1912
|
-
pkg = JSON.parse(readFileSync5(join5(__dirname, "../../../package.json"), "utf8"));
|
|
1913
|
-
} catch {
|
|
1914
|
-
}
|
|
1917
|
+
var version = true ? "0.4.8" : process.env.npm_package_version ?? "unknown";
|
|
1915
1918
|
var LOGO = [
|
|
1916
1919
|
" \u2597\u2584\u2584\u2584\u2584\u2584\u2596",
|
|
1917
1920
|
"\u2590\u2591 \u25CF \u25CF \u2591\u258C",
|
|
@@ -1935,7 +1938,7 @@ function Banner({ connectionState }) {
|
|
|
1935
1938
|
"Querky ",
|
|
1936
1939
|
/* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
|
|
1937
1940
|
"v",
|
|
1938
|
-
|
|
1941
|
+
version
|
|
1939
1942
|
] })
|
|
1940
1943
|
] }),
|
|
1941
1944
|
/* @__PURE__ */ jsx4(Text4, { children: " " }),
|
|
@@ -2019,6 +2022,7 @@ var TABLE_COLORS = [
|
|
|
2019
2022
|
"#fbbf24",
|
|
2020
2023
|
"#2dd4bf"
|
|
2021
2024
|
];
|
|
2025
|
+
var BORDER2 = "#4b5563";
|
|
2022
2026
|
var PAD = 1;
|
|
2023
2027
|
var GAP = 2;
|
|
2024
2028
|
var FK_PREFIX = "FK \u2192 ";
|
|
@@ -2066,31 +2070,31 @@ function TableBox({ table, m, color, colorMap }) {
|
|
|
2066
2070
|
const bot = "\u2570" + "\u2500".repeat(nameW + PAD * 2) + "\u2534" + "\u2500".repeat(typeW + PAD * 2) + "\u2534" + "\u2500".repeat(keyW + PAD * 2) + "\u256F";
|
|
2067
2071
|
const headerW = totalW - 4;
|
|
2068
2072
|
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
2069
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: top }),
|
|
2073
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: top }),
|
|
2070
2074
|
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
2071
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
|
|
2075
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
|
|
2072
2076
|
/* @__PURE__ */ jsxs6(Text6, { color, bold: true, children: [
|
|
2073
2077
|
sp,
|
|
2074
2078
|
p(table.name, headerW),
|
|
2075
2079
|
sp
|
|
2076
2080
|
] }),
|
|
2077
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" })
|
|
2081
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" })
|
|
2078
2082
|
] }),
|
|
2079
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: sep }),
|
|
2083
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: sep }),
|
|
2080
2084
|
table.columns.map((col, i) => /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
2081
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
|
|
2085
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
|
|
2082
2086
|
/* @__PURE__ */ jsxs6(Text6, { children: [
|
|
2083
2087
|
sp,
|
|
2084
2088
|
p(col.name, nameW),
|
|
2085
2089
|
sp
|
|
2086
2090
|
] }),
|
|
2087
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
|
|
2091
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
|
|
2088
2092
|
/* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
|
|
2089
2093
|
sp,
|
|
2090
2094
|
p(col.type, typeW),
|
|
2091
2095
|
sp
|
|
2092
2096
|
] }),
|
|
2093
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
|
|
2097
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
|
|
2094
2098
|
col.isPk ? /* @__PURE__ */ jsxs6(Text6, { bold: true, children: [
|
|
2095
2099
|
sp,
|
|
2096
2100
|
p("PK", keyW),
|
|
@@ -2109,9 +2113,9 @@ function TableBox({ table, m, color, colorMap }) {
|
|
|
2109
2113
|
" ".repeat(keyW),
|
|
2110
2114
|
sp
|
|
2111
2115
|
] }),
|
|
2112
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" })
|
|
2116
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" })
|
|
2113
2117
|
] }, i)),
|
|
2114
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: bot })
|
|
2118
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: bot })
|
|
2115
2119
|
] });
|
|
2116
2120
|
}
|
|
2117
2121
|
function ErdView({ data }) {
|
|
@@ -2129,7 +2133,7 @@ function ErdView({ data }) {
|
|
|
2129
2133
|
{
|
|
2130
2134
|
table: data.tables[ti],
|
|
2131
2135
|
m: metrics[ti],
|
|
2132
|
-
color: colorMap.get(data.tables[ti].name) ??
|
|
2136
|
+
color: colorMap.get(data.tables[ti].name) ?? BORDER2,
|
|
2133
2137
|
colorMap
|
|
2134
2138
|
}
|
|
2135
2139
|
) }, ti)) }, ri)) });
|
|
@@ -2148,26 +2152,42 @@ function limitLines(s, n) {
|
|
|
2148
2152
|
return lines.slice(0, n).join("\n") + `
|
|
2149
2153
|
\u2026 +${lines.length - n} more lines (scroll up after next submit)`;
|
|
2150
2154
|
}
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
const
|
|
2154
|
-
|
|
2155
|
-
|
|
2155
|
+
var QUERY_HEADER_COLOR = "#9ca3af";
|
|
2156
|
+
function QueryHeader({ label, query }) {
|
|
2157
|
+
const isMultiLine = query.includes("\n");
|
|
2158
|
+
if (isMultiLine) {
|
|
2159
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
2160
|
+
/* @__PURE__ */ jsxs7(Text7, { children: [
|
|
2161
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: "\u25CF " }),
|
|
2162
|
+
/* @__PURE__ */ jsxs7(Text7, { color: QUERY_HEADER_COLOR, bold: true, children: [
|
|
2163
|
+
label,
|
|
2164
|
+
":"
|
|
2165
|
+
] })
|
|
2166
|
+
] }),
|
|
2167
|
+
query.split("\n").map((line, i) => /* @__PURE__ */ jsxs7(Text7, { color: QUERY_HEADER_COLOR, bold: true, children: [
|
|
2168
|
+
" ",
|
|
2169
|
+
line
|
|
2170
|
+
] }, i))
|
|
2171
|
+
] });
|
|
2172
|
+
}
|
|
2173
|
+
return /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
2174
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: "\u25CF " }),
|
|
2175
|
+
/* @__PURE__ */ jsxs7(Text7, { color: QUERY_HEADER_COLOR, bold: true, children: [
|
|
2176
|
+
label,
|
|
2177
|
+
"(",
|
|
2178
|
+
query,
|
|
2179
|
+
")"
|
|
2180
|
+
] })
|
|
2181
|
+
] });
|
|
2156
2182
|
}
|
|
2157
2183
|
function EntryView({ entry }) {
|
|
2158
2184
|
const showAi = entry.aiResponse !== "" || entry.aiError !== null;
|
|
2159
2185
|
const showErd = entry.erdData !== null;
|
|
2160
2186
|
const isShell = entry.query.startsWith("!");
|
|
2161
2187
|
const isCommand = !isShell && (entry.query.startsWith("/") || entry.query.startsWith("\\"));
|
|
2162
|
-
const label = isShell ? "Shell
|
|
2188
|
+
const label = isShell ? "Shell" : isCommand ? "Command" : "Query";
|
|
2163
2189
|
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 1, paddingX: 1, children: [
|
|
2164
|
-
/* @__PURE__ */
|
|
2165
|
-
/* @__PURE__ */ jsxs7(Text7, { color: theme.accent, bold: true, children: [
|
|
2166
|
-
label,
|
|
2167
|
-
" "
|
|
2168
|
-
] }),
|
|
2169
|
-
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: displayQuery(entry.query) })
|
|
2170
|
-
] }),
|
|
2190
|
+
/* @__PURE__ */ jsx7(QueryHeader, { label, query: entry.query }),
|
|
2171
2191
|
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, flexDirection: "column", children: isShell ? entry.shellOutput !== null && /* @__PURE__ */ jsx7(Text7, { children: entry.shellOutput || "(no output)" }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
2172
2192
|
entry.commandMessage && (entry.commandMessage.helpData ? /* @__PURE__ */ jsx7(HelpView, { data: entry.commandMessage.helpData }) : entry.commandMessage.ok ? /* @__PURE__ */ jsxs7(Text7, { color: theme.accent, children: [
|
|
2173
2193
|
"\u2713 ",
|
|
@@ -2183,29 +2203,29 @@ function EntryView({ entry }) {
|
|
|
2183
2203
|
function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2, onChangeDatabase }) {
|
|
2184
2204
|
const { exit } = useApp();
|
|
2185
2205
|
const { isRawModeSupported } = useStdin2();
|
|
2186
|
-
const [queryState, setQueryState] =
|
|
2187
|
-
const [lastQuery, setLastQuery] =
|
|
2188
|
-
const [lastSqlQuery, setLastSqlQuery] =
|
|
2189
|
-
const [lastResult, setLastResult] =
|
|
2190
|
-
const [page, setPage] =
|
|
2191
|
-
const [vimMode, setVimMode] =
|
|
2192
|
-
const [inputIsShell, setInputIsShell] =
|
|
2193
|
-
const [elapsed, setElapsed] =
|
|
2194
|
-
const [vimEnabled, setVimEnabled] =
|
|
2195
|
-
const [commandMessage, setCommandMessage] =
|
|
2196
|
-
const [history, setHistory] =
|
|
2197
|
-
const [schema, setSchema] =
|
|
2198
|
-
const [aiResponse, setAiResponse] =
|
|
2199
|
-
const [isStreaming, setIsStreaming] =
|
|
2200
|
-
const [aiError, setAiError] =
|
|
2201
|
-
const [shellOutput, setShellOutput] =
|
|
2202
|
-
const [isShellRunning, setIsShellRunning] =
|
|
2203
|
-
const [erdData, setErdData] =
|
|
2204
|
-
const [isErdLoading, setIsErdLoading] =
|
|
2205
|
-
const [completedEntries, setCompletedEntries] =
|
|
2206
|
+
const [queryState, setQueryState] = useState4({ status: "idle" });
|
|
2207
|
+
const [lastQuery, setLastQuery] = useState4("");
|
|
2208
|
+
const [lastSqlQuery, setLastSqlQuery] = useState4("");
|
|
2209
|
+
const [lastResult, setLastResult] = useState4(null);
|
|
2210
|
+
const [page, setPage] = useState4(0);
|
|
2211
|
+
const [vimMode, setVimMode] = useState4("INSERT");
|
|
2212
|
+
const [inputIsShell, setInputIsShell] = useState4(false);
|
|
2213
|
+
const [elapsed, setElapsed] = useState4(null);
|
|
2214
|
+
const [vimEnabled, setVimEnabled] = useState4(true);
|
|
2215
|
+
const [commandMessage, setCommandMessage] = useState4(null);
|
|
2216
|
+
const [history, setHistory] = useState4(() => loadHistory());
|
|
2217
|
+
const [schema, setSchema] = useState4(null);
|
|
2218
|
+
const [aiResponse, setAiResponse] = useState4("");
|
|
2219
|
+
const [isStreaming, setIsStreaming] = useState4(false);
|
|
2220
|
+
const [aiError, setAiError] = useState4(null);
|
|
2221
|
+
const [shellOutput, setShellOutput] = useState4(null);
|
|
2222
|
+
const [isShellRunning, setIsShellRunning] = useState4(false);
|
|
2223
|
+
const [erdData, setErdData] = useState4(null);
|
|
2224
|
+
const [isErdLoading, setIsErdLoading] = useState4(false);
|
|
2225
|
+
const [completedEntries, setCompletedEntries] = useState4([]);
|
|
2206
2226
|
const entryIdRef = useRef2(0);
|
|
2207
2227
|
const aliasScope = connectionState.status === "connected" ? makeScope(connectionState.driver, connectionState.user, connectionState.host, connectionState.database) : "";
|
|
2208
|
-
const [aliases, setAliases] =
|
|
2228
|
+
const [aliases, setAliases] = useState4(
|
|
2209
2229
|
() => aliasScope ? getAllAliases(aliasScope) : {}
|
|
2210
2230
|
);
|
|
2211
2231
|
function handleSaveAlias(name, query) {
|
|
@@ -2313,7 +2333,7 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2313
2333
|
return;
|
|
2314
2334
|
}
|
|
2315
2335
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
2316
|
-
const filename =
|
|
2336
|
+
const filename = join5(homedir4(), `q-export-${ts}.${format}`);
|
|
2317
2337
|
try {
|
|
2318
2338
|
if (format === "json") {
|
|
2319
2339
|
writeFileSync5(filename, JSON.stringify(lastResult.rows, null, 2));
|
|
@@ -2403,7 +2423,6 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2403
2423
|
void handleErd();
|
|
2404
2424
|
},
|
|
2405
2425
|
onClear: () => {
|
|
2406
|
-
process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
2407
2426
|
setCompletedEntries([]);
|
|
2408
2427
|
setLastQuery("");
|
|
2409
2428
|
setCommandMessage(null);
|
|
@@ -2413,6 +2432,7 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2413
2432
|
setAiError(null);
|
|
2414
2433
|
setElapsed(null);
|
|
2415
2434
|
setPage(0);
|
|
2435
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
2416
2436
|
},
|
|
2417
2437
|
aliases,
|
|
2418
2438
|
onSaveAlias: handleSaveAlias,
|
|
@@ -2444,13 +2464,7 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2444
2464
|
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingX: 1, children: [
|
|
2445
2465
|
lastQuery === "" && /* @__PURE__ */ jsx7(Banner, { connectionState }),
|
|
2446
2466
|
lastQuery !== "" && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 2, children: [
|
|
2447
|
-
/* @__PURE__ */
|
|
2448
|
-
/* @__PURE__ */ jsxs7(Text7, { color: theme.accent, bold: true, children: [
|
|
2449
|
-
activeLabel,
|
|
2450
|
-
" "
|
|
2451
|
-
] }),
|
|
2452
|
-
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: displayQuery(lastQuery) })
|
|
2453
|
-
] }),
|
|
2467
|
+
/* @__PURE__ */ jsx7(QueryHeader, { label: activeLabel.replace(":", ""), query: lastQuery }),
|
|
2454
2468
|
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, flexDirection: "column", children: isShellEntry ? isShellRunning ? /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "running\u2026" }) : /* @__PURE__ */ jsx7(Text7, { children: limitLines(shellOutput ?? "", activePageSize()) }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
2455
2469
|
commandMessage && (commandMessage.helpData ? /* @__PURE__ */ jsx7(HelpView, { data: commandMessage.helpData }) : commandMessage.ok ? /* @__PURE__ */ jsxs7(Text7, { color: theme.accent, children: [
|
|
2456
2470
|
"\u2713 ",
|
|
@@ -2484,7 +2498,7 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2484
2498
|
}
|
|
2485
2499
|
|
|
2486
2500
|
// src/ui/components/ConnectionWizard.tsx
|
|
2487
|
-
import { useState as
|
|
2501
|
+
import { useState as useState5 } from "react";
|
|
2488
2502
|
import { Box as Box8, Text as Text8, useInput as useInput3, useStdin as useStdin3 } from "ink";
|
|
2489
2503
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2490
2504
|
var DRIVERS = ["postgresql", "mysql", "sqlite"];
|
|
@@ -2495,8 +2509,8 @@ function fieldLabels(driver) {
|
|
|
2495
2509
|
}
|
|
2496
2510
|
function ConnectionWizard({ onConnect, initialError }) {
|
|
2497
2511
|
const { isRawModeSupported } = useStdin3();
|
|
2498
|
-
const [focus, setFocus] =
|
|
2499
|
-
const [fields, setFields] =
|
|
2512
|
+
const [focus, setFocus] = useState5(0);
|
|
2513
|
+
const [fields, setFields] = useState5({
|
|
2500
2514
|
driver: "postgresql",
|
|
2501
2515
|
host: "localhost",
|
|
2502
2516
|
port: "5432",
|
|
@@ -2504,9 +2518,9 @@ function ConnectionWizard({ onConnect, initialError }) {
|
|
|
2504
2518
|
user: "",
|
|
2505
2519
|
password: ""
|
|
2506
2520
|
});
|
|
2507
|
-
const [connecting, setConnecting] =
|
|
2508
|
-
const [error, setError] =
|
|
2509
|
-
const [keychainHint, setKeychainHint] =
|
|
2521
|
+
const [connecting, setConnecting] = useState5(false);
|
|
2522
|
+
const [error, setError] = useState5(initialError ?? null);
|
|
2523
|
+
const [keychainHint, setKeychainHint] = useState5(false);
|
|
2510
2524
|
const labels = fieldLabels(fields.driver);
|
|
2511
2525
|
const fieldCount = labels.length;
|
|
2512
2526
|
function getTextValue(idx) {
|
|
@@ -2686,8 +2700,8 @@ var aiUrl = values["ai-url"];
|
|
|
2686
2700
|
var aiModel = values["ai-model"];
|
|
2687
2701
|
var aiKey = values["api-key"] || process.env.Q_CLI_API_KEY || "";
|
|
2688
2702
|
function Root({ initialDsn: initialDsn2, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2 }) {
|
|
2689
|
-
const [connectionState, setConnectionState] =
|
|
2690
|
-
const [dsnError, setDsnError] =
|
|
2703
|
+
const [connectionState, setConnectionState] = useState6(null);
|
|
2704
|
+
const [dsnError, setDsnError] = useState6(null);
|
|
2691
2705
|
useEffect5(() => {
|
|
2692
2706
|
if (initialDsn2) {
|
|
2693
2707
|
connectDsn(initialDsn2).then((state) => {
|
|
@@ -2726,6 +2740,9 @@ function Root({ initialDsn: initialDsn2, aiUrl: aiUrl2, aiModel: aiModel2, aiKey
|
|
|
2726
2740
|
}
|
|
2727
2741
|
);
|
|
2728
2742
|
}
|
|
2743
|
+
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
2744
|
+
process.on("exit", () => process.stdout.write("\x1B[?1049l"));
|
|
2745
|
+
process.on("SIGTERM", () => process.exit(0));
|
|
2729
2746
|
render(
|
|
2730
2747
|
/* @__PURE__ */ jsx9(Root, { initialDsn, aiUrl, aiModel, aiKey }),
|
|
2731
2748
|
{ exitOnCtrlC: true }
|