dirsql 0.3.72__tar.gz → 0.3.73__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 (136) hide show
  1. {dirsql-0.3.72 → dirsql-0.3.73}/Cargo.lock +1 -1
  2. {dirsql-0.3.72 → dirsql-0.3.73}/PKG-INFO +1 -1
  3. {dirsql-0.3.72/packages/rust → dirsql-0.3.73}/docs/howto/columns-from-paths.md +2 -8
  4. {dirsql-0.3.72/packages/python → dirsql-0.3.73}/docs/howto/define-tables.md +2 -16
  5. {dirsql-0.3.72/packages/python → dirsql-0.3.73}/docs/howto/extract-from-contents.md +2 -8
  6. {dirsql-0.3.72/packages/python → dirsql-0.3.73}/docs/howto/load-extension.md +2 -5
  7. {dirsql-0.3.72/packages/python → dirsql-0.3.73}/docs/howto/search-by-meaning.md +9 -17
  8. {dirsql-0.3.72/packages/rust → dirsql-0.3.73}/docs/howto/skip-files.md +1 -5
  9. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/Cargo.toml +1 -1
  10. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/howto/columns-from-paths.md +2 -8
  11. {dirsql-0.3.72/packages/rust → dirsql-0.3.73/packages/python}/docs/howto/define-tables.md +2 -16
  12. {dirsql-0.3.72/packages/rust → dirsql-0.3.73/packages/python}/docs/howto/extract-from-contents.md +2 -8
  13. {dirsql-0.3.72/packages/rust → dirsql-0.3.73/packages/python}/docs/howto/load-extension.md +2 -5
  14. {dirsql-0.3.72/packages/rust → dirsql-0.3.73/packages/python}/docs/howto/search-by-meaning.md +9 -17
  15. {dirsql-0.3.72 → dirsql-0.3.73/packages/python}/docs/howto/skip-files.md +1 -5
  16. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/e2e-attestation.json +2 -2
  17. {dirsql-0.3.72 → dirsql-0.3.73/packages/rust}/docs/howto/columns-from-paths.md +2 -8
  18. {dirsql-0.3.72 → dirsql-0.3.73/packages/rust}/docs/howto/define-tables.md +2 -16
  19. {dirsql-0.3.72 → dirsql-0.3.73/packages/rust}/docs/howto/extract-from-contents.md +2 -8
  20. {dirsql-0.3.72 → dirsql-0.3.73/packages/rust}/docs/howto/load-extension.md +2 -5
  21. {dirsql-0.3.72 → dirsql-0.3.73/packages/rust}/docs/howto/search-by-meaning.md +9 -17
  22. {dirsql-0.3.72/packages/python → dirsql-0.3.73/packages/rust}/docs/howto/skip-files.md +1 -5
  23. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/cli/execute.rs +14 -1
  24. {dirsql-0.3.72 → dirsql-0.3.73}/Cargo.toml +0 -0
  25. {dirsql-0.3.72 → dirsql-0.3.73}/README.md +0 -0
  26. {dirsql-0.3.72 → dirsql-0.3.73}/dirsql/__init__.py +0 -0
  27. {dirsql-0.3.72 → dirsql-0.3.73}/dirsql/_async.py +0 -0
  28. {dirsql-0.3.72 → dirsql-0.3.73}/dirsql/_dirsql.pyi +0 -0
  29. {dirsql-0.3.72 → dirsql-0.3.73}/dirsql/cli/__init__.py +0 -0
  30. {dirsql-0.3.72 → dirsql-0.3.73}/dirsql/cli/binary_path.py +0 -0
  31. {dirsql-0.3.72 → dirsql-0.3.73}/dirsql/cli/is_windows.py +0 -0
  32. {dirsql-0.3.72 → dirsql-0.3.73}/dirsql/cli/main.py +0 -0
  33. {dirsql-0.3.72 → dirsql-0.3.73}/dirsql/cli/resolve_config_extensions.py +0 -0
  34. {dirsql-0.3.72 → dirsql-0.3.73}/dirsql/py.typed +0 -0
  35. {dirsql-0.3.72 → dirsql-0.3.73}/dirsql/resolve_config_extensions.py +0 -0
  36. {dirsql-0.3.72 → dirsql-0.3.73}/dirsql/resolve_extension.py +0 -0
  37. {dirsql-0.3.72 → dirsql-0.3.73}/docs/.claude/CLAUDE.md +0 -0
  38. {dirsql-0.3.72 → dirsql-0.3.73}/docs/.vitepress/config.ts +0 -0
  39. {dirsql-0.3.72 → dirsql-0.3.73}/docs/.vitepress/theme/index.ts +0 -0
  40. {dirsql-0.3.72 → dirsql-0.3.73}/docs/.vitepress/theme/lang.ts +0 -0
  41. {dirsql-0.3.72 → dirsql-0.3.73}/docs/AGENTS.md +0 -0
  42. {dirsql-0.3.72 → dirsql-0.3.73}/docs/explanation.md +0 -0
  43. {dirsql-0.3.72 → dirsql-0.3.73}/docs/getting-started.md +0 -0
  44. {dirsql-0.3.72 → dirsql-0.3.73}/docs/howto/embed.md +0 -0
  45. {dirsql-0.3.72 → dirsql-0.3.73}/docs/howto/persist.md +0 -0
  46. {dirsql-0.3.72 → dirsql-0.3.73}/docs/howto/react-to-changes.md +0 -0
  47. {dirsql-0.3.72 → dirsql-0.3.73}/docs/index.md +0 -0
  48. {dirsql-0.3.72 → dirsql-0.3.73}/docs/migrations.md +0 -0
  49. {dirsql-0.3.72 → dirsql-0.3.73}/docs/package.json +0 -0
  50. {dirsql-0.3.72 → dirsql-0.3.73}/docs/playwright.config.ts +0 -0
  51. {dirsql-0.3.72 → dirsql-0.3.73}/docs/pnpm-lock.yaml +0 -0
  52. {dirsql-0.3.72 → dirsql-0.3.73}/docs/pnpm-workspace.yaml +0 -0
  53. {dirsql-0.3.72 → dirsql-0.3.73}/docs/reference/cli.md +0 -0
  54. {dirsql-0.3.72 → dirsql-0.3.73}/docs/reference/columns.md +0 -0
  55. {dirsql-0.3.72 → dirsql-0.3.73}/docs/reference/config.md +0 -0
  56. {dirsql-0.3.72 → dirsql-0.3.73}/docs/reference/hooks.md +0 -0
  57. {dirsql-0.3.72 → dirsql-0.3.73}/docs/reference/http-api.md +0 -0
  58. {dirsql-0.3.72 → dirsql-0.3.73}/docs/reference/sdk.md +0 -0
  59. {dirsql-0.3.72 → dirsql-0.3.73}/docs/tests/integration/home.spec.ts +0 -0
  60. {dirsql-0.3.72 → dirsql-0.3.73}/docs/tests/integration/language-flag.spec.ts +0 -0
  61. {dirsql-0.3.72 → dirsql-0.3.73}/docs/tests/integration/sidebar.spec.ts +0 -0
  62. {dirsql-0.3.72 → dirsql-0.3.73}/docs/tests/unit/config.test.ts +0 -0
  63. {dirsql-0.3.72 → dirsql-0.3.73}/docs/tests/unit/lang.test.ts +0 -0
  64. {dirsql-0.3.72 → dirsql-0.3.73}/docs/vitest.config.ts +0 -0
  65. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/README.md +0 -0
  66. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/conftest.py +0 -0
  67. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/.claude/CLAUDE.md +0 -0
  68. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/.vitepress/config.ts +0 -0
  69. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  70. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  71. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/AGENTS.md +0 -0
  72. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/explanation.md +0 -0
  73. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/getting-started.md +0 -0
  74. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/howto/embed.md +0 -0
  75. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/howto/persist.md +0 -0
  76. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/howto/react-to-changes.md +0 -0
  77. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/index.md +0 -0
  78. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/migrations.md +0 -0
  79. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/package.json +0 -0
  80. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/playwright.config.ts +0 -0
  81. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/pnpm-lock.yaml +0 -0
  82. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/pnpm-workspace.yaml +0 -0
  83. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/reference/cli.md +0 -0
  84. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/reference/columns.md +0 -0
  85. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/reference/config.md +0 -0
  86. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/reference/hooks.md +0 -0
  87. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/reference/http-api.md +0 -0
  88. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/reference/sdk.md +0 -0
  89. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/tests/integration/home.spec.ts +0 -0
  90. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/tests/integration/language-flag.spec.ts +0 -0
  91. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/tests/integration/sidebar.spec.ts +0 -0
  92. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/tests/unit/config.test.ts +0 -0
  93. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/tests/unit/lang.test.ts +0 -0
  94. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/docs/vitest.config.ts +0 -0
  95. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/src/lib.rs +0 -0
  96. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/tests/__init__.py +0 -0
  97. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/tests/binding/__init__.py +0 -0
  98. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/tests/conftest.py +0 -0
  99. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/tests/e2e/__init__.py +0 -0
  100. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/tests/integration/__init__.py +0 -0
  101. {dirsql-0.3.72 → dirsql-0.3.73}/packages/python/tests/smoke/__init__.py +0 -0
  102. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/Cargo.toml +0 -0
  103. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/README.md +0 -0
  104. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/benches/db_bench.rs +0 -0
  105. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/benches/differ_bench.rs +0 -0
  106. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/benches/matcher_bench.rs +0 -0
  107. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/benches/scanner_bench.rs +0 -0
  108. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/docs/explanation.md +0 -0
  109. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/docs/getting-started.md +0 -0
  110. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/docs/howto/embed.md +0 -0
  111. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/docs/howto/persist.md +0 -0
  112. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/docs/howto/react-to-changes.md +0 -0
  113. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/docs/index.md +0 -0
  114. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/docs/migrations.md +0 -0
  115. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/docs/reference/cli.md +0 -0
  116. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/docs/reference/columns.md +0 -0
  117. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/docs/reference/config.md +0 -0
  118. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/docs/reference/hooks.md +0 -0
  119. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/docs/reference/http-api.md +0 -0
  120. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/docs/reference/sdk.md +0 -0
  121. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/bin/dirsql.rs +0 -0
  122. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/cli/init.rs +0 -0
  123. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/cli/mod.rs +0 -0
  124. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/cli/router.rs +0 -0
  125. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/cli/serialize.rs +0 -0
  126. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/cli/server.rs +0 -0
  127. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/command.rs +0 -0
  128. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/config.rs +0 -0
  129. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/db.rs +0 -0
  130. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/differ.rs +0 -0
  131. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/lib.rs +0 -0
  132. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/matcher.rs +0 -0
  133. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/persist.rs +0 -0
  134. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/scanner.rs +0 -0
  135. {dirsql-0.3.72 → dirsql-0.3.73}/packages/rust/src/watcher.rs +0 -0
  136. {dirsql-0.3.72 → dirsql-0.3.73}/pyproject.toml +0 -0
@@ -500,7 +500,7 @@ dependencies = [
500
500
 
501
501
  [[package]]
502
502
  name = "dirsql-py-ext"
503
- version = "0.3.72"
503
+ version = "0.3.73"
504
504
  dependencies = [
505
505
  "dirsql",
506
506
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dirsql
3
- Version: 0.3.72
3
+ Version: 0.3.73
4
4
  Summary: Ephemeral SQL index over a local directory
5
5
  Keywords: sql,filesystem,directory,sqlite,index
6
6
  Author: Kevin Scott
@@ -29,12 +29,8 @@ within one path segment) are in
29
29
 
30
30
  ## 2. Query the captured columns
31
31
 
32
- Start the server (`npx dirsql` / `uvx dirsql`) and query:
33
-
34
32
  ```bash
35
- curl -s http://localhost:7117/query \
36
- -H 'content-type: application/json' \
37
- -d '{"sql":"SELECT year, month, _basename FROM photos ORDER BY year, month"}'
33
+ dirsql query "SELECT year, month, _basename FROM photos ORDER BY year, month"
38
34
  ```
39
35
 
40
36
  ```json
@@ -44,9 +40,7 @@ curl -s http://localhost:7117/query \
44
40
  Captures are real SQL columns, so aggregation works:
45
41
 
46
42
  ```bash
47
- curl -s http://localhost:7117/query \
48
- -H 'content-type: application/json' \
49
- -d '{"sql":"SELECT year, COUNT(*) AS photos FROM photos GROUP BY year"}'
43
+ dirsql query "SELECT year, COUNT(*) AS photos FROM photos GROUP BY year"
50
44
  ```
51
45
 
52
46
  ```json
@@ -24,26 +24,12 @@ glob = "posts/**/*.md"
24
24
  filesystem facts `dirsql` computes for every file. Facts are opt-in by
25
25
  DDL: only the ones you declare become columns.
26
26
 
27
- ## 2. Start the server and query
28
-
29
- ::: code-group
30
-
31
- ```bash [npm]
32
- npx dirsql
33
- ```
34
-
35
- ```bash [PyPI]
36
- uvx dirsql
37
- ```
38
-
39
- :::
27
+ ## 2. Query the table
40
28
 
41
29
  Each matched file is one row:
42
30
 
43
31
  ```bash
44
- curl -s http://localhost:7117/query \
45
- -H 'content-type: application/json' \
46
- -d '{"sql":"SELECT _path, _size FROM posts ORDER BY _path"}'
32
+ dirsql query "SELECT _path, _size FROM posts ORDER BY _path"
47
33
  ```
48
34
 
49
35
  ```json
@@ -31,12 +31,8 @@ by every hook.
31
31
 
32
32
  ## 2. Query the extracted columns
33
33
 
34
- Start the server (`npx dirsql` / `uvx dirsql`) and query:
35
-
36
34
  ```bash
37
- curl -s http://localhost:7117/query \
38
- -H 'content-type: application/json' \
39
- -d '{"sql":"SELECT title, author, year, _path FROM books ORDER BY year"}'
35
+ dirsql query "SELECT title, author, year, _path FROM books ORDER BY year"
40
36
  ```
41
37
 
42
38
  ```json
@@ -61,9 +57,7 @@ on-file = "jq -c -s '.' {path}"
61
57
  ```
62
58
 
63
59
  ```bash
64
- curl -s http://localhost:7117/query \
65
- -H 'content-type: application/json' \
66
- -d '{"sql":"SELECT event, user FROM events"}'
60
+ dirsql query "SELECT event, user FROM events"
67
61
  ```
68
62
 
69
63
  ```json
@@ -23,13 +23,10 @@ overrides the init symbol when it doesn't match the filename-derived
23
23
  default — `sqlite-vec` is exactly such a case
24
24
  ([reference](../reference/config.md#dirsql-extension)).
25
25
 
26
- Start the server (`npx dirsql` / `uvx dirsql`) and the extension's
27
- functions are callable:
26
+ The extension's functions are callable:
28
27
 
29
28
  ```bash
30
- curl -s http://localhost:7117/query \
31
- -H 'content-type: application/json' \
32
- -d '{"sql":"SELECT vec_version() AS vec_version"}'
29
+ dirsql query "SELECT vec_version() AS vec_version"
33
30
  ```
34
31
 
35
32
  ```json
@@ -99,20 +99,14 @@ installed `sqlite_vec` module to its bundled loadable. Naming rules per
99
99
  runtime — and the literal-path alternative that works everywhere — are in
100
100
  [Load a SQLite extension](./load-extension.md).
101
101
 
102
- ## 3. Start the server and ask questions
102
+ ## 3. Ask questions
103
103
 
104
- Launch with `sqlite-vec` available to the launcher's environment:
104
+ Run with `sqlite-vec` available to the launcher's environment. The initial
105
+ scan runs `embed.py` once per note, then the query argument goes straight to
106
+ `pre-query`, exactly as a `POST /query` body would:
105
107
 
106
108
  ```bash
107
- uvx --with sqlite-vec dirsql
108
- ```
109
-
110
- The initial scan runs `embed.py` once per note. Then ask:
111
-
112
- ```bash
113
- curl -s http://localhost:7117/query \
114
- -H 'content-type: application/json' \
115
- -d '{"q": "how do I cook pasta?"}'
109
+ uvx --with sqlite-vec dirsql query '{"q": "how do I cook pasta?"}'
116
110
  ```
117
111
 
118
112
  ```json
@@ -120,9 +114,7 @@ curl -s http://localhost:7117/query \
120
114
  ```
121
115
 
122
116
  ```bash
123
- curl -s http://localhost:7117/query \
124
- -H 'content-type: application/json' \
125
- -d '{"q": "reviewing code on github"}'
117
+ uvx --with sqlite-vec dirsql query '{"q": "reviewing code on github"}'
126
118
  ```
127
119
 
128
120
  ```json
@@ -133,9 +125,9 @@ Neither question shares a keyword with its top note — "cook" appears
133
125
  nowhere in `pasta.md`, "github" nowhere in `branches.md`. The distance
134
126
  ranking is doing the work.
135
127
 
136
- Because `pre-query` is set, the request body is *not* the usual
137
- `{"sql": …}` — the raw body goes to your script, which decides what SQL
138
- runs ([hook interactions](../reference/http-api.md#hook-interactions)).
128
+ Because `pre-query` is set, the query argument is *not* the usual
129
+ `{"sql": …}` — it goes to your script as-is, which decides what SQL runs
130
+ ([hook interactions](../reference/http-api.md#hook-interactions)).
139
131
 
140
132
  ## Recomputing vs. caching
141
133
 
@@ -31,12 +31,8 @@ ignored file never reaches any table — even one whose glob would match it.
31
31
 
32
32
  ## 2. Confirm what made it in
33
33
 
34
- Start the server (`npx dirsql` / `uvx dirsql`) and check:
35
-
36
34
  ```bash
37
- curl -s http://localhost:7117/query \
38
- -H 'content-type: application/json' \
39
- -d '{"sql":"SELECT _path FROM notes ORDER BY _path"}'
35
+ dirsql query "SELECT _path FROM notes ORDER BY _path"
40
36
  ```
41
37
 
42
38
  ```json
@@ -4,7 +4,7 @@ name = "dirsql-py-ext"
4
4
  # pypi/maturin handler can rewrite it via `write-version` before
5
5
  # `maturin build`. `pyproject.toml` declares `dynamic = ["version"]`
6
6
  # and maturin reads this field. Mirrors `packages/rust/Cargo.toml`.
7
- version = "0.3.72"
7
+ version = "0.3.73"
8
8
  edition.workspace = true
9
9
  publish = false
10
10
  readme = "README.md"
@@ -29,12 +29,8 @@ within one path segment) are in
29
29
 
30
30
  ## 2. Query the captured columns
31
31
 
32
- Start the server (`npx dirsql` / `uvx dirsql`) and query:
33
-
34
32
  ```bash
35
- curl -s http://localhost:7117/query \
36
- -H 'content-type: application/json' \
37
- -d '{"sql":"SELECT year, month, _basename FROM photos ORDER BY year, month"}'
33
+ dirsql query "SELECT year, month, _basename FROM photos ORDER BY year, month"
38
34
  ```
39
35
 
40
36
  ```json
@@ -44,9 +40,7 @@ curl -s http://localhost:7117/query \
44
40
  Captures are real SQL columns, so aggregation works:
45
41
 
46
42
  ```bash
47
- curl -s http://localhost:7117/query \
48
- -H 'content-type: application/json' \
49
- -d '{"sql":"SELECT year, COUNT(*) AS photos FROM photos GROUP BY year"}'
43
+ dirsql query "SELECT year, COUNT(*) AS photos FROM photos GROUP BY year"
50
44
  ```
51
45
 
52
46
  ```json
@@ -24,26 +24,12 @@ glob = "posts/**/*.md"
24
24
  filesystem facts `dirsql` computes for every file. Facts are opt-in by
25
25
  DDL: only the ones you declare become columns.
26
26
 
27
- ## 2. Start the server and query
28
-
29
- ::: code-group
30
-
31
- ```bash [npm]
32
- npx dirsql
33
- ```
34
-
35
- ```bash [PyPI]
36
- uvx dirsql
37
- ```
38
-
39
- :::
27
+ ## 2. Query the table
40
28
 
41
29
  Each matched file is one row:
42
30
 
43
31
  ```bash
44
- curl -s http://localhost:7117/query \
45
- -H 'content-type: application/json' \
46
- -d '{"sql":"SELECT _path, _size FROM posts ORDER BY _path"}'
32
+ dirsql query "SELECT _path, _size FROM posts ORDER BY _path"
47
33
  ```
48
34
 
49
35
  ```json
@@ -31,12 +31,8 @@ by every hook.
31
31
 
32
32
  ## 2. Query the extracted columns
33
33
 
34
- Start the server (`npx dirsql` / `uvx dirsql`) and query:
35
-
36
34
  ```bash
37
- curl -s http://localhost:7117/query \
38
- -H 'content-type: application/json' \
39
- -d '{"sql":"SELECT title, author, year, _path FROM books ORDER BY year"}'
35
+ dirsql query "SELECT title, author, year, _path FROM books ORDER BY year"
40
36
  ```
41
37
 
42
38
  ```json
@@ -61,9 +57,7 @@ on-file = "jq -c -s '.' {path}"
61
57
  ```
62
58
 
63
59
  ```bash
64
- curl -s http://localhost:7117/query \
65
- -H 'content-type: application/json' \
66
- -d '{"sql":"SELECT event, user FROM events"}'
60
+ dirsql query "SELECT event, user FROM events"
67
61
  ```
68
62
 
69
63
  ```json
@@ -23,13 +23,10 @@ overrides the init symbol when it doesn't match the filename-derived
23
23
  default — `sqlite-vec` is exactly such a case
24
24
  ([reference](../reference/config.md#dirsql-extension)).
25
25
 
26
- Start the server (`npx dirsql` / `uvx dirsql`) and the extension's
27
- functions are callable:
26
+ The extension's functions are callable:
28
27
 
29
28
  ```bash
30
- curl -s http://localhost:7117/query \
31
- -H 'content-type: application/json' \
32
- -d '{"sql":"SELECT vec_version() AS vec_version"}'
29
+ dirsql query "SELECT vec_version() AS vec_version"
33
30
  ```
34
31
 
35
32
  ```json
@@ -99,20 +99,14 @@ installed `sqlite_vec` module to its bundled loadable. Naming rules per
99
99
  runtime — and the literal-path alternative that works everywhere — are in
100
100
  [Load a SQLite extension](./load-extension.md).
101
101
 
102
- ## 3. Start the server and ask questions
102
+ ## 3. Ask questions
103
103
 
104
- Launch with `sqlite-vec` available to the launcher's environment:
104
+ Run with `sqlite-vec` available to the launcher's environment. The initial
105
+ scan runs `embed.py` once per note, then the query argument goes straight to
106
+ `pre-query`, exactly as a `POST /query` body would:
105
107
 
106
108
  ```bash
107
- uvx --with sqlite-vec dirsql
108
- ```
109
-
110
- The initial scan runs `embed.py` once per note. Then ask:
111
-
112
- ```bash
113
- curl -s http://localhost:7117/query \
114
- -H 'content-type: application/json' \
115
- -d '{"q": "how do I cook pasta?"}'
109
+ uvx --with sqlite-vec dirsql query '{"q": "how do I cook pasta?"}'
116
110
  ```
117
111
 
118
112
  ```json
@@ -120,9 +114,7 @@ curl -s http://localhost:7117/query \
120
114
  ```
121
115
 
122
116
  ```bash
123
- curl -s http://localhost:7117/query \
124
- -H 'content-type: application/json' \
125
- -d '{"q": "reviewing code on github"}'
117
+ uvx --with sqlite-vec dirsql query '{"q": "reviewing code on github"}'
126
118
  ```
127
119
 
128
120
  ```json
@@ -133,9 +125,9 @@ Neither question shares a keyword with its top note — "cook" appears
133
125
  nowhere in `pasta.md`, "github" nowhere in `branches.md`. The distance
134
126
  ranking is doing the work.
135
127
 
136
- Because `pre-query` is set, the request body is *not* the usual
137
- `{"sql": …}` — the raw body goes to your script, which decides what SQL
138
- runs ([hook interactions](../reference/http-api.md#hook-interactions)).
128
+ Because `pre-query` is set, the query argument is *not* the usual
129
+ `{"sql": …}` — it goes to your script as-is, which decides what SQL runs
130
+ ([hook interactions](../reference/http-api.md#hook-interactions)).
139
131
 
140
132
  ## Recomputing vs. caching
141
133
 
@@ -31,12 +31,8 @@ ignored file never reaches any table — even one whose glob would match it.
31
31
 
32
32
  ## 2. Confirm what made it in
33
33
 
34
- Start the server (`npx dirsql` / `uvx dirsql`) and check:
35
-
36
34
  ```bash
37
- curl -s http://localhost:7117/query \
38
- -H 'content-type: application/json' \
39
- -d '{"sql":"SELECT _path FROM notes ORDER BY _path"}'
35
+ dirsql query "SELECT _path FROM notes ORDER BY _path"
40
36
  ```
41
37
 
42
38
  ```json
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "command": "uv run python -m pytest tests/e2e/ -x -q",
3
- "ran_at": 1783420501,
3
+ "ran_at": 1783427443,
4
4
  "exit_code": 0,
5
- "commit": "fe9d09208be0b3c6084d9b916a41403d5822d096"
5
+ "commit": "16fc390f62d2f4f9d607eb28fc2adc8ee1d6ea0a"
6
6
  }
@@ -29,12 +29,8 @@ within one path segment) are in
29
29
 
30
30
  ## 2. Query the captured columns
31
31
 
32
- Start the server (`npx dirsql` / `uvx dirsql`) and query:
33
-
34
32
  ```bash
35
- curl -s http://localhost:7117/query \
36
- -H 'content-type: application/json' \
37
- -d '{"sql":"SELECT year, month, _basename FROM photos ORDER BY year, month"}'
33
+ dirsql query "SELECT year, month, _basename FROM photos ORDER BY year, month"
38
34
  ```
39
35
 
40
36
  ```json
@@ -44,9 +40,7 @@ curl -s http://localhost:7117/query \
44
40
  Captures are real SQL columns, so aggregation works:
45
41
 
46
42
  ```bash
47
- curl -s http://localhost:7117/query \
48
- -H 'content-type: application/json' \
49
- -d '{"sql":"SELECT year, COUNT(*) AS photos FROM photos GROUP BY year"}'
43
+ dirsql query "SELECT year, COUNT(*) AS photos FROM photos GROUP BY year"
50
44
  ```
51
45
 
52
46
  ```json
@@ -24,26 +24,12 @@ glob = "posts/**/*.md"
24
24
  filesystem facts `dirsql` computes for every file. Facts are opt-in by
25
25
  DDL: only the ones you declare become columns.
26
26
 
27
- ## 2. Start the server and query
28
-
29
- ::: code-group
30
-
31
- ```bash [npm]
32
- npx dirsql
33
- ```
34
-
35
- ```bash [PyPI]
36
- uvx dirsql
37
- ```
38
-
39
- :::
27
+ ## 2. Query the table
40
28
 
41
29
  Each matched file is one row:
42
30
 
43
31
  ```bash
44
- curl -s http://localhost:7117/query \
45
- -H 'content-type: application/json' \
46
- -d '{"sql":"SELECT _path, _size FROM posts ORDER BY _path"}'
32
+ dirsql query "SELECT _path, _size FROM posts ORDER BY _path"
47
33
  ```
48
34
 
49
35
  ```json
@@ -31,12 +31,8 @@ by every hook.
31
31
 
32
32
  ## 2. Query the extracted columns
33
33
 
34
- Start the server (`npx dirsql` / `uvx dirsql`) and query:
35
-
36
34
  ```bash
37
- curl -s http://localhost:7117/query \
38
- -H 'content-type: application/json' \
39
- -d '{"sql":"SELECT title, author, year, _path FROM books ORDER BY year"}'
35
+ dirsql query "SELECT title, author, year, _path FROM books ORDER BY year"
40
36
  ```
41
37
 
42
38
  ```json
@@ -61,9 +57,7 @@ on-file = "jq -c -s '.' {path}"
61
57
  ```
62
58
 
63
59
  ```bash
64
- curl -s http://localhost:7117/query \
65
- -H 'content-type: application/json' \
66
- -d '{"sql":"SELECT event, user FROM events"}'
60
+ dirsql query "SELECT event, user FROM events"
67
61
  ```
68
62
 
69
63
  ```json
@@ -23,13 +23,10 @@ overrides the init symbol when it doesn't match the filename-derived
23
23
  default — `sqlite-vec` is exactly such a case
24
24
  ([reference](../reference/config.md#dirsql-extension)).
25
25
 
26
- Start the server (`npx dirsql` / `uvx dirsql`) and the extension's
27
- functions are callable:
26
+ The extension's functions are callable:
28
27
 
29
28
  ```bash
30
- curl -s http://localhost:7117/query \
31
- -H 'content-type: application/json' \
32
- -d '{"sql":"SELECT vec_version() AS vec_version"}'
29
+ dirsql query "SELECT vec_version() AS vec_version"
33
30
  ```
34
31
 
35
32
  ```json
@@ -99,20 +99,14 @@ installed `sqlite_vec` module to its bundled loadable. Naming rules per
99
99
  runtime — and the literal-path alternative that works everywhere — are in
100
100
  [Load a SQLite extension](./load-extension.md).
101
101
 
102
- ## 3. Start the server and ask questions
102
+ ## 3. Ask questions
103
103
 
104
- Launch with `sqlite-vec` available to the launcher's environment:
104
+ Run with `sqlite-vec` available to the launcher's environment. The initial
105
+ scan runs `embed.py` once per note, then the query argument goes straight to
106
+ `pre-query`, exactly as a `POST /query` body would:
105
107
 
106
108
  ```bash
107
- uvx --with sqlite-vec dirsql
108
- ```
109
-
110
- The initial scan runs `embed.py` once per note. Then ask:
111
-
112
- ```bash
113
- curl -s http://localhost:7117/query \
114
- -H 'content-type: application/json' \
115
- -d '{"q": "how do I cook pasta?"}'
109
+ uvx --with sqlite-vec dirsql query '{"q": "how do I cook pasta?"}'
116
110
  ```
117
111
 
118
112
  ```json
@@ -120,9 +114,7 @@ curl -s http://localhost:7117/query \
120
114
  ```
121
115
 
122
116
  ```bash
123
- curl -s http://localhost:7117/query \
124
- -H 'content-type: application/json' \
125
- -d '{"q": "reviewing code on github"}'
117
+ uvx --with sqlite-vec dirsql query '{"q": "reviewing code on github"}'
126
118
  ```
127
119
 
128
120
  ```json
@@ -133,9 +125,9 @@ Neither question shares a keyword with its top note — "cook" appears
133
125
  nowhere in `pasta.md`, "github" nowhere in `branches.md`. The distance
134
126
  ranking is doing the work.
135
127
 
136
- Because `pre-query` is set, the request body is *not* the usual
137
- `{"sql": …}` — the raw body goes to your script, which decides what SQL
138
- runs ([hook interactions](../reference/http-api.md#hook-interactions)).
128
+ Because `pre-query` is set, the query argument is *not* the usual
129
+ `{"sql": …}` — it goes to your script as-is, which decides what SQL runs
130
+ ([hook interactions](../reference/http-api.md#hook-interactions)).
139
131
 
140
132
  ## Recomputing vs. caching
141
133
 
@@ -31,12 +31,8 @@ ignored file never reaches any table — even one whose glob would match it.
31
31
 
32
32
  ## 2. Confirm what made it in
33
33
 
34
- Start the server (`npx dirsql` / `uvx dirsql`) and check:
35
-
36
34
  ```bash
37
- curl -s http://localhost:7117/query \
38
- -H 'content-type: application/json' \
39
- -d '{"sql":"SELECT _path FROM notes ORDER BY _path"}'
35
+ dirsql query "SELECT _path FROM notes ORDER BY _path"
40
36
  ```
41
37
 
42
38
  ```json
@@ -123,7 +123,9 @@ fn parse_sql_body(body: &str) -> Result<String, QueryFailure> {
123
123
  /// (`Internal`).
124
124
  fn classify_query_error(err: DirSqlError) -> QueryFailure {
125
125
  match err {
126
- DirSqlError::Core(_) => QueryFailure::BadRequest(err.to_string()),
126
+ DirSqlError::Core(_) | DirSqlError::WriteForbidden => {
127
+ QueryFailure::BadRequest(err.to_string())
128
+ }
127
129
  _ => QueryFailure::Internal(err.to_string()),
128
130
  }
129
131
  }
@@ -237,6 +239,17 @@ mod tests {
237
239
  );
238
240
  }
239
241
 
242
+ #[test]
243
+ fn classify_write_forbidden_is_bad_request() {
244
+ // A rejected write is the caller's fault, exactly like a `Core` SQL
245
+ // error -> `BadRequest`, not the `Internal` catch-all (issue #444).
246
+ let failure = classify_query_error(DirSqlError::WriteForbidden);
247
+ assert!(
248
+ matches!(failure, QueryFailure::BadRequest(_)),
249
+ "got: {failure:?}"
250
+ );
251
+ }
252
+
240
253
  #[test]
241
254
  fn require_ready_fails_unavailable_when_degraded() {
242
255
  // The degraded state yields `Unavailable` carrying the diagnostic
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