sqlrite 0.1.16__tar.gz → 0.1.17__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.
Files changed (110) hide show
  1. {sqlrite-0.1.16 → sqlrite-0.1.17}/.github/workflows/release.yml +69 -1
  2. {sqlrite-0.1.16 → sqlrite-0.1.17}/Cargo.lock +159 -5
  3. {sqlrite-0.1.16 → sqlrite-0.1.17}/Cargo.toml +1 -1
  4. {sqlrite-0.1.16 → sqlrite-0.1.17}/PKG-INFO +59 -1
  5. {sqlrite-0.1.16 → sqlrite-0.1.17}/README.md +36 -4
  6. {sqlrite-0.1.16 → sqlrite-0.1.17}/desktop/package.json +1 -1
  7. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/embedding.md +47 -0
  8. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/phase-7-plan.md +1 -1
  9. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/release-plan.md +12 -3
  10. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/roadmap.md +1 -1
  11. {sqlrite-0.1.16 → sqlrite-0.1.17}/pyproject.toml +1 -1
  12. {sqlrite-0.1.16 → sqlrite-0.1.17}/scripts/bump-version.sh +7 -5
  13. {sqlrite-0.1.16 → sqlrite-0.1.17}/sdk/go/README.md +58 -0
  14. {sqlrite-0.1.16 → sqlrite-0.1.17}/sdk/python/Cargo.toml +1 -1
  15. {sqlrite-0.1.16 → sqlrite-0.1.17}/sdk/python/README.md +58 -0
  16. {sqlrite-0.1.16 → sqlrite-0.1.17}/.github/workflows/ci.yml +0 -0
  17. {sqlrite-0.1.16 → sqlrite-0.1.17}/.github/workflows/release-pr.yml +0 -0
  18. {sqlrite-0.1.16 → sqlrite-0.1.17}/.github/workflows/rust.yml +0 -0
  19. {sqlrite-0.1.16 → sqlrite-0.1.17}/.gitignore +0 -0
  20. {sqlrite-0.1.16 → sqlrite-0.1.17}/CODE_OF_CONDUCT.md +0 -0
  21. {sqlrite-0.1.16 → sqlrite-0.1.17}/LICENSE +0 -0
  22. {sqlrite-0.1.16 → sqlrite-0.1.17}/MAINTAINERS +0 -0
  23. {sqlrite-0.1.16 → sqlrite-0.1.17}/Makefile +0 -0
  24. {sqlrite-0.1.16 → sqlrite-0.1.17}/desktop/index.html +0 -0
  25. {sqlrite-0.1.16 → sqlrite-0.1.17}/desktop/package-lock.json +0 -0
  26. {sqlrite-0.1.16 → sqlrite-0.1.17}/desktop/src/App.svelte +0 -0
  27. {sqlrite-0.1.16 → sqlrite-0.1.17}/desktop/src/app.css +0 -0
  28. {sqlrite-0.1.16 → sqlrite-0.1.17}/desktop/src/main.ts +0 -0
  29. {sqlrite-0.1.16 → sqlrite-0.1.17}/desktop/src/vite-env.d.ts +0 -0
  30. {sqlrite-0.1.16 → sqlrite-0.1.17}/desktop/svelte.config.js +0 -0
  31. {sqlrite-0.1.16 → sqlrite-0.1.17}/desktop/tsconfig.json +0 -0
  32. {sqlrite-0.1.16 → sqlrite-0.1.17}/desktop/vite.config.ts +0 -0
  33. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/_index.md +0 -0
  34. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/architecture.md +0 -0
  35. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/design-decisions.md +0 -0
  36. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/desktop.md +0 -0
  37. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/file-format.md +0 -0
  38. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/getting-started.md +0 -0
  39. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/pager.md +0 -0
  40. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/release-secrets.md +0 -0
  41. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/smoke-test.md +0 -0
  42. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/sql-engine.md +0 -0
  43. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/storage-model.md +0 -0
  44. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/supported-sql.md +0 -0
  45. {sqlrite-0.1.16 → sqlrite-0.1.17}/docs/usage.md +0 -0
  46. {sqlrite-0.1.16 → sqlrite-0.1.17}/examples/README.md +0 -0
  47. {sqlrite-0.1.16 → sqlrite-0.1.17}/examples/c/Makefile +0 -0
  48. {sqlrite-0.1.16 → sqlrite-0.1.17}/examples/c/hello.c +0 -0
  49. {sqlrite-0.1.16 → sqlrite-0.1.17}/examples/go/go.mod +0 -0
  50. {sqlrite-0.1.16 → sqlrite-0.1.17}/examples/go/hello.go +0 -0
  51. {sqlrite-0.1.16 → sqlrite-0.1.17}/examples/nodejs/hello.mjs +0 -0
  52. {sqlrite-0.1.16 → sqlrite-0.1.17}/examples/python/hello.py +0 -0
  53. {sqlrite-0.1.16 → sqlrite-0.1.17}/examples/rust/quickstart.rs +0 -0
  54. {sqlrite-0.1.16 → sqlrite-0.1.17}/examples/wasm/Makefile +0 -0
  55. {sqlrite-0.1.16 → sqlrite-0.1.17}/examples/wasm/index.html +0 -0
  56. {sqlrite-0.1.16 → sqlrite-0.1.17}/images/SQLRite - Desktop.png +0 -0
  57. {sqlrite-0.1.16 → sqlrite-0.1.17}/images/SQLRite Data Structures.png +0 -0
  58. {sqlrite-0.1.16 → sqlrite-0.1.17}/images/SQLRite Simple SQL Execution High Level Diagram.png +0 -0
  59. {sqlrite-0.1.16 → sqlrite-0.1.17}/images/SQLRite Simple SQL INSERT Execution High Level Diagram (Insert Row).png +0 -0
  60. {sqlrite-0.1.16 → sqlrite-0.1.17}/images/SQLRite Simple SQL INSERT Execution High Level Diagram.png +0 -0
  61. {sqlrite-0.1.16 → sqlrite-0.1.17}/images/SQLRite_logo.png +0 -0
  62. {sqlrite-0.1.16 → sqlrite-0.1.17}/images/architecture.png +0 -0
  63. {sqlrite-0.1.16 → sqlrite-0.1.17}/rust-toolchain.toml +0 -0
  64. {sqlrite-0.1.16 → sqlrite-0.1.17}/samples/AST.delete.example +0 -0
  65. {sqlrite-0.1.16 → sqlrite-0.1.17}/samples/AST.insert.exemple +0 -0
  66. {sqlrite-0.1.16 → sqlrite-0.1.17}/samples/AST.select.example +0 -0
  67. {sqlrite-0.1.16 → sqlrite-0.1.17}/samples/AST.update.example +0 -0
  68. {sqlrite-0.1.16 → sqlrite-0.1.17}/samples/CREATE TABLE sqlrite_schema.sql +0 -0
  69. {sqlrite-0.1.16 → sqlrite-0.1.17}/samples/CREATE_TABLE with duplicate.sql +0 -0
  70. {sqlrite-0.1.16 → sqlrite-0.1.17}/samples/CREATE_TABLE.sql +0 -0
  71. {sqlrite-0.1.16 → sqlrite-0.1.17}/samples/INSERT.sql +0 -0
  72. {sqlrite-0.1.16 → sqlrite-0.1.17}/sdk/go/conn.go +0 -0
  73. {sqlrite-0.1.16 → sqlrite-0.1.17}/sdk/go/go.mod +0 -0
  74. {sqlrite-0.1.16 → sqlrite-0.1.17}/sdk/go/rows.go +0 -0
  75. {sqlrite-0.1.16 → sqlrite-0.1.17}/sdk/go/sqlrite.go +0 -0
  76. {sqlrite-0.1.16 → sqlrite-0.1.17}/sdk/go/sqlrite_test.go +0 -0
  77. {sqlrite-0.1.16 → sqlrite-0.1.17}/sdk/go/stmt.go +0 -0
  78. {sqlrite-0.1.16 → sqlrite-0.1.17}/sdk/python/src/lib.rs +0 -0
  79. {sqlrite-0.1.16 → sqlrite-0.1.17}/sdk/python/tests/test_sqlrite.py +0 -0
  80. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/connection.rs +0 -0
  81. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/error.rs +0 -0
  82. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/lib.rs +0 -0
  83. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/main.rs +0 -0
  84. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/meta_command/mod.rs +0 -0
  85. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/repl/mod.rs +0 -0
  86. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/db/database.rs +0 -0
  87. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/db/mod.rs +0 -0
  88. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/db/secondary_index.rs +0 -0
  89. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/db/table.rs +0 -0
  90. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/executor.rs +0 -0
  91. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/hnsw.rs +0 -0
  92. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/mod.rs +0 -0
  93. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/pager/cell.rs +0 -0
  94. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/pager/file.rs +0 -0
  95. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/pager/header.rs +0 -0
  96. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/pager/hnsw_cell.rs +0 -0
  97. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/pager/index_cell.rs +0 -0
  98. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/pager/interior_page.rs +0 -0
  99. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/pager/mod.rs +0 -0
  100. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/pager/overflow.rs +0 -0
  101. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/pager/page.rs +0 -0
  102. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/pager/pager.rs +0 -0
  103. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/pager/table_page.rs +0 -0
  104. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/pager/varint.rs +0 -0
  105. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/pager/wal.rs +0 -0
  106. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/parser/create.rs +0 -0
  107. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/parser/insert.rs +0 -0
  108. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/parser/mod.rs +0 -0
  109. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/parser/select.rs +0 -0
  110. {sqlrite-0.1.16 → sqlrite-0.1.17}/src/sql/tokenizer.rs +0 -0
@@ -126,6 +126,7 @@ jobs:
126
126
  TAGS=(
127
127
  "sqlrite-v$V"
128
128
  "sqlrite-ffi-v$V"
129
+ "sqlrite-ask-v$V"
129
130
  "sqlrite-desktop-v$V"
130
131
  "sqlrite-py-v$V"
131
132
  "sqlrite-node-v$V"
@@ -199,6 +200,73 @@ jobs:
199
200
  See the umbrella release [v${{ needs.detect.outputs.version }}](../../releases/tag/v${{ needs.detect.outputs.version }}) for the full changelog.
200
201
  generate_release_notes: true
201
202
 
203
+ # ---------------------------------------------------------------------------
204
+ # Step 3a': publish the `sqlrite-ask` crate (Phase 7g.1) — natural-
205
+ # language → SQL adapter built on top of the engine. Same shape as
206
+ # `publish-crate` above; separate job so a registry hiccup on one
207
+ # doesn't block the other and re-runs are surgical.
208
+ #
209
+ # Crate name on crates.io: `sqlrite-ask`. Library name (the `use`
210
+ # path): `sqlrite_ask`. No alias-renaming this time — the short
211
+ # name was available unlike `sqlrite` (see Phase 6d retrospective
212
+ # for why the engine had to rename).
213
+ publish-ask:
214
+ name: Publish sqlrite-ask crate to crates.io
215
+ needs: [detect, tag-all, publish-crate]
216
+ if: needs.detect.outputs.should_release == 'true'
217
+ runs-on: ubuntu-latest
218
+ environment: release
219
+ steps:
220
+ - uses: actions/checkout@v4
221
+
222
+ - uses: dtolnay/rust-toolchain@stable
223
+
224
+ - uses: Swatinem/rust-cache@v2
225
+ with:
226
+ shared-key: publish-ask
227
+
228
+ - name: cargo publish
229
+ env:
230
+ CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
231
+ # `--no-verify` mirrors `publish-crate` — Release-PR CI
232
+ # already validated this commit.
233
+ #
234
+ # `needs: [..., publish-crate]` is load-bearing: sqlrite-ask
235
+ # depends on sqlrite-engine, and crates.io rejects publishes
236
+ # whose path-deps haven't yet resolved to a published version
237
+ # at the same number. Sequencing makes the dep visible by the
238
+ # time we publish.
239
+ run: cargo publish -p sqlrite-ask --no-verify
240
+
241
+ - name: GitHub Release
242
+ uses: softprops/action-gh-release@v2
243
+ with:
244
+ tag_name: sqlrite-ask-v${{ needs.detect.outputs.version }}
245
+ name: sqlrite-ask v${{ needs.detect.outputs.version }}
246
+ body: |
247
+ Published to crates.io: https://crates.io/crates/sqlrite-ask/${{ needs.detect.outputs.version }}
248
+
249
+ Natural-language → SQL adapter for SQLRite. Anthropic-first; OpenAI / Ollama follow-ups.
250
+
251
+ ```toml
252
+ [dependencies]
253
+ sqlrite-engine = "${{ needs.detect.outputs.version }}"
254
+ sqlrite-ask = "${{ needs.detect.outputs.version }}"
255
+ ```
256
+
257
+ ```rust
258
+ use sqlrite::Connection;
259
+ use sqlrite_ask::{AskConfig, ConnectionAskExt};
260
+
261
+ let conn = Connection::open("foo.sqlrite")?;
262
+ let cfg = AskConfig::from_env()?; // SQLRITE_LLM_API_KEY etc.
263
+ let resp = conn.ask("How many users are over 30?", &cfg)?;
264
+ println!("Generated SQL: {}", resp.sql);
265
+ ```
266
+
267
+ See the umbrella release [v${{ needs.detect.outputs.version }}](../../releases/tag/v${{ needs.detect.outputs.version }}) for the full changelog.
268
+ generate_release_notes: true
269
+
202
270
  # ---------------------------------------------------------------------------
203
271
  # Step 3b: build `libsqlrite_c` for each supported platform and
204
272
  # upload the tarballs to the `sqlrite-ffi-v<V>` GitHub Release.
@@ -1223,7 +1291,7 @@ jobs:
1223
1291
  # config if we add one later.
1224
1292
  finalize:
1225
1293
  name: Finalize umbrella release
1226
- needs: [detect, publish-crate, publish-ffi, publish-desktop, publish-python, publish-nodejs, publish-wasm, publish-go]
1294
+ needs: [detect, publish-crate, publish-ask, publish-ffi, publish-desktop, publish-python, publish-nodejs, publish-wasm, publish-go]
1227
1295
  if: needs.detect.outputs.should_release == 'true'
1228
1296
  runs-on: ubuntu-latest
1229
1297
  steps:
@@ -106,6 +106,12 @@ dependencies = [
106
106
  "object",
107
107
  ]
108
108
 
109
+ [[package]]
110
+ name = "ascii"
111
+ version = "1.1.0"
112
+ source = "registry+https://github.com/rust-lang/crates.io-index"
113
+ checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16"
114
+
109
115
  [[package]]
110
116
  name = "atk"
111
117
  version = "0.18.2"
@@ -396,6 +402,12 @@ dependencies = [
396
402
  "windows-link 0.2.1",
397
403
  ]
398
404
 
405
+ [[package]]
406
+ name = "chunked_transfer"
407
+ version = "1.5.0"
408
+ source = "registry+https://github.com/rust-lang/crates.io-index"
409
+ checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901"
410
+
399
411
  [[package]]
400
412
  name = "clap"
401
413
  version = "4.6.1"
@@ -1557,6 +1569,12 @@ version = "1.10.1"
1557
1569
  source = "registry+https://github.com/rust-lang/crates.io-index"
1558
1570
  checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
1559
1571
 
1572
+ [[package]]
1573
+ name = "httpdate"
1574
+ version = "1.0.3"
1575
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1576
+ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
1577
+
1560
1578
  [[package]]
1561
1579
  name = "hyper"
1562
1580
  version = "1.9.0"
@@ -3267,6 +3285,20 @@ dependencies = [
3267
3285
  "windows-sys 0.60.2",
3268
3286
  ]
3269
3287
 
3288
+ [[package]]
3289
+ name = "ring"
3290
+ version = "0.17.14"
3291
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3292
+ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
3293
+ dependencies = [
3294
+ "cc",
3295
+ "cfg-if",
3296
+ "getrandom 0.2.17",
3297
+ "libc",
3298
+ "untrusted",
3299
+ "windows-sys 0.52.0",
3300
+ ]
3301
+
3270
3302
  [[package]]
3271
3303
  name = "rustc-hash"
3272
3304
  version = "2.1.2"
@@ -3295,6 +3327,41 @@ dependencies = [
3295
3327
  "windows-sys 0.61.2",
3296
3328
  ]
3297
3329
 
3330
+ [[package]]
3331
+ name = "rustls"
3332
+ version = "0.23.40"
3333
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3334
+ checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b"
3335
+ dependencies = [
3336
+ "log",
3337
+ "once_cell",
3338
+ "ring",
3339
+ "rustls-pki-types",
3340
+ "rustls-webpki",
3341
+ "subtle",
3342
+ "zeroize",
3343
+ ]
3344
+
3345
+ [[package]]
3346
+ name = "rustls-pki-types"
3347
+ version = "1.14.1"
3348
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3349
+ checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9"
3350
+ dependencies = [
3351
+ "zeroize",
3352
+ ]
3353
+
3354
+ [[package]]
3355
+ name = "rustls-webpki"
3356
+ version = "0.103.13"
3357
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3358
+ checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
3359
+ dependencies = [
3360
+ "ring",
3361
+ "rustls-pki-types",
3362
+ "untrusted",
3363
+ ]
3364
+
3298
3365
  [[package]]
3299
3366
  name = "rustversion"
3300
3367
  version = "1.0.22"
@@ -3735,9 +3802,21 @@ dependencies = [
3735
3802
  "recursive",
3736
3803
  ]
3737
3804
 
3805
+ [[package]]
3806
+ name = "sqlrite-ask"
3807
+ version = "0.1.17"
3808
+ dependencies = [
3809
+ "serde",
3810
+ "serde_json",
3811
+ "sqlrite-engine",
3812
+ "thiserror 2.0.18",
3813
+ "tiny_http",
3814
+ "ureq",
3815
+ ]
3816
+
3738
3817
  [[package]]
3739
3818
  name = "sqlrite-desktop"
3740
- version = "0.1.16"
3819
+ version = "0.1.17"
3741
3820
  dependencies = [
3742
3821
  "serde",
3743
3822
  "serde_json",
@@ -3749,7 +3828,7 @@ dependencies = [
3749
3828
 
3750
3829
  [[package]]
3751
3830
  name = "sqlrite-engine"
3752
- version = "0.1.16"
3831
+ version = "0.1.17"
3753
3832
  dependencies = [
3754
3833
  "clap",
3755
3834
  "env_logger",
@@ -3765,7 +3844,7 @@ dependencies = [
3765
3844
 
3766
3845
  [[package]]
3767
3846
  name = "sqlrite-ffi"
3768
- version = "0.1.16"
3847
+ version = "0.1.17"
3769
3848
  dependencies = [
3770
3849
  "cbindgen",
3771
3850
  "sqlrite-engine",
@@ -3773,7 +3852,7 @@ dependencies = [
3773
3852
 
3774
3853
  [[package]]
3775
3854
  name = "sqlrite-nodejs"
3776
- version = "0.1.16"
3855
+ version = "0.1.17"
3777
3856
  dependencies = [
3778
3857
  "napi",
3779
3858
  "napi-build",
@@ -3783,7 +3862,7 @@ dependencies = [
3783
3862
 
3784
3863
  [[package]]
3785
3864
  name = "sqlrite-python"
3786
- version = "0.1.16"
3865
+ version = "0.1.17"
3787
3866
  dependencies = [
3788
3867
  "pyo3",
3789
3868
  "sqlrite-engine",
@@ -3863,6 +3942,12 @@ version = "0.11.1"
3863
3942
  source = "registry+https://github.com/rust-lang/crates.io-index"
3864
3943
  checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
3865
3944
 
3945
+ [[package]]
3946
+ name = "subtle"
3947
+ version = "2.6.1"
3948
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3949
+ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
3950
+
3866
3951
  [[package]]
3867
3952
  name = "swift-rs"
3868
3953
  version = "1.0.7"
@@ -4373,6 +4458,18 @@ dependencies = [
4373
4458
  "time-core",
4374
4459
  ]
4375
4460
 
4461
+ [[package]]
4462
+ name = "tiny_http"
4463
+ version = "0.12.0"
4464
+ source = "registry+https://github.com/rust-lang/crates.io-index"
4465
+ checksum = "389915df6413a2e74fb181895f933386023c71110878cd0825588928e64cdc82"
4466
+ dependencies = [
4467
+ "ascii",
4468
+ "chunked_transfer",
4469
+ "httpdate",
4470
+ "log",
4471
+ ]
4472
+
4376
4473
  [[package]]
4377
4474
  name = "tinystr"
4378
4475
  version = "0.8.3"
@@ -4696,6 +4793,30 @@ version = "0.2.4"
4696
4793
  source = "registry+https://github.com/rust-lang/crates.io-index"
4697
4794
  checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
4698
4795
 
4796
+ [[package]]
4797
+ name = "untrusted"
4798
+ version = "0.9.0"
4799
+ source = "registry+https://github.com/rust-lang/crates.io-index"
4800
+ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
4801
+
4802
+ [[package]]
4803
+ name = "ureq"
4804
+ version = "2.12.1"
4805
+ source = "registry+https://github.com/rust-lang/crates.io-index"
4806
+ checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d"
4807
+ dependencies = [
4808
+ "base64 0.22.1",
4809
+ "flate2",
4810
+ "log",
4811
+ "once_cell",
4812
+ "rustls",
4813
+ "rustls-pki-types",
4814
+ "serde",
4815
+ "serde_json",
4816
+ "url",
4817
+ "webpki-roots 0.26.11",
4818
+ ]
4819
+
4699
4820
  [[package]]
4700
4821
  name = "url"
4701
4822
  version = "2.5.8"
@@ -5000,6 +5121,24 @@ dependencies = [
5000
5121
  "system-deps",
5001
5122
  ]
5002
5123
 
5124
+ [[package]]
5125
+ name = "webpki-roots"
5126
+ version = "0.26.11"
5127
+ source = "registry+https://github.com/rust-lang/crates.io-index"
5128
+ checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
5129
+ dependencies = [
5130
+ "webpki-roots 1.0.7",
5131
+ ]
5132
+
5133
+ [[package]]
5134
+ name = "webpki-roots"
5135
+ version = "1.0.7"
5136
+ source = "registry+https://github.com/rust-lang/crates.io-index"
5137
+ checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d"
5138
+ dependencies = [
5139
+ "rustls-pki-types",
5140
+ ]
5141
+
5003
5142
  [[package]]
5004
5143
  name = "webview2-com"
5005
5144
  version = "0.38.2"
@@ -5230,6 +5369,15 @@ dependencies = [
5230
5369
  "windows-targets 0.42.2",
5231
5370
  ]
5232
5371
 
5372
+ [[package]]
5373
+ name = "windows-sys"
5374
+ version = "0.52.0"
5375
+ source = "registry+https://github.com/rust-lang/crates.io-index"
5376
+ checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
5377
+ dependencies = [
5378
+ "windows-targets 0.52.6",
5379
+ ]
5380
+
5233
5381
  [[package]]
5234
5382
  name = "windows-sys"
5235
5383
  version = "0.59.0"
@@ -5724,6 +5872,12 @@ dependencies = [
5724
5872
  "synstructure",
5725
5873
  ]
5726
5874
 
5875
+ [[package]]
5876
+ name = "zeroize"
5877
+ version = "1.8.2"
5878
+ source = "registry+https://github.com/rust-lang/crates.io-index"
5879
+ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
5880
+
5727
5881
  [[package]]
5728
5882
  name = "zerotrie"
5729
5883
  version = "0.2.4"
@@ -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.16"
30
+ version = "0.1.17"
31
31
  authors = ["Joao Henrique Machado Silva <joaoh82@gmail.com>"]
32
32
  edition = "2024"
33
33
  rust-version = "1.85"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlrite
3
- Version: 0.1.16
3
+ Version: 0.1.17
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -87,6 +87,64 @@ conn = sqlrite.connect_read_only("foo.sqlrite")
87
87
  # connections on the same file coexist (shared OS lock).
88
88
  ```
89
89
 
90
+ ### Vector columns + KNN (Phase 7a–7d)
91
+
92
+ The engine ships with a fixed-dimension `VECTOR(N)` storage class and three distance functions (`vec_distance_l2`, `vec_distance_cosine`, `vec_distance_dot`). Plain `cursor.execute(...)` is all you need from Python — values come back as Python lists of floats.
93
+
94
+ ```python
95
+ cur.execute("CREATE TABLE docs (id INTEGER PRIMARY KEY, embedding VECTOR(384))")
96
+ cur.execute("INSERT INTO docs (id, embedding) VALUES (1, [0.1, 0.2, ..., 0.0])") # 384 floats
97
+ cur.execute("""
98
+ SELECT id FROM docs
99
+ ORDER BY vec_distance_l2(embedding, [0.1, 0.2, ..., 0.0])
100
+ LIMIT 10
101
+ """)
102
+ for row in cur:
103
+ print(row)
104
+ ```
105
+
106
+ For larger collections, build an HNSW index — the executor will use it automatically when the `WHERE`/`ORDER BY` shape matches:
107
+
108
+ ```python
109
+ cur.execute("CREATE INDEX idx_docs_emb ON docs USING hnsw (embedding)")
110
+ ```
111
+
112
+ ### JSON columns (Phase 7e)
113
+
114
+ `JSON` (and `JSONB` as an alias) columns store text, validated at INSERT/UPDATE time. Read with `json_extract` / `json_type` / `json_array_length` / `json_object_keys`. Path subset: `$`, `.key`, `[N]`, chained.
115
+
116
+ ```python
117
+ cur.execute("CREATE TABLE events (id INTEGER PRIMARY KEY, payload JSON)")
118
+ cur.execute(
119
+ "INSERT INTO events (payload) VALUES "
120
+ "('{\"user\": {\"name\": \"alice\"}, \"score\": 42}')"
121
+ )
122
+ cur.execute(
123
+ "SELECT json_extract(payload, '$.user.name'), json_type(payload, '$.score') FROM events"
124
+ )
125
+ print(cur.fetchall()) # [('alice', 'integer')]
126
+ ```
127
+
128
+ > `json_object_keys` returns a JSON-array text rather than a table-valued result (set-returning functions aren't supported yet).
129
+
130
+ ### Natural-language → SQL (Phase 7g — *coming soon*)
131
+
132
+ The Phase 7g.2-7g.8 wave adds a Python-native `conn.ask()` that wraps the new `sqlrite-ask` Rust crate via PyO3. Today it's available only from Rust ([`sqlrite-ask` on crates.io](https://crates.io/crates/sqlrite-ask)); the Python wrapper lands in 7g.4 and will look like:
133
+
134
+ ```python
135
+ # 7g.4 preview — not yet released
136
+ import sqlrite
137
+
138
+ conn = sqlrite.connect("foo.sqlrite")
139
+ cfg = sqlrite.AskConfig.from_env() # SQLRITE_LLM_API_KEY etc.
140
+ resp = conn.ask("How many users are over 30?", cfg)
141
+ print(resp.sql) # "SELECT COUNT(*) FROM users WHERE age > 30"
142
+ print(resp.explanation) # "Counts users over the age threshold."
143
+
144
+ # Convenience:
145
+ rows = conn.ask_run("How many users are over 30?", cfg).fetchall()
146
+ ```
147
+
90
148
  ## API surface
91
149
 
92
150
  | Function / Method | Purpose |
@@ -158,6 +158,32 @@ Expressions in `WHERE` and `UPDATE`'s `SET` RHS:
158
158
  | `.read FILENAME` | later |
159
159
  | `.ast QUERY` | later |
160
160
 
161
+ #### Natural-language → SQL (`sqlrite-ask`)
162
+
163
+ *Phase 7g.1.* The companion crate [`sqlrite-ask`](sqlrite-ask/) turns a natural-language question into a SQL query against your database, using the [Anthropic API](https://docs.anthropic.com/) for the actual generation.
164
+
165
+ ```toml
166
+ [dependencies]
167
+ sqlrite-engine = "0.1"
168
+ sqlrite-ask = "0.1"
169
+ ```
170
+
171
+ ```rust
172
+ use sqlrite::Connection;
173
+ use sqlrite_ask::{AskConfig, ConnectionAskExt};
174
+
175
+ let conn = Connection::open("foo.sqlrite")?;
176
+ let cfg = AskConfig::from_env()?; // SQLRITE_LLM_API_KEY etc.
177
+ let resp = conn.ask("How many users are over 30?", &cfg)?;
178
+ println!("Generated SQL: {}", resp.sql);
179
+ println!("Why: {}", resp.explanation);
180
+ // Caller decides whether to run resp.sql — the library deliberately doesn't.
181
+ ```
182
+
183
+ **Defaults:** `claude-sonnet-4-6`, `max_tokens: 1024`, schema dump cached for 5 minutes via Anthropic prompt caching (configurable to 1h or off via `AskConfig::cache_ttl`). Bring your own API key — set `SQLRITE_LLM_API_KEY` or pass it on `AskConfig`.
184
+
185
+ Per-product `ask()` wrappers (`.ask` REPL command, desktop "Ask" button, `conn.ask()` in the Python / Node / Go SDKs, and the MCP `ask` tool) ship in **7g.2-7g.8** as follow-up sub-phases. WASM gets a JS-callback shape so the API key never enters the browser. See [`docs/phase-7-plan.md`](docs/phase-7-plan.md) §7g for the full surface plan.
186
+
161
187
  ### Roadmap
162
188
 
163
189
  The project is staged in phases, each independently shippable. A finished phase is committed to `main` before the next one starts.
@@ -236,10 +262,16 @@ Lockstep versioning — one dispatch bumps every product to the same `vX.Y.Z`. T
236
262
  - [ ] macOS Apple Developer ID cert → `codesign` + `notarytool` in `tauri-action`
237
263
  - [ ] Windows code-signing cert → `signtool` in `tauri-action`
238
264
 
239
- **Phase 7 — AI-era extensions** *(research)*
240
- - [ ] Vector / embedding column type with an ANN index
241
- - [ ] Natural-language SQL front-end that emits queries against this engine
242
- - [ ] Other agent-era ideas as they emerge
265
+ **Phase 7 — AI-era extensions** *(in progress — full plan in [`docs/phase-7-plan.md`](docs/phase-7-plan.md))*
266
+ - [x] **7a `VECTOR(N)` column type** *(v0.1.10)*: dense f32 vectors with bracket-array literal syntax (`[0.1, 0.2, ...]`); file format bumped to v4
267
+ - [x] **7b Distance functions** *(v0.1.11)*: `vec_distance_l2/cosine/dot` + `ORDER BY <expr> LIMIT k` so KNN queries work end-to-end
268
+ - [x] **7c — Bounded-heap top-k optimization** *(v0.1.12)*
269
+ - [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
270
+ - [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
271
+ - [x] **7g.1 — `sqlrite-ask` crate** *(this wave)*: foundational natural-language → SQL via the [Anthropic API](https://docs.anthropic.com/) (Sonnet 4.6 by default), prompt-cached schema dump, sync `ureq` HTTP. Public surface: `sqlrite_ask::ask(conn, q, &cfg)` or `conn.ask(q, &cfg)` via `ConnectionAskExt`.
272
+ - [ ] **7g.2-7g.8** — per-product `ask()` adapters: REPL `.ask`, desktop "Ask" button, Python/Node/Go/WASM SDKs, MCP `ask` tool
273
+ - [ ] **7h** — MCP server adapter (`sqlrite-mcp` binary)
274
+ - [ ] *(deferred to Phase 8)* Full-text search with BM25 + hybrid retrieval
243
275
 
244
276
  **Possible extras** *(no committed phase)*
245
277
  - Joins (`INNER`, `LEFT OUTER`, `CROSS` — SQLite does not support `RIGHT`/`FULL OUTER`)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sqlrite-desktop-frontend",
3
3
  "private": true,
4
- "version": "0.1.16",
4
+ "version": "0.1.17",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -71,6 +71,53 @@ See [Phase 4f notes in roadmap.md](roadmap.md) for the snapshot semantics and th
71
71
  - **Parameter binding.** `stmt.query(&[&"alice"])` is the intended shape but the current implementation takes no arguments — use string interpolation for now. Parameter binding lands with the cursor refactor.
72
72
  - **Cursor abstraction.** The Pager still eagerly loads every row at open time; `Rows` today wraps an in-memory `Vec`. Phase 5a's follow-up refactor streams rows through the B-Tree on demand — same public API, much lower memory for big SELECTs.
73
73
 
74
+ ### Natural-language → SQL via `sqlrite-ask` (Phase 7g.1)
75
+
76
+ The companion crate [`sqlrite-ask`](../sqlrite-ask/) layers a natural-language → SQL helper on top of the engine. Engine stays pure-SQL with no HTTP / TLS / async deps; anyone who doesn't need `ask()` can ignore the crate entirely.
77
+
78
+ ```toml
79
+ [dependencies]
80
+ sqlrite-engine = "0.1"
81
+ sqlrite-ask = "0.1"
82
+ ```
83
+
84
+ ```rust
85
+ use sqlrite::Connection;
86
+ use sqlrite_ask::{AskConfig, AskResponse, ConnectionAskExt};
87
+
88
+ let conn = Connection::open("foo.sqlrite")?;
89
+ let cfg = AskConfig::from_env()?; // reads SQLRITE_LLM_API_KEY etc.
90
+ let resp: AskResponse = conn.ask("How many users are over 30?", &cfg)?;
91
+
92
+ println!("Generated SQL: {}", resp.sql);
93
+ println!("Rationale: {}", resp.explanation);
94
+ println!("Tokens: in={}, out={}, cache_hit={}",
95
+ resp.usage.input_tokens,
96
+ resp.usage.output_tokens,
97
+ resp.usage.cache_read_input_tokens);
98
+
99
+ // Caller decides whether to execute the generated SQL — the library
100
+ // does NOT auto-execute. SDK convenience wrappers (Python's
101
+ // `conn.ask_run()`, Node's `db.askRun()`, etc.) add a one-shot
102
+ // generate-and-execute helper, but the default Rust API is
103
+ // "generate, return, let me decide".
104
+ let mut conn = conn; // need &mut for execute
105
+ let _ = conn.execute(&resp.sql)?;
106
+ ```
107
+
108
+ **What `sqlrite-ask` provides:**
109
+
110
+ - `ask(conn, question, config) -> AskResponse` — free function entry point.
111
+ - `Connection::ask(question, config)` via the `ConnectionAskExt` trait — same flow, method syntax.
112
+ - `AskConfig::from_env()` — reads `SQLRITE_LLM_PROVIDER` / `_API_KEY` / `_MODEL` / `_MAX_TOKENS` / `_CACHE_TTL` with sensible defaults.
113
+ - `AnthropicProvider` — sync `ureq` POST to `https://api.anthropic.com/v1/messages`. The crate is provider-pluggable (a `Provider` trait + `Request` / `Response` types), with OpenAI and Ollama follow-ups planned for later 7g sub-phases.
114
+ - Schema-aware prompt construction — walks `Database.tables` deterministically (alphabetical) and emits a `<schema>...</schema>` block with `cache_control: ephemeral`, so the schema dump is served from Anthropic's prompt cache after the first call.
115
+ - Output parser tolerant to fenced JSON (`` ```json … ``` ``) or JSON-with-leading-prose, in addition to strict JSON.
116
+
117
+ **Defaults:** `claude-sonnet-4-6`, `max_tokens: 1024`, 5-minute prompt-cache TTL. Configurable via `AskConfig`.
118
+
119
+ **Per-product wrappers ship in 7g.2-7g.8** — REPL `.ask`, desktop "Ask" button, Python/Node/Go SDKs `conn.ask()`, WASM SDK with a JS-callback shape (so the API key stays out of the browser tab), and the MCP `ask` tool.
120
+
74
121
  ## The C FFI (Phase 5b)
75
122
 
76
123
  The `sqlrite-ffi/` crate wraps the Rust API in a C ABI that every non-Rust SDK binds against. Build the shared library:
@@ -249,7 +249,7 @@ let rows = conn.execute(&resp.sql)?;
249
249
 
250
250
  **Layered design.** The work splits into one library layer + several thin adapters:
251
251
 
252
- - **7g.1 — `sqlrite-ask` crate (foundational, ~400 LOC).** New separate crate (not feature-gated on the engine) so the engine stays pure-SQL with no HTTP / async deps. Owns: provider adapters (Anthropic / OpenAI / Ollama), prompt construction, schema introspection helper that walks `sqlrite_master`, the `AskResponse` type, configuration loading from env or a passed config struct. Depends on `sqlrite-engine` for the schema introspection.
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` (~80 LOC).** Thin. Calls `sqlrite-ask`, prints the generated SQL, prompts `Y/n`, runs if confirmed. Most of the file is the rustyline integration.
254
254
  - **7g.3 — Desktop UI (~150 LOC).** New "Ask" button + prompt input + inline SQL preview in the editor. Calls into `sqlrite-ask` from a Tauri command; the command lives in `desktop/src-tauri/`. Schema introspection runs server-side; HTTP call also server-side (so the API key stays in the app process, not the webview).
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.
@@ -72,19 +72,27 @@ GitHub Releases by product ("show me every Python release").
72
72
  |-----------------|------------------------|--------------------------------------------------|
73
73
  | Rust engine | `sqlrite-vX.Y.Z` | crates.io + GitHub Release |
74
74
  | C FFI shim | `sqlrite-ffi-vX.Y.Z` | GitHub Release (per-platform tarballs) |
75
+ | `sqlrite-ask` | `sqlrite-ask-vX.Y.Z` | crates.io + GitHub Release |
75
76
  | Python SDK | `sqlrite-py-vX.Y.Z` | PyPI + GitHub Release |
76
77
  | Node.js SDK | `sqlrite-node-vX.Y.Z` | npm (`@joaoh82/sqlrite`) + GitHub Release |
77
78
  | Go SDK | `sdk/go/vX.Y.Z` | Git tag (no registry) + GitHub Release assets |
78
79
  | WASM | `sqlrite-wasm-vX.Y.Z` | npm (`@joaoh82/sqlrite-wasm`) + GitHub Release |
79
80
  | Desktop app | `sqlrite-desktop-vX.Y.Z` | GitHub Release (unsigned installers) |
80
- | **Meta** | `vX.Y.Z` | GitHub Release (links to the other seven; acts as the "this was release 0.2.0" anchor) |
81
+ | **Meta** | `vX.Y.Z` | GitHub Release (links to the other eight; acts as the "this was release 0.2.0" anchor) |
81
82
 
82
- All eight tags point at the same commit — the merge commit of the
83
+ All nine tags point at the same commit — the merge commit of the
83
84
  release PR. The meta tag is the umbrella release users can link to
84
- in announcements; the seven per-product tags are for tooling
85
+ in announcements; the eight per-product tags are for tooling
85
86
  (crates.io, Go module proxy, npm dist-tags, etc.) that expects a
86
87
  specific format.
87
88
 
89
+ > **`sqlrite-ask` joined the lockstep wave in v0.1.17 (Phase 7g.1).** Gets
90
+ > its own tag and crates.io publish but ships in lockstep with everything
91
+ > else — same version every wave. `publish-ask` runs after `publish-crate`
92
+ > in `release.yml` because crates.io rejects publishes whose path-deps
93
+ > haven't yet resolved at the same version. `sqlrite-mcp` (Phase 7h) will
94
+ > add a ninth product line on the same pattern.
95
+
88
96
  ## Version bumping: exact file list
89
97
 
90
98
  The release workflow edits these files in a single commit (the
@@ -95,6 +103,7 @@ matching new value:
95
103
  |------------------------------------------|---------------------------------------------|
96
104
  | `Cargo.toml` (root) | `[package].version` |
97
105
  | `sqlrite-ffi/Cargo.toml` | `[package].version` |
106
+ | `sqlrite-ask/Cargo.toml` | `[package].version` |
98
107
  | `sdk/python/Cargo.toml` | `[package].version` |
99
108
  | `sdk/python/pyproject.toml` | `[project].version` |
100
109
  | `sdk/nodejs/Cargo.toml` | `[package].version` |
@@ -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). Thin per-product adapters in 7g.2-7g.8 cover REPL, desktop, Python, Node.js, Go, WASM (JS-callback shape per Q9), and the MCP `ask` tool.
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()` free function + `ConnectionAskExt` trait + `AskConfig::from_env()`, sync `ureq` POST to `/v1/messages`, schema-aware prompt with prompt-caching on the schema dump (Sonnet 4.6 default; configurable). Thin per-product adapters in 7g.2-7g.8 cover REPL, desktop, 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.16"
7
+ version = "0.1.17"
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" }
@@ -5,11 +5,12 @@
5
5
  # Usage:
6
6
  # scripts/bump-version.sh 0.2.0
7
7
  #
8
- # Rewrites the version field in every manifest that carries one (seven
9
- # Cargo.toml / pyproject.toml files, plus three JSON manifests — ten
10
- # files total). Then you run `cargo build` yourself to refresh
11
- # Cargo.lock. Idempotent: running twice with the same version is a
12
- # no-op; running twice with different versions lands on the second.
8
+ # Rewrites the version field in every manifest that carries one
9
+ # (eight Cargo.toml / pyproject.toml files, plus three JSON manifests
10
+ # — eleven files total). Then you run `cargo build` yourself to
11
+ # refresh Cargo.lock. Idempotent: running twice with the same version
12
+ # is a no-op; running twice with different versions lands on the
13
+ # second.
13
14
  #
14
15
  # Used by:
15
16
  # - `release-pr.yml` GitHub Actions workflow as the version-bump
@@ -67,6 +68,7 @@ cd "$REPO_ROOT"
67
68
  TOML_FILES=(
68
69
  "Cargo.toml"
69
70
  "sqlrite-ffi/Cargo.toml"
71
+ "sqlrite-ask/Cargo.toml"
70
72
  "sdk/python/Cargo.toml"
71
73
  "sdk/python/pyproject.toml"
72
74
  "sdk/nodejs/Cargo.toml"
@@ -82,6 +82,64 @@ defer ro.Close()
82
82
  // Reads work; any Exec throws with "read-only" in the message.
83
83
  ```
84
84
 
85
+ ### Vector columns + KNN (Phase 7a–7d)
86
+
87
+ `VECTOR(N)` storage class plus `vec_distance_l2` / `vec_distance_cosine` / `vec_distance_dot` distance functions. Vector literals are JSON-style bracket arrays `[0.1, 0.2, ...]`. Today the Go side bridges them as text — `database/sql` doesn't yet have a typed accessor for vectors:
88
+
89
+ ```go
90
+ db.Exec(`CREATE TABLE docs (id INTEGER PRIMARY KEY, embedding VECTOR(384))`)
91
+ db.Exec(`INSERT INTO docs (id, embedding) VALUES (1, [0.1, 0.2, ..., 0.0])`)
92
+
93
+ rows, _ := db.Query(`
94
+ SELECT id FROM docs
95
+ ORDER BY vec_distance_l2(embedding, [0.1, 0.2, ..., 0.0])
96
+ LIMIT 10
97
+ `)
98
+ defer rows.Close()
99
+ for rows.Next() {
100
+ var id int64
101
+ rows.Scan(&id)
102
+ }
103
+ ```
104
+
105
+ For larger collections, build an HNSW index — the executor uses it automatically:
106
+
107
+ ```go
108
+ db.Exec(`CREATE INDEX idx_docs_emb ON docs USING hnsw (embedding)`)
109
+ ```
110
+
111
+ ### JSON columns (Phase 7e)
112
+
113
+ `JSON` (and `JSONB` as an alias) columns are validated at INSERT/UPDATE time. Read with `json_extract` / `json_type` / `json_array_length` / `json_object_keys`. Path subset: `$`, `.key`, `[N]`, chained.
114
+
115
+ ```go
116
+ db.Exec(`CREATE TABLE events (id INTEGER PRIMARY KEY, payload JSON)`)
117
+ db.Exec(`INSERT INTO events (payload) VALUES ('{"user": {"name": "alice"}, "score": 42}')`)
118
+
119
+ var name string
120
+ db.QueryRow(`SELECT json_extract(payload, '$.user.name') FROM events`).Scan(&name)
121
+ fmt.Println(name) // alice
122
+ ```
123
+
124
+ > `json_object_keys` returns a JSON-array text rather than a table-valued result (set-returning functions aren't supported yet).
125
+
126
+ ### Natural-language → SQL (Phase 7g — *coming soon*)
127
+
128
+ The Phase 7g.2-7g.8 wave adds `sqlrite.Ask(db, ...)` / `sqlrite.AskRun(db, ...)` that wrap the new [`sqlrite-ask`](https://crates.io/crates/sqlrite-ask) Rust crate through cgo. Today it's available only from Rust; the Go wrapper lands in 7g.6 and will look like:
129
+
130
+ ```go
131
+ // 7g.6 preview — not yet released
132
+ import "github.com/joaoh82/rust_sqlite/sdk/go"
133
+
134
+ cfg := sqlrite.AskConfigFromEnv() // SQLRITE_LLM_API_KEY etc.
135
+ resp, err := sqlrite.Ask(db, "How many users are over 30?", cfg)
136
+ fmt.Println(resp.SQL) // "SELECT COUNT(*) FROM users WHERE age > 30"
137
+ fmt.Println(resp.Explanation) // "Counts users over the age threshold."
138
+
139
+ // Convenience:
140
+ rows, _ := sqlrite.AskRun(db, "How many users are over 30?", cfg)
141
+ ```
142
+
85
143
  ## API surface
86
144
 
87
145
  | Symbol | Purpose |
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sqlrite-python"
3
- version = "0.1.16"
3
+ version = "0.1.17"
4
4
  authors = ["Joao Henrique Machado Silva <joaoh82@gmail.com>"]
5
5
  edition = "2024"
6
6
  rust-version = "1.85"
@@ -62,6 +62,64 @@ conn = sqlrite.connect_read_only("foo.sqlrite")
62
62
  # connections on the same file coexist (shared OS lock).
63
63
  ```
64
64
 
65
+ ### Vector columns + KNN (Phase 7a–7d)
66
+
67
+ The engine ships with a fixed-dimension `VECTOR(N)` storage class and three distance functions (`vec_distance_l2`, `vec_distance_cosine`, `vec_distance_dot`). Plain `cursor.execute(...)` is all you need from Python — values come back as Python lists of floats.
68
+
69
+ ```python
70
+ cur.execute("CREATE TABLE docs (id INTEGER PRIMARY KEY, embedding VECTOR(384))")
71
+ cur.execute("INSERT INTO docs (id, embedding) VALUES (1, [0.1, 0.2, ..., 0.0])") # 384 floats
72
+ cur.execute("""
73
+ SELECT id FROM docs
74
+ ORDER BY vec_distance_l2(embedding, [0.1, 0.2, ..., 0.0])
75
+ LIMIT 10
76
+ """)
77
+ for row in cur:
78
+ print(row)
79
+ ```
80
+
81
+ For larger collections, build an HNSW index — the executor will use it automatically when the `WHERE`/`ORDER BY` shape matches:
82
+
83
+ ```python
84
+ cur.execute("CREATE INDEX idx_docs_emb ON docs USING hnsw (embedding)")
85
+ ```
86
+
87
+ ### JSON columns (Phase 7e)
88
+
89
+ `JSON` (and `JSONB` as an alias) columns store text, validated at INSERT/UPDATE time. Read with `json_extract` / `json_type` / `json_array_length` / `json_object_keys`. Path subset: `$`, `.key`, `[N]`, chained.
90
+
91
+ ```python
92
+ cur.execute("CREATE TABLE events (id INTEGER PRIMARY KEY, payload JSON)")
93
+ cur.execute(
94
+ "INSERT INTO events (payload) VALUES "
95
+ "('{\"user\": {\"name\": \"alice\"}, \"score\": 42}')"
96
+ )
97
+ cur.execute(
98
+ "SELECT json_extract(payload, '$.user.name'), json_type(payload, '$.score') FROM events"
99
+ )
100
+ print(cur.fetchall()) # [('alice', 'integer')]
101
+ ```
102
+
103
+ > `json_object_keys` returns a JSON-array text rather than a table-valued result (set-returning functions aren't supported yet).
104
+
105
+ ### Natural-language → SQL (Phase 7g — *coming soon*)
106
+
107
+ The Phase 7g.2-7g.8 wave adds a Python-native `conn.ask()` that wraps the new `sqlrite-ask` Rust crate via PyO3. Today it's available only from Rust ([`sqlrite-ask` on crates.io](https://crates.io/crates/sqlrite-ask)); the Python wrapper lands in 7g.4 and will look like:
108
+
109
+ ```python
110
+ # 7g.4 preview — not yet released
111
+ import sqlrite
112
+
113
+ conn = sqlrite.connect("foo.sqlrite")
114
+ cfg = sqlrite.AskConfig.from_env() # SQLRITE_LLM_API_KEY etc.
115
+ resp = conn.ask("How many users are over 30?", cfg)
116
+ print(resp.sql) # "SELECT COUNT(*) FROM users WHERE age > 30"
117
+ print(resp.explanation) # "Counts users over the age threshold."
118
+
119
+ # Convenience:
120
+ rows = conn.ask_run("How many users are over 30?", cfg).fetchall()
121
+ ```
122
+
65
123
  ## API surface
66
124
 
67
125
  | Function / Method | Purpose |
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