sqlrite 0.1.19__tar.gz → 0.1.20__tar.gz
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.
- {sqlrite-0.1.19 → sqlrite-0.1.20}/Cargo.lock +6 -6
- {sqlrite-0.1.19 → sqlrite-0.1.20}/Cargo.toml +1 -1
- {sqlrite-0.1.19 → sqlrite-0.1.20}/PKG-INFO +1 -1
- {sqlrite-0.1.19 → sqlrite-0.1.20}/README.md +3 -2
- {sqlrite-0.1.19 → sqlrite-0.1.20}/desktop/package.json +1 -1
- {sqlrite-0.1.19 → sqlrite-0.1.20}/desktop/src/App.svelte +112 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/desktop/src/app.css +96 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/desktop.md +2 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/phase-7-plan.md +1 -1
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/roadmap.md +1 -1
- {sqlrite-0.1.19 → sqlrite-0.1.20}/pyproject.toml +1 -1
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sdk/python/Cargo.toml +1 -1
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sqlrite-ask/Cargo.toml +1 -1
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/ask/mod.rs +12 -3
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/lib.rs +6 -4
- {sqlrite-0.1.19 → sqlrite-0.1.20}/.github/workflows/ci.yml +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/.github/workflows/release-pr.yml +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/.github/workflows/release.yml +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/.github/workflows/rust.yml +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/.gitignore +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/CODE_OF_CONDUCT.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/LICENSE +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/MAINTAINERS +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/Makefile +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/desktop/index.html +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/desktop/package-lock.json +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/desktop/src/main.ts +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/desktop/src/vite-env.d.ts +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/desktop/svelte.config.js +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/desktop/tsconfig.json +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/desktop/vite.config.ts +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/_index.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/architecture.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/design-decisions.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/embedding.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/file-format.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/getting-started.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/pager.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/release-plan.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/release-secrets.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/smoke-test.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/sql-engine.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/storage-model.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/supported-sql.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/docs/usage.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/examples/README.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/examples/c/Makefile +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/examples/c/hello.c +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/examples/go/go.mod +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/examples/go/hello.go +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/examples/nodejs/hello.mjs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/examples/python/hello.py +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/examples/rust/quickstart.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/examples/wasm/Makefile +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/examples/wasm/index.html +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/images/SQLRite - Desktop.png +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/images/SQLRite Data Structures.png +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/images/SQLRite Simple SQL Execution High Level Diagram.png +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/images/SQLRite Simple SQL INSERT Execution High Level Diagram (Insert Row).png +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/images/SQLRite Simple SQL INSERT Execution High Level Diagram.png +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/images/SQLRite_logo.png +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/images/architecture.png +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/rust-toolchain.toml +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/samples/AST.delete.example +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/samples/AST.insert.exemple +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/samples/AST.select.example +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/samples/AST.update.example +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/samples/CREATE TABLE sqlrite_schema.sql +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/samples/CREATE_TABLE with duplicate.sql +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/samples/CREATE_TABLE.sql +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/samples/INSERT.sql +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/scripts/bump-version.sh +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sdk/go/README.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sdk/go/conn.go +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sdk/go/go.mod +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sdk/go/rows.go +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sdk/go/sqlrite.go +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sdk/go/sqlrite_test.go +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sdk/go/stmt.go +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sdk/python/README.md +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sdk/python/src/lib.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sdk/python/tests/test_sqlrite.py +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sqlrite-ask/src/lib.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sqlrite-ask/src/prompt.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sqlrite-ask/src/provider/anthropic.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sqlrite-ask/src/provider/mock.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sqlrite-ask/src/provider/mod.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/sqlrite-ask/tests/anthropic_http.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/ask/schema.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/connection.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/error.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/main.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/meta_command/mod.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/repl/mod.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/db/database.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/db/mod.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/db/secondary_index.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/db/table.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/executor.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/hnsw.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/mod.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/pager/cell.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/pager/file.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/pager/header.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/pager/hnsw_cell.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/pager/index_cell.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/pager/interior_page.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/pager/mod.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/pager/overflow.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/pager/page.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/pager/pager.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/pager/table_page.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/pager/varint.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/pager/wal.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/parser/create.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/parser/insert.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/parser/mod.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/parser/select.rs +0 -0
- {sqlrite-0.1.19 → sqlrite-0.1.20}/src/sql/tokenizer.rs +0 -0
|
@@ -3804,7 +3804,7 @@ dependencies = [
|
|
|
3804
3804
|
|
|
3805
3805
|
[[package]]
|
|
3806
3806
|
name = "sqlrite-ask"
|
|
3807
|
-
version = "0.1.
|
|
3807
|
+
version = "0.1.20"
|
|
3808
3808
|
dependencies = [
|
|
3809
3809
|
"serde",
|
|
3810
3810
|
"serde_json",
|
|
@@ -3815,7 +3815,7 @@ dependencies = [
|
|
|
3815
3815
|
|
|
3816
3816
|
[[package]]
|
|
3817
3817
|
name = "sqlrite-desktop"
|
|
3818
|
-
version = "0.1.
|
|
3818
|
+
version = "0.1.20"
|
|
3819
3819
|
dependencies = [
|
|
3820
3820
|
"serde",
|
|
3821
3821
|
"serde_json",
|
|
@@ -3827,7 +3827,7 @@ dependencies = [
|
|
|
3827
3827
|
|
|
3828
3828
|
[[package]]
|
|
3829
3829
|
name = "sqlrite-engine"
|
|
3830
|
-
version = "0.1.
|
|
3830
|
+
version = "0.1.20"
|
|
3831
3831
|
dependencies = [
|
|
3832
3832
|
"clap",
|
|
3833
3833
|
"env_logger",
|
|
@@ -3844,7 +3844,7 @@ dependencies = [
|
|
|
3844
3844
|
|
|
3845
3845
|
[[package]]
|
|
3846
3846
|
name = "sqlrite-ffi"
|
|
3847
|
-
version = "0.1.
|
|
3847
|
+
version = "0.1.20"
|
|
3848
3848
|
dependencies = [
|
|
3849
3849
|
"cbindgen",
|
|
3850
3850
|
"sqlrite-engine",
|
|
@@ -3852,7 +3852,7 @@ dependencies = [
|
|
|
3852
3852
|
|
|
3853
3853
|
[[package]]
|
|
3854
3854
|
name = "sqlrite-nodejs"
|
|
3855
|
-
version = "0.1.
|
|
3855
|
+
version = "0.1.20"
|
|
3856
3856
|
dependencies = [
|
|
3857
3857
|
"napi",
|
|
3858
3858
|
"napi-build",
|
|
@@ -3862,7 +3862,7 @@ dependencies = [
|
|
|
3862
3862
|
|
|
3863
3863
|
[[package]]
|
|
3864
3864
|
name = "sqlrite-python"
|
|
3865
|
-
version = "0.1.
|
|
3865
|
+
version = "0.1.20"
|
|
3866
3866
|
dependencies = [
|
|
3867
3867
|
"pyo3",
|
|
3868
3868
|
"sqlrite-engine",
|
|
@@ -27,7 +27,7 @@ resolver = "3"
|
|
|
27
27
|
# `package =` key so the import name stays `sqlrite` internally:
|
|
28
28
|
# sqlrite = { package = "sqlrite-engine", path = "…" }
|
|
29
29
|
name = "sqlrite-engine"
|
|
30
|
-
version = "0.1.
|
|
30
|
+
version = "0.1.20"
|
|
31
31
|
authors = ["Joao Henrique Machado Silva <joaoh82@gmail.com>"]
|
|
32
32
|
edition = "2024"
|
|
33
33
|
rust-version = "1.85"
|
|
@@ -270,8 +270,9 @@ Lockstep versioning — one dispatch bumps every product to the same `vX.Y.Z`. T
|
|
|
270
270
|
- [x] **7d — HNSW ANN index** *(v0.1.13–15)*: `CREATE INDEX … USING hnsw (col)`; recall@10 ≥ 0.95 at default `M=16, ef_construction=200, ef_search=50`; persisted as a `KIND_HNSW` cell tree
|
|
271
271
|
- [x] **7e — JSON column type + path queries** *(v0.1.16)*: `JSON` / `JSONB` columns stored as canonical text; `json_extract` / `json_type` / `json_array_length` / `json_object_keys`; `$.key`, `[N]`, chained JSONPath subset
|
|
272
272
|
- [x] **7g.1 — `sqlrite-ask` crate** *(v0.1.18)*: foundational natural-language → SQL via the [Anthropic API](https://docs.anthropic.com/) (Sonnet 4.6 by default), prompt-cached schema dump, sync `ureq` HTTP.
|
|
273
|
-
- [x] **7g.2 — REPL `.ask` + dep-direction flip** *(
|
|
274
|
-
- [
|
|
273
|
+
- [x] **7g.2 — REPL `.ask` + dep-direction flip** *(v0.1.19)*: `.ask <question>` meta-command with `Run? [Y/n]` confirmation. The wiring required dropping the engine dep from `sqlrite-ask` (cargo cycle) — `sqlrite-ask` is now pure over `&str` schemas; the `Connection`/`Database` integration moved to the engine's new `ask` feature. Public surface for callers: `use sqlrite::{Connection, ConnectionAskExt}`.
|
|
274
|
+
- [x] **7g.3 — Desktop "Ask…" button** *(this wave)*: composer panel above the editor textarea; click → type a natural-language question → submit → generated SQL drops into the editor for review before Run. Schema introspection + LLM HTTP call run in the Tauri Rust backend, so the API key never crosses into the webview.
|
|
275
|
+
- [ ] **7g.4-7g.8** — per-product `ask()` adapters: Python/Node/Go/WASM SDKs, MCP `ask` tool
|
|
275
276
|
- [ ] **7h** — MCP server adapter (`sqlrite-mcp` binary)
|
|
276
277
|
- [ ] *(deferred to Phase 8)* Full-text search with BM25 + hybrid retrieval
|
|
277
278
|
|
|
@@ -31,6 +31,19 @@
|
|
|
31
31
|
let errorMessage = $state<string | null>(null);
|
|
32
32
|
let running = $state<boolean>(false);
|
|
33
33
|
|
|
34
|
+
// Phase 7g.3 — Ask… composer state. The composer is a small panel
|
|
35
|
+
// that slides in above the editor when the user clicks "Ask…".
|
|
36
|
+
// Submitting calls the `ask_sql` Tauri command (which runs schema
|
|
37
|
+
// introspection + the LLM call server-side, so the API key stays
|
|
38
|
+
// out of the webview), then drops the generated SQL into the
|
|
39
|
+
// editor for the user to review + run.
|
|
40
|
+
let askVisible = $state<boolean>(false);
|
|
41
|
+
let askQuestion = $state<string>("");
|
|
42
|
+
let askExplanation = $state<string | null>(null);
|
|
43
|
+
let askInputRef = $state<HTMLTextAreaElement | null>(null);
|
|
44
|
+
let asking = $state<boolean>(false);
|
|
45
|
+
type AskResult = { sql: string; explanation: string };
|
|
46
|
+
|
|
34
47
|
// Editor refs and derived line numbers for the gutter. We derive a
|
|
35
48
|
// dense `[1, 2, …, n]` array so Svelte's {#each} iterates every slot
|
|
36
49
|
// — a sparse `Array(n)` would skip indices.
|
|
@@ -280,6 +293,67 @@
|
|
|
280
293
|
}
|
|
281
294
|
}
|
|
282
295
|
|
|
296
|
+
// Phase 7g.3 — Ask composer handlers.
|
|
297
|
+
|
|
298
|
+
/** Toggle the Ask composer. Focuses the question input on open. */
|
|
299
|
+
async function onAskClick() {
|
|
300
|
+
askVisible = !askVisible;
|
|
301
|
+
if (askVisible) {
|
|
302
|
+
// Clear any prior explanation when reopening, but preserve the
|
|
303
|
+
// question — the user might want to tweak + retry rather than
|
|
304
|
+
// retype from scratch.
|
|
305
|
+
askExplanation = null;
|
|
306
|
+
errorMessage = null;
|
|
307
|
+
await tick();
|
|
308
|
+
askInputRef?.focus();
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** Submit the natural-language question to the backend. */
|
|
313
|
+
async function onAskSubmit() {
|
|
314
|
+
const question = askQuestion.trim();
|
|
315
|
+
if (!question) return;
|
|
316
|
+
asking = true;
|
|
317
|
+
errorMessage = null;
|
|
318
|
+
askExplanation = null;
|
|
319
|
+
try {
|
|
320
|
+
const resp = await invoke<AskResult>("ask_sql", { question });
|
|
321
|
+
if (resp.sql.trim().length === 0) {
|
|
322
|
+
// Model declined to generate SQL for this schema. Surface
|
|
323
|
+
// its rationale in the same slot we'd use for a successful
|
|
324
|
+
// explanation; don't touch the editor.
|
|
325
|
+
askExplanation =
|
|
326
|
+
resp.explanation || "(model declined to generate SQL)";
|
|
327
|
+
} else {
|
|
328
|
+
// Drop the generated SQL into the editor (don't auto-run —
|
|
329
|
+
// user reviews + clicks Run themselves). Stash the
|
|
330
|
+
// explanation so the user can see why they got that query.
|
|
331
|
+
sql = resp.sql;
|
|
332
|
+
askExplanation = resp.explanation || null;
|
|
333
|
+
// Move focus back to the editor so Cmd/Ctrl+Enter just works.
|
|
334
|
+
await tick();
|
|
335
|
+
textareaRef?.focus();
|
|
336
|
+
}
|
|
337
|
+
} catch (err) {
|
|
338
|
+
errorMessage = String(err);
|
|
339
|
+
} finally {
|
|
340
|
+
asking = false;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/** Cmd/Ctrl+Enter in the question input submits. Esc closes. */
|
|
345
|
+
function onAskKey(e: KeyboardEvent) {
|
|
346
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
|
|
347
|
+
e.preventDefault();
|
|
348
|
+
onAskSubmit();
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (e.key === "Escape") {
|
|
352
|
+
e.preventDefault();
|
|
353
|
+
askVisible = false;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
283
357
|
onMount(() => {
|
|
284
358
|
refreshTables();
|
|
285
359
|
});
|
|
@@ -347,6 +421,41 @@
|
|
|
347
421
|
|
|
348
422
|
<section class="main">
|
|
349
423
|
<div class="editor">
|
|
424
|
+
{#if askVisible}
|
|
425
|
+
<div class="ask-panel">
|
|
426
|
+
<div class="ask-header">
|
|
427
|
+
<span class="ask-title">Ask</span>
|
|
428
|
+
<span class="ask-hint">
|
|
429
|
+
Natural-language → SQL · Submit: ⌘↵ · Close: Esc
|
|
430
|
+
</span>
|
|
431
|
+
<button
|
|
432
|
+
class="ask-close"
|
|
433
|
+
onclick={() => (askVisible = false)}
|
|
434
|
+
aria-label="Close Ask panel"
|
|
435
|
+
>×</button>
|
|
436
|
+
</div>
|
|
437
|
+
<textarea
|
|
438
|
+
bind:this={askInputRef}
|
|
439
|
+
bind:value={askQuestion}
|
|
440
|
+
onkeydown={onAskKey}
|
|
441
|
+
placeholder="e.g. How many users are over 30?"
|
|
442
|
+
rows="2"
|
|
443
|
+
spellcheck="false"
|
|
444
|
+
></textarea>
|
|
445
|
+
<div class="ask-actions">
|
|
446
|
+
{#if askExplanation}
|
|
447
|
+
<span class="ask-explanation">{askExplanation}</span>
|
|
448
|
+
{:else}
|
|
449
|
+
<span class="ask-explanation muted">
|
|
450
|
+
Generated SQL replaces the editor contents — review before running.
|
|
451
|
+
</span>
|
|
452
|
+
{/if}
|
|
453
|
+
<button onclick={onAskSubmit} disabled={asking || !askQuestion.trim()}>
|
|
454
|
+
{asking ? "Generating…" : "Generate SQL"}
|
|
455
|
+
</button>
|
|
456
|
+
</div>
|
|
457
|
+
</div>
|
|
458
|
+
{/if}
|
|
350
459
|
<div class="editor-surface">
|
|
351
460
|
<div class="gutter" bind:this={gutterRef} aria-hidden="true">
|
|
352
461
|
{#each lineNumbers as n (n)}
|
|
@@ -366,6 +475,9 @@
|
|
|
366
475
|
<span class="shortcut-hint">
|
|
367
476
|
Run: ⌘↵ · Comment: ⌘/{hasSelection ? " · selection only" : ""}
|
|
368
477
|
</span>
|
|
478
|
+
<button class="ask-button" onclick={onAskClick} disabled={asking}>
|
|
479
|
+
{askVisible ? "Hide Ask" : "Ask…"}
|
|
480
|
+
</button>
|
|
369
481
|
<button onclick={onRunSql} disabled={running}>
|
|
370
482
|
{#if running}Running…{:else if hasSelection}Run selection{:else}Run{/if}
|
|
371
483
|
</button>
|
|
@@ -267,6 +267,102 @@ button:disabled {
|
|
|
267
267
|
user-select: none;
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
/* Phase 7g.3 — `Ask…` button distinguishes itself with a subtle
|
|
271
|
+
* accent so users notice the new feature without it shouting. The
|
|
272
|
+
* normal `Run` button keeps its existing primary styling. */
|
|
273
|
+
.ask-button {
|
|
274
|
+
margin-right: 8px;
|
|
275
|
+
background: transparent;
|
|
276
|
+
color: var(--fg);
|
|
277
|
+
border: 1px solid var(--border);
|
|
278
|
+
}
|
|
279
|
+
.ask-button:hover:not(:disabled) {
|
|
280
|
+
background: var(--panel-2);
|
|
281
|
+
border-color: var(--accent);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* The Ask composer slides in above the editor surface. Visually it
|
|
285
|
+
* shares the editor's panel background but is set off by a bottom
|
|
286
|
+
* border so users can see where it ends and the editor begins. */
|
|
287
|
+
.ask-panel {
|
|
288
|
+
background: var(--panel-2);
|
|
289
|
+
border-bottom: 1px solid var(--border);
|
|
290
|
+
padding: 10px 12px 12px;
|
|
291
|
+
display: flex;
|
|
292
|
+
flex-direction: column;
|
|
293
|
+
gap: 8px;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.ask-header {
|
|
297
|
+
display: flex;
|
|
298
|
+
align-items: center;
|
|
299
|
+
gap: 12px;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.ask-title {
|
|
303
|
+
font-weight: 600;
|
|
304
|
+
font-size: 13px;
|
|
305
|
+
color: var(--fg);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.ask-hint {
|
|
309
|
+
flex: 1;
|
|
310
|
+
color: var(--fg-muted);
|
|
311
|
+
font-family: var(--mono);
|
|
312
|
+
font-size: 11px;
|
|
313
|
+
user-select: none;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/* Subtle close button — visually a hairline so it doesn't compete
|
|
317
|
+
* with the Generate button below. */
|
|
318
|
+
.ask-close {
|
|
319
|
+
width: 24px;
|
|
320
|
+
height: 24px;
|
|
321
|
+
padding: 0;
|
|
322
|
+
background: transparent;
|
|
323
|
+
border: 1px solid var(--border);
|
|
324
|
+
color: var(--fg-muted);
|
|
325
|
+
font-size: 14px;
|
|
326
|
+
line-height: 1;
|
|
327
|
+
}
|
|
328
|
+
.ask-close:hover {
|
|
329
|
+
color: var(--fg);
|
|
330
|
+
border-color: var(--accent);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.ask-panel textarea {
|
|
334
|
+
background: var(--panel);
|
|
335
|
+
color: var(--fg);
|
|
336
|
+
border: 1px solid var(--border);
|
|
337
|
+
border-radius: 4px;
|
|
338
|
+
padding: 8px 10px;
|
|
339
|
+
font-family: var(--mono);
|
|
340
|
+
font-size: 13px;
|
|
341
|
+
line-height: 1.4;
|
|
342
|
+
resize: vertical;
|
|
343
|
+
min-height: 48px;
|
|
344
|
+
outline: none;
|
|
345
|
+
}
|
|
346
|
+
.ask-panel textarea:focus {
|
|
347
|
+
border-color: var(--accent);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.ask-actions {
|
|
351
|
+
display: flex;
|
|
352
|
+
align-items: center;
|
|
353
|
+
justify-content: space-between;
|
|
354
|
+
gap: 12px;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.ask-explanation {
|
|
358
|
+
flex: 1;
|
|
359
|
+
font-size: 12px;
|
|
360
|
+
color: var(--fg);
|
|
361
|
+
}
|
|
362
|
+
.ask-explanation.muted {
|
|
363
|
+
color: var(--fg-muted);
|
|
364
|
+
}
|
|
365
|
+
|
|
270
366
|
.output {
|
|
271
367
|
flex: 1;
|
|
272
368
|
min-height: 0;
|
|
@@ -125,6 +125,7 @@ The `Mutex` isn't a concurrency optimization — it's a correctness requirement.
|
|
|
125
125
|
| `list_tables()` | Sidebar data — one entry per user table with column metadata. |
|
|
126
126
|
| `table_rows(name, limit)` | Seed the result grid with up to `limit` rows from `name`. |
|
|
127
127
|
| `execute_sql(sql)` | Run one SQL statement through `process_command`. Returns structured rows for SELECTs, a status string for everything else. |
|
|
128
|
+
| `ask_sql(question)` | **Phase 7g.3** — Natural-language → SQL via the configured LLM (Anthropic by default). Reads `AskConfig::from_env()` and calls `sqlrite::ask::ask_with_database` against the locked engine `Database`. Schema introspection + LLM HTTP call run in the Tauri Rust backend so **the API key never crosses into the webview** — same security story as Q9's WASM JS-callback shape, applied here as a natural side effect of how Tauri's command bridge works. Returns `{ sql, explanation }`; the frontend pastes `sql` into the editor for the user to review + run. Requires `SQLRITE_LLM_API_KEY` in the process environment (Tauri inherits the parent shell's env). |
|
|
128
129
|
|
|
129
130
|
### Command / response types
|
|
130
131
|
|
|
@@ -162,6 +163,7 @@ One Svelte component — [`App.svelte`](../desktop/src/App.svelte) — renders t
|
|
|
162
163
|
- **Line numbers**: rendered in a gutter on the left of the textarea; derived from the text content (`sql.split("\n").length`) and kept scroll-synced with the textarea via an `onscroll` handler. Font size and line height are locked between the gutter and the textarea so every line number aligns with its row.
|
|
163
164
|
- **Cmd/Ctrl + Enter** — run the query. If the textarea has a non-empty selection, only the selected substring runs; otherwise the full editor contents run. Matches DataGrip / DBeaver / pgAdmin behavior. The Run button label flips to **Run selection** and the shortcut hint shows "selection only" when a selection is active so the state is visible without clicking.
|
|
164
165
|
- **Cmd/Ctrl + /** — toggle SQL line comment (`-- `) on the current line or on every line of the selection. Matches VS Code / Sublime / IntelliJ convention.
|
|
166
|
+
- **Ask…** *(Phase 7g.3)* — opens a slide-in composer panel above the editor. Type a natural-language question, hit Cmd/Ctrl+Enter (or click "Generate SQL"), and the [`ask_sql`](#commands) Tauri command returns generated SQL + a one-sentence rationale. The SQL replaces the editor textarea; the rationale shows in the panel. **Generated SQL is not auto-executed** — the user reviews and clicks Run themselves. An empty SQL response (model declined the question against this schema) surfaces the model's explanation in the same slot. Esc closes the composer. Requires `SQLRITE_LLM_API_KEY` set in the environment Tauri was launched from; absence surfaces a clean "missing API key" error in the existing error slot.
|
|
165
167
|
|
|
166
168
|
The textarea starts with a short comment-only placeholder so clicking Run before typing any SQL doesn't error.
|
|
167
169
|
|
|
@@ -251,7 +251,7 @@ let rows = conn.execute(&resp.sql)?;
|
|
|
251
251
|
|
|
252
252
|
- **✅ 7g.1 — `sqlrite-ask` crate (foundational, ~750 LOC code + tests).** New separate crate (not feature-gated on the engine) so the engine stays pure-SQL with no HTTP / async deps. Owns: provider adapters (Anthropic in 7g.1; OpenAI / Ollama follow-ups), prompt construction, schema introspection helper that walks `Database.tables` directly (typed walk — cheaper + more robust than reflecting through `sqlrite_master`), the `AskResponse` type, configuration loading from env (`SQLRITE_LLM_PROVIDER` / `_API_KEY` / `_MODEL` / `_MAX_TOKENS` / `_CACHE_TTL`) or a passed config struct. Depends on `sqlrite-engine` for the schema introspection. Public API: `ask()` free function, `ConnectionAskExt::ask` trait extension on `sqlrite::Connection`, `AskConfig::from_env()`, `AskResponse { sql, explanation, usage }`. Default model `claude-sonnet-4-6` per the cost-quality NL→SQL sweet spot. Sync `ureq` HTTP (rejected reqwest::blocking — pulls tokio in even on the blocking path); JSON request/response shapes hand-rolled in serde_json (~120 LOC) — there is no official Anthropic Rust SDK, and rolling our own matches Q5's "build it yourself" theme. Schema dump goes inside a `<schema>...</schema>` block with `cache_control: ephemeral` so repeat asks against the same DB hit Anthropic's prompt cache (5-min TTL default; 1-hour TTL via `CacheTtl::OneHour`). Output parsing is tolerant — strict JSON, fenced JSON, or JSON-with-leading-prose all parse — because real LLM output drifts even with strict prompts. 30 tests pass (26 unit + 4 integration via `tiny_http` localhost mock).
|
|
253
253
|
- **✅ 7g.2 — REPL `.ask` + structural refactor.** New `MetaCommand::Ask(String)` variant + `handle_ask` that calls `sqlrite::ask::ask_with_database`, prints the generated SQL + rationale, prompts `Run? [Y/n] ` via rustyline (Ctrl-C / EOF map to skip — paranoid default for LLM-generated SQL), and pipes through `process_command` if confirmed. The thin REPL part itself is ~120 LOC. **Required a bigger structural fix that 7g.1 didn't anticipate:** wiring the binary to call into `sqlrite-ask` created a cargo cycle (`sqlrite-engine[bin] → sqlrite-ask → sqlrite-engine[lib]`) that even `optional = true` doesn't break — cargo's static cycle detection includes all potential edges. Resolution: flipped the dep direction. `sqlrite-ask` is now pure (no engine dep, canonical API takes a `&str` schema dump + `&str` question). Schema introspection + the `Connection`/`Database` integration (`ConnectionAskExt`, `ask`, `ask_with_database`, `ask_with_provider`, `ask_with_database_and_provider`) moved into `sqlrite-engine` itself under a new `ask` feature (default-on for the CLI binary, off for `--no-default-features` / WASM). Public API for end users is unchanged in spirit: `use sqlrite::{Connection, ConnectionAskExt}` instead of `use sqlrite_ask::ConnectionAskExt`. Net effect — `sqlrite-ask` shrunk + got easier to test in isolation; the engine carries the integration weight, scoped behind a feature flag so SDK / WASM / Tauri builds opt in. 30+ tests pass on both sides (sqlrite-ask: 20 unit + 4 integration; engine ask module: 6 schema + 3 .ask parser).
|
|
254
|
-
-
|
|
254
|
+
- **✅ 7g.3 — Desktop UI "Ask…" button.** New "Ask…" button in the editor toolbar plus a slide-in composer panel above the editor surface (question textarea + "Generate SQL" button + explanation slot). Submitting calls a new `ask_sql` Tauri command that reads `AskConfig::from_env()` server-side, locks the engine's `Database`, calls `sqlrite::ask::ask_with_database` (so the schema dump + LLM HTTP call stay in the Rust backend — the API key never crosses into the webview). Generated SQL drops into the editor textarea for the user to review + Run themselves; the rationale shows in the panel; an empty SQL response (model declined) surfaces the model's explanation in the same slot. Cmd/Ctrl+Enter in the question textarea submits; Esc closes. ~110 LOC of Svelte + ~30 LOC of Rust + ~85 LOC of CSS. As a side benefit, ergonomic re-exports added on `sqlrite::ask::*` (`AskConfig`, `AskResponse`, `AskError`, `Provider`, etc.) so library callers don't have to add `sqlrite-ask` as a direct dep alongside the engine.
|
|
255
255
|
- **7g.4 — Python SDK (~80 LOC).** PyO3 wrapper around `sqlrite-ask`. `Connection.ask(question)` returns a Python object with `.sql` and `.explanation`. `Connection.ask_run(question)` is the convenience that calls `execute` after.
|
|
256
256
|
- **7g.5 — Node.js SDK (~80 LOC).** Same shape via napi-rs. `db.ask(question)` / `db.askRun(question)`.
|
|
257
257
|
- **7g.6 — Go SDK (~80 LOC).** cgo wrapper. `sqlrite.Ask(db, question)` returns `(AskResponse, error)`.
|
|
@@ -476,7 +476,7 @@ Approved sub-phases (Q1–Q10 resolved):
|
|
|
476
476
|
- **✅ 7d — HNSW ANN index** — three PRs: 7d.1 (algorithm w/ recall@10 ≥ 0.95), 7d.2 (SQL integration + query optimizer), 7d.3 (persistence + DELETE/UPDATE rebuild). `CREATE INDEX … USING hnsw (col)`; fixed defaults `M=16, ef_construction=200, ef_search=50` (Q2). New `KIND_HNSW` cell tag.
|
|
477
477
|
- **✅ 7e — JSON column type + path queries** — `JSON` data type stored as canonical text (validated via `serde_json::from_str` at INSERT/UPDATE time; SQLite-JSON1-style — Q3 scope correction since bincode was removed in Phase 3c). Functions: `json_extract` / `json_type` / `json_array_length` / `json_object_keys`. Path subset supports `$`, `.key`, `[N]`, chained. `json_object_keys` returns a JSON-array text rather than a table-valued result (no set-returning functions in the executor yet).
|
|
478
478
|
- **7f — ~~Full-text search with BM25~~** — **deferred to Phase 8** (Q1).
|
|
479
|
-
- **7g — `ask()` API across the product surface** — natural-language → SQL via Anthropic API (Q4), Anthropic-first then OpenAI + Ollama follow-ups. Foundational **✅ 7g.1** introduces a new `sqlrite-ask` crate (Q10 — separate crate, not a feature flag) — `ask_with_schema()` over `&str` inputs (Phase 7g.2 made it pure — see retrospective below), sync `ureq` POST to `/v1/messages`, schema-aware prompt with prompt-caching on the schema dump (Sonnet 4.6 default; configurable). **✅ 7g.2** wires the REPL's `.ask` meta-command (`MetaCommand::Ask(String)` + confirm-and-run UX) and adds the `sqlrite::ask` module on the engine side (gated under a new `ask` feature) carrying `ConnectionAskExt` + the schema introspection helper. Per-product adapters in 7g.
|
|
479
|
+
- **7g — `ask()` API across the product surface** — natural-language → SQL via Anthropic API (Q4), Anthropic-first then OpenAI + Ollama follow-ups. Foundational **✅ 7g.1** introduces a new `sqlrite-ask` crate (Q10 — separate crate, not a feature flag) — `ask_with_schema()` over `&str` inputs (Phase 7g.2 made it pure — see retrospective below), sync `ureq` POST to `/v1/messages`, schema-aware prompt with prompt-caching on the schema dump (Sonnet 4.6 default; configurable). **✅ 7g.2** wires the REPL's `.ask` meta-command (`MetaCommand::Ask(String)` + confirm-and-run UX) and adds the `sqlrite::ask` module on the engine side (gated under a new `ask` feature) carrying `ConnectionAskExt` + the schema introspection helper. **✅ 7g.3** adds the desktop "Ask…" composer (slide-in panel above the editor; Tauri command runs the LLM call in the Rust backend so the API key stays out of the webview). Per-product adapters in 7g.4-7g.8 cover Python, Node.js, Go, WASM (JS-callback shape per Q9), and the MCP `ask` tool — and fold in the SDK README catch-up for VECTOR / JSON / HNSW capabilities along the way.
|
|
480
480
|
- **7h — MCP server adapter** — new `sqlrite-mcp` binary, hand-rolled JSON-RPC + tool framework (Q5).
|
|
481
481
|
|
|
482
482
|
Total scope budget: ~3-4 kLOC of new Rust across the wave. Each sub-phase ships as its own PR + release wave through the Phase 6 pipeline. The Phase 7 wave will likely close out **v0.2.0** (first minor bump after the 0.1.x Phase 6 cycle). Two new product lines added to lockstep versioning: `sqlrite-ask` and `sqlrite-mcp`.
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sqlrite"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.20"
|
|
8
8
|
description = "Python bindings for SQLRite — a small, embeddable SQLite clone written in Rust."
|
|
9
9
|
authors = [{ name = "Joao Henrique Machado Silva", email = "joaoh82@gmail.com" }]
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# Published to crates.io as `sqlrite-ask`. Joins the lockstep release
|
|
11
11
|
# wave (`sqlrite-ask-vX.Y.Z` tag) — see `docs/release-plan.md`.
|
|
12
12
|
name = "sqlrite-ask"
|
|
13
|
-
version = "0.1.
|
|
13
|
+
version = "0.1.20"
|
|
14
14
|
authors = ["Joao Henrique Machado Silva <joaoh82@gmail.com>"]
|
|
15
15
|
edition = "2024"
|
|
16
16
|
rust-version = "1.85"
|
|
@@ -38,15 +38,24 @@
|
|
|
38
38
|
//! for callers who don't want to bring the trait into scope, or
|
|
39
39
|
//! who hold a `&Database` directly (the REPL binary does this).
|
|
40
40
|
|
|
41
|
-
use sqlrite_ask::{
|
|
42
|
-
AskConfig, AskError, AskResponse, Provider, ask_with_schema, ask_with_schema_and_provider,
|
|
43
|
-
};
|
|
41
|
+
use sqlrite_ask::{ask_with_schema, ask_with_schema_and_provider};
|
|
44
42
|
|
|
45
43
|
use crate::Connection;
|
|
46
44
|
use crate::sql::db::database::Database;
|
|
47
45
|
|
|
48
46
|
pub mod schema;
|
|
49
47
|
|
|
48
|
+
// Re-export the public surface from sqlrite-ask. Lets callers reach
|
|
49
|
+
// these without listing `sqlrite-ask` as a direct dep — convenient
|
|
50
|
+
// for the Tauri desktop app, the SDK adapters, and any Rust embedder
|
|
51
|
+
// who already pulls the engine in. They can keep saying
|
|
52
|
+
// `use sqlrite::ask::AskConfig` instead of dragging the second crate
|
|
53
|
+
// in just for one type.
|
|
54
|
+
pub use sqlrite_ask::{
|
|
55
|
+
AnthropicProvider, AskConfig, AskError, AskResponse, CacheTtl, Provider, ProviderKind, Request,
|
|
56
|
+
Response, Usage,
|
|
57
|
+
};
|
|
58
|
+
|
|
50
59
|
/// Extension trait adding `Connection::ask` to
|
|
51
60
|
/// [`crate::Connection`]. Bring it into scope with
|
|
52
61
|
/// `use sqlrite::ConnectionAskExt;` (the engine re-exports it at
|
|
@@ -59,10 +59,12 @@ pub mod sql;
|
|
|
59
59
|
// Phase 5a public API.
|
|
60
60
|
pub use connection::{Connection, FromValue, OwnedRow, Row, Rows, Statement};
|
|
61
61
|
|
|
62
|
-
// Phase 7g.2: re-export the `Connection::ask` extension trait
|
|
63
|
-
// crate root when the `ask`
|
|
64
|
-
//
|
|
65
|
-
// ConnectionAskExt
|
|
62
|
+
// Phase 7g.2: re-export the `Connection::ask` extension trait + the
|
|
63
|
+
// public `sqlrite_ask` types at the crate root when the `ask`
|
|
64
|
+
// feature is on. Lets callers write `use sqlrite::{Connection,
|
|
65
|
+
// ConnectionAskExt, ask::AskConfig};` rather than dragging in
|
|
66
|
+
// `sqlrite-ask` as a separate dep just to reach `AskConfig`. Only
|
|
67
|
+
// available with the `ask` feature.
|
|
66
68
|
#[cfg(feature = "ask")]
|
|
67
69
|
pub use ask::ConnectionAskExt;
|
|
68
70
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sqlrite-0.1.19 → sqlrite-0.1.20}/images/SQLRite Simple SQL Execution High Level Diagram.png
RENAMED
|
File without changes
|
|
File without changes
|
{sqlrite-0.1.19 → sqlrite-0.1.20}/images/SQLRite Simple SQL INSERT Execution High Level Diagram.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|