dirsql 0.3.65__tar.gz → 0.3.67__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 (135) hide show
  1. {dirsql-0.3.65 → dirsql-0.3.67}/Cargo.lock +1 -1
  2. {dirsql-0.3.65 → dirsql-0.3.67}/PKG-INFO +3 -3
  3. {dirsql-0.3.65/packages/python → dirsql-0.3.67}/README.md +2 -2
  4. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/Cargo.toml +1 -1
  5. {dirsql-0.3.65 → dirsql-0.3.67/packages/python}/README.md +2 -2
  6. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/e2e-attestation.json +2 -2
  7. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/README.md +1 -1
  8. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/bin/dirsql.rs +2 -2
  9. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/cli/init.rs +43 -1
  10. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/cli/mod.rs +22 -0
  11. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/cli/router.rs +34 -0
  12. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/lib.rs +1 -1
  13. {dirsql-0.3.65 → dirsql-0.3.67}/Cargo.toml +0 -0
  14. {dirsql-0.3.65 → dirsql-0.3.67}/dirsql/__init__.py +0 -0
  15. {dirsql-0.3.65 → dirsql-0.3.67}/dirsql/_async.py +0 -0
  16. {dirsql-0.3.65 → dirsql-0.3.67}/dirsql/_dirsql.pyi +0 -0
  17. {dirsql-0.3.65 → dirsql-0.3.67}/dirsql/cli/__init__.py +0 -0
  18. {dirsql-0.3.65 → dirsql-0.3.67}/dirsql/cli/binary_path.py +0 -0
  19. {dirsql-0.3.65 → dirsql-0.3.67}/dirsql/cli/is_windows.py +0 -0
  20. {dirsql-0.3.65 → dirsql-0.3.67}/dirsql/cli/main.py +0 -0
  21. {dirsql-0.3.65 → dirsql-0.3.67}/dirsql/cli/resolve_config_extensions.py +0 -0
  22. {dirsql-0.3.65 → dirsql-0.3.67}/dirsql/py.typed +0 -0
  23. {dirsql-0.3.65 → dirsql-0.3.67}/dirsql/resolve_config_extensions.py +0 -0
  24. {dirsql-0.3.65 → dirsql-0.3.67}/dirsql/resolve_extension.py +0 -0
  25. {dirsql-0.3.65 → dirsql-0.3.67}/docs/.claude/CLAUDE.md +0 -0
  26. {dirsql-0.3.65 → dirsql-0.3.67}/docs/.vitepress/config.ts +0 -0
  27. {dirsql-0.3.65 → dirsql-0.3.67}/docs/.vitepress/theme/index.ts +0 -0
  28. {dirsql-0.3.65 → dirsql-0.3.67}/docs/.vitepress/theme/lang.ts +0 -0
  29. {dirsql-0.3.65 → dirsql-0.3.67}/docs/AGENTS.md +0 -0
  30. {dirsql-0.3.65 → dirsql-0.3.67}/docs/explanation.md +0 -0
  31. {dirsql-0.3.65 → dirsql-0.3.67}/docs/getting-started.md +0 -0
  32. {dirsql-0.3.65 → dirsql-0.3.67}/docs/howto/columns-from-paths.md +0 -0
  33. {dirsql-0.3.65 → dirsql-0.3.67}/docs/howto/define-tables.md +0 -0
  34. {dirsql-0.3.65 → dirsql-0.3.67}/docs/howto/embed.md +0 -0
  35. {dirsql-0.3.65 → dirsql-0.3.67}/docs/howto/extract-from-contents.md +0 -0
  36. {dirsql-0.3.65 → dirsql-0.3.67}/docs/howto/load-extension.md +0 -0
  37. {dirsql-0.3.65 → dirsql-0.3.67}/docs/howto/persist.md +0 -0
  38. {dirsql-0.3.65 → dirsql-0.3.67}/docs/howto/react-to-changes.md +0 -0
  39. {dirsql-0.3.65 → dirsql-0.3.67}/docs/howto/search-by-meaning.md +0 -0
  40. {dirsql-0.3.65 → dirsql-0.3.67}/docs/howto/skip-files.md +0 -0
  41. {dirsql-0.3.65 → dirsql-0.3.67}/docs/index.md +0 -0
  42. {dirsql-0.3.65 → dirsql-0.3.67}/docs/migrations.md +0 -0
  43. {dirsql-0.3.65 → dirsql-0.3.67}/docs/package.json +0 -0
  44. {dirsql-0.3.65 → dirsql-0.3.67}/docs/playwright.config.ts +0 -0
  45. {dirsql-0.3.65 → dirsql-0.3.67}/docs/pnpm-lock.yaml +0 -0
  46. {dirsql-0.3.65 → dirsql-0.3.67}/docs/pnpm-workspace.yaml +0 -0
  47. {dirsql-0.3.65 → dirsql-0.3.67}/docs/reference/cli.md +0 -0
  48. {dirsql-0.3.65 → dirsql-0.3.67}/docs/reference/columns.md +0 -0
  49. {dirsql-0.3.65 → dirsql-0.3.67}/docs/reference/config.md +0 -0
  50. {dirsql-0.3.65 → dirsql-0.3.67}/docs/reference/hooks.md +0 -0
  51. {dirsql-0.3.65 → dirsql-0.3.67}/docs/reference/http-api.md +0 -0
  52. {dirsql-0.3.65 → dirsql-0.3.67}/docs/reference/sdk.md +0 -0
  53. {dirsql-0.3.65 → dirsql-0.3.67}/docs/tests/integration/home.spec.ts +0 -0
  54. {dirsql-0.3.65 → dirsql-0.3.67}/docs/tests/integration/language-flag.spec.ts +0 -0
  55. {dirsql-0.3.65 → dirsql-0.3.67}/docs/tests/integration/sidebar.spec.ts +0 -0
  56. {dirsql-0.3.65 → dirsql-0.3.67}/docs/tests/unit/config.test.ts +0 -0
  57. {dirsql-0.3.65 → dirsql-0.3.67}/docs/tests/unit/lang.test.ts +0 -0
  58. {dirsql-0.3.65 → dirsql-0.3.67}/docs/vitest.config.ts +0 -0
  59. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/conftest.py +0 -0
  60. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/.claude/CLAUDE.md +0 -0
  61. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/.vitepress/config.ts +0 -0
  62. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  63. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  64. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/AGENTS.md +0 -0
  65. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/explanation.md +0 -0
  66. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/getting-started.md +0 -0
  67. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/howto/columns-from-paths.md +0 -0
  68. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/howto/define-tables.md +0 -0
  69. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/howto/embed.md +0 -0
  70. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/howto/extract-from-contents.md +0 -0
  71. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/howto/load-extension.md +0 -0
  72. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/howto/persist.md +0 -0
  73. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/howto/react-to-changes.md +0 -0
  74. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/howto/search-by-meaning.md +0 -0
  75. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/howto/skip-files.md +0 -0
  76. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/index.md +0 -0
  77. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/migrations.md +0 -0
  78. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/package.json +0 -0
  79. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/playwright.config.ts +0 -0
  80. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/pnpm-lock.yaml +0 -0
  81. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/pnpm-workspace.yaml +0 -0
  82. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/reference/cli.md +0 -0
  83. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/reference/columns.md +0 -0
  84. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/reference/config.md +0 -0
  85. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/reference/hooks.md +0 -0
  86. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/reference/http-api.md +0 -0
  87. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/reference/sdk.md +0 -0
  88. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/tests/integration/home.spec.ts +0 -0
  89. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/tests/integration/language-flag.spec.ts +0 -0
  90. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/tests/integration/sidebar.spec.ts +0 -0
  91. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/tests/unit/config.test.ts +0 -0
  92. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/tests/unit/lang.test.ts +0 -0
  93. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/docs/vitest.config.ts +0 -0
  94. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/src/lib.rs +0 -0
  95. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/tests/__init__.py +0 -0
  96. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/tests/binding/__init__.py +0 -0
  97. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/tests/conftest.py +0 -0
  98. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/tests/e2e/__init__.py +0 -0
  99. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/tests/integration/__init__.py +0 -0
  100. {dirsql-0.3.65 → dirsql-0.3.67}/packages/python/tests/smoke/__init__.py +0 -0
  101. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/Cargo.toml +0 -0
  102. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/benches/db_bench.rs +0 -0
  103. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/benches/differ_bench.rs +0 -0
  104. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/benches/matcher_bench.rs +0 -0
  105. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/benches/scanner_bench.rs +0 -0
  106. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/explanation.md +0 -0
  107. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/getting-started.md +0 -0
  108. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/howto/columns-from-paths.md +0 -0
  109. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/howto/define-tables.md +0 -0
  110. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/howto/embed.md +0 -0
  111. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/howto/extract-from-contents.md +0 -0
  112. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/howto/load-extension.md +0 -0
  113. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/howto/persist.md +0 -0
  114. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/howto/react-to-changes.md +0 -0
  115. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/howto/search-by-meaning.md +0 -0
  116. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/howto/skip-files.md +0 -0
  117. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/index.md +0 -0
  118. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/migrations.md +0 -0
  119. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/reference/cli.md +0 -0
  120. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/reference/columns.md +0 -0
  121. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/reference/config.md +0 -0
  122. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/reference/hooks.md +0 -0
  123. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/reference/http-api.md +0 -0
  124. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/docs/reference/sdk.md +0 -0
  125. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/cli/serialize.rs +0 -0
  126. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/cli/server.rs +0 -0
  127. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/command.rs +0 -0
  128. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/config.rs +0 -0
  129. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/db.rs +0 -0
  130. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/differ.rs +0 -0
  131. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/matcher.rs +0 -0
  132. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/persist.rs +0 -0
  133. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/scanner.rs +0 -0
  134. {dirsql-0.3.65 → dirsql-0.3.67}/packages/rust/src/watcher.rs +0 -0
  135. {dirsql-0.3.65 → dirsql-0.3.67}/pyproject.toml +0 -0
@@ -500,7 +500,7 @@ dependencies = [
500
500
 
501
501
  [[package]]
502
502
  name = "dirsql-py-ext"
503
- version = "0.3.65"
503
+ version = "0.3.67"
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.65
3
+ Version: 0.3.67
4
4
  Requires-Dist: pytest>=8 ; extra == 'dev'
5
5
  Requires-Dist: pytest-describe>=2 ; extra == 'dev'
6
6
  Requires-Dist: pytest-asyncio>=0.23 ; extra == 'dev'
@@ -117,7 +117,7 @@ await db.ready()
117
117
  rows = await db.query("SELECT vec_version() AS v")
118
118
  ```
119
119
 
120
- `dirsql` enables extension loading only while loading the configured libraries, then disables it again, so the SQL `load_extension()` function is never exposed to your queries. Programmatic entries load first, followed by any `[[dirsql.extension]]` entries declared in a `config` file. See the [config reference](https://github.com/thekevinscott/dirsql/blob/main/docs/cli/config.md#loading-extensions).
120
+ `dirsql` enables extension loading only while loading the configured libraries, then disables it again, so the SQL `load_extension()` function is never exposed to your queries. Programmatic entries load first, followed by any `[[dirsql.extension]]` entries declared in a `config` file. See the [config reference](https://github.com/thekevinscott/dirsql/blob/main/docs/reference/config.md#dirsqlextension).
121
121
 
122
122
  ## Watching for changes
123
123
 
@@ -134,7 +134,7 @@ Each event has `.action` (`"insert"`, `"update"`, `"delete"`, or `"error"`), `.t
134
134
 
135
135
  ## CLI
136
136
 
137
- `pip install dirsql` also installs a `dirsql` console script that runs an HTTP server exposing the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. Run `dirsql` (or `uvx dirsql`) to start it. See the [CLI guide](https://thekevinscott.github.io/dirsql/cli/).
137
+ `pip install dirsql` also installs a `dirsql` console script that runs an HTTP server exposing the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. Run `dirsql` (or `uvx dirsql`) to start it. See the [CLI reference](https://thekevinscott.github.io/dirsql/reference/cli).
138
138
 
139
139
  ## License
140
140
 
@@ -99,7 +99,7 @@ await db.ready()
99
99
  rows = await db.query("SELECT vec_version() AS v")
100
100
  ```
101
101
 
102
- `dirsql` enables extension loading only while loading the configured libraries, then disables it again, so the SQL `load_extension()` function is never exposed to your queries. Programmatic entries load first, followed by any `[[dirsql.extension]]` entries declared in a `config` file. See the [config reference](https://github.com/thekevinscott/dirsql/blob/main/docs/cli/config.md#loading-extensions).
102
+ `dirsql` enables extension loading only while loading the configured libraries, then disables it again, so the SQL `load_extension()` function is never exposed to your queries. Programmatic entries load first, followed by any `[[dirsql.extension]]` entries declared in a `config` file. See the [config reference](https://github.com/thekevinscott/dirsql/blob/main/docs/reference/config.md#dirsqlextension).
103
103
 
104
104
  ## Watching for changes
105
105
 
@@ -116,7 +116,7 @@ Each event has `.action` (`"insert"`, `"update"`, `"delete"`, or `"error"`), `.t
116
116
 
117
117
  ## CLI
118
118
 
119
- `pip install dirsql` also installs a `dirsql` console script that runs an HTTP server exposing the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. Run `dirsql` (or `uvx dirsql`) to start it. See the [CLI guide](https://thekevinscott.github.io/dirsql/cli/).
119
+ `pip install dirsql` also installs a `dirsql` console script that runs an HTTP server exposing the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. Run `dirsql` (or `uvx dirsql`) to start it. See the [CLI reference](https://thekevinscott.github.io/dirsql/reference/cli).
120
120
 
121
121
  ## License
122
122
 
@@ -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.65"
7
+ version = "0.3.67"
8
8
  edition.workspace = true
9
9
  publish = false
10
10
  readme = "README.md"
@@ -99,7 +99,7 @@ await db.ready()
99
99
  rows = await db.query("SELECT vec_version() AS v")
100
100
  ```
101
101
 
102
- `dirsql` enables extension loading only while loading the configured libraries, then disables it again, so the SQL `load_extension()` function is never exposed to your queries. Programmatic entries load first, followed by any `[[dirsql.extension]]` entries declared in a `config` file. See the [config reference](https://github.com/thekevinscott/dirsql/blob/main/docs/cli/config.md#loading-extensions).
102
+ `dirsql` enables extension loading only while loading the configured libraries, then disables it again, so the SQL `load_extension()` function is never exposed to your queries. Programmatic entries load first, followed by any `[[dirsql.extension]]` entries declared in a `config` file. See the [config reference](https://github.com/thekevinscott/dirsql/blob/main/docs/reference/config.md#dirsqlextension).
103
103
 
104
104
  ## Watching for changes
105
105
 
@@ -116,7 +116,7 @@ Each event has `.action` (`"insert"`, `"update"`, `"delete"`, or `"error"`), `.t
116
116
 
117
117
  ## CLI
118
118
 
119
- `pip install dirsql` also installs a `dirsql` console script that runs an HTTP server exposing the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. Run `dirsql` (or `uvx dirsql`) to start it. See the [CLI guide](https://thekevinscott.github.io/dirsql/cli/).
119
+ `pip install dirsql` also installs a `dirsql` console script that runs an HTTP server exposing the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. Run `dirsql` (or `uvx dirsql`) to start it. See the [CLI reference](https://thekevinscott.github.io/dirsql/reference/cli).
120
120
 
121
121
  ## License
122
122
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "command": "uv run python -m pytest tests/e2e/ -x -q",
3
- "ran_at": 1783214202,
3
+ "ran_at": 1783215074,
4
4
  "exit_code": 0,
5
- "commit": "b2c468d12c2e60a7df48884b391a788fd184a62f"
5
+ "commit": "c5d752734907f27497b28b3448bad19247c3482e"
6
6
  }
@@ -124,7 +124,7 @@ cargo install dirsql --features cli
124
124
  dirsql
125
125
  ```
126
126
 
127
- Running `dirsql` starts an HTTP server bound to `localhost:7117` that exposes the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. Override with `--host`, `--port`, `--config`. See the [CLI guide](https://thekevinscott.github.io/dirsql/cli/).
127
+ Running `dirsql` starts an HTTP server bound to `localhost:7117` that exposes the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. Override with `--host`, `--port`, `--config`. See the [CLI reference](https://thekevinscott.github.io/dirsql/reference/cli).
128
128
 
129
129
  The `cli` feature is **opt-in** -- `cargo add dirsql` pulls no CLI dependencies. `cargo install dirsql` without `--features cli` silently installs nothing (`required-features` skips the bin target with no warning); always include the flag, or use `npx dirsql` / `uvx dirsql` for prebuilt binaries.
130
130
 
@@ -1,6 +1,6 @@
1
1
  //! `dirsql` CLI binary. Two modes:
2
- //! - No subcommand: HTTP server documented in `docs/guide/cli.md`.
3
- //! - `init`: starter `.dirsql.toml` generation; see `docs/guide/init.md`.
2
+ //! - No subcommand: HTTP server documented in `docs/reference/cli.md`.
3
+ //! - `init`: starter `.dirsql.toml` generation; see `docs/reference/cli.md`.
4
4
  //!
5
5
  //! Only compiled with `--features cli`.
6
6
 
@@ -1,5 +1,5 @@
1
1
  //! `dirsql init` — generate a starter `.dirsql.toml` by shelling out to
2
- //! the `claude` CLI. See `docs/guide/init.md` for the user-facing
2
+ //! the `claude` CLI. See `docs/reference/cli.md` for the user-facing
3
3
  //! contract.
4
4
  //!
5
5
  //! The agent's only required responsibility is to print a valid
@@ -166,4 +166,46 @@ mod tests {
166
166
  "got: {err:?}"
167
167
  );
168
168
  }
169
+
170
+ // The spawn / non-zero-exit / write failure arms of `run` require actually
171
+ // invoking `claude` and touching the filesystem, so they are exercised at
172
+ // the e2e tier. Their `Display` renderings, however, are pure and covered
173
+ // here (the values are constructed inline, no process or fs I/O).
174
+
175
+ #[test]
176
+ fn spawn_error_display_mentions_spawn() {
177
+ let err = InitError::Spawn(std::io::Error::new(
178
+ std::io::ErrorKind::PermissionDenied,
179
+ "denied",
180
+ ));
181
+ let msg = format!("{err}");
182
+ assert!(msg.contains("failed to spawn"), "got: {msg}");
183
+ assert!(msg.contains("denied"), "got: {msg}");
184
+ }
185
+
186
+ #[test]
187
+ fn write_error_display_names_the_path_and_source() {
188
+ let err = InitError::Write {
189
+ path: PathBuf::from("/tmp/out.toml"),
190
+ source: std::io::Error::other("disk full"),
191
+ };
192
+ let msg = format!("{err}");
193
+ assert!(msg.contains("/tmp/out.toml"), "got: {msg}");
194
+ assert!(msg.contains("disk full"), "got: {msg}");
195
+ }
196
+
197
+ #[test]
198
+ fn invalid_utf8_error_display_mentions_utf8() {
199
+ // A non-UTF8 byte sequence yields the `FromUtf8Error` that `#[from]`
200
+ // converts into `InitError::InvalidUtf8`.
201
+ let utf8_err = String::from_utf8(vec![0xff, 0xfe]).unwrap_err();
202
+ let err: InitError = utf8_err.into();
203
+ let msg = format!("{err}");
204
+ assert!(msg.contains("non-UTF8"), "got: {msg}");
205
+ }
206
+
207
+ // NOTE: `InitError::ClaudeFailed`'s `Display` is not unit-tested -- building
208
+ // it needs an `ExitStatus`, and `std::process::ExitStatus::from_raw` is
209
+ // effectful std the unit-isolation lint (`no-out-of-module-call`) forbids.
210
+ // Its rendering is covered end-to-end at the e2e tier instead.
169
211
  }
@@ -330,4 +330,26 @@ mod tests {
330
330
  assert_eq!(pq.command, "reshape {args}");
331
331
  assert_eq!(pq.config_dir, PathBuf::from("/proj"));
332
332
  }
333
+
334
+ #[test]
335
+ fn with_query_timeout_overrides_the_default() {
336
+ // The builder replaces the 30s default with the supplied timeout and
337
+ // leaves the rest of the config untouched.
338
+ let cfg = ServerConfig::bind("127.0.0.1", 8080).with_query_timeout(Duration::from_secs(5));
339
+ assert_eq!(cfg.query_timeout, Duration::from_secs(5));
340
+ assert_eq!(cfg.host, "127.0.0.1");
341
+ assert_eq!(cfg.port, 8080);
342
+ }
343
+
344
+ #[test]
345
+ fn app_state_from_string_builds_the_unavailable_arm() {
346
+ // `String -> AppState` yields the degraded arm carrying the diagnostic
347
+ // verbatim (the `/query`/`/events` 503 body). `AppState` isn't `Debug`,
348
+ // so match rather than assert on a rendering.
349
+ let state: AppState = "config failed to load".to_string().into();
350
+ match state {
351
+ AppState::Unavailable(reason) => assert_eq!(reason, "config failed to load"),
352
+ AppState::Ready(_) => panic!("String must map to the Unavailable arm"),
353
+ }
354
+ }
333
355
  }
@@ -356,4 +356,38 @@ mod tests {
356
356
  "application/json"
357
357
  );
358
358
  }
359
+
360
+ // `parse_sql_body` is the no-`pre-query` request path: it is pure (serde
361
+ // only), so it is unit-tested here directly rather than through the async
362
+ // `handle_query` handler (which needs a live server and is covered at the
363
+ // integration tier).
364
+
365
+ #[test]
366
+ fn parse_sql_body_returns_trimmed_sql() {
367
+ // Surrounding whitespace is stripped; the inner SQL is returned as-is.
368
+ let sql = parse_sql_body(r#"{"sql": " SELECT 1 "}"#).expect("valid body");
369
+ assert_eq!(sql, "SELECT 1");
370
+ }
371
+
372
+ #[test]
373
+ fn parse_sql_body_rejects_malformed_json() {
374
+ // A body that isn't JSON fails at the serde step -> 400.
375
+ let resp = parse_sql_body("not json").expect_err("malformed JSON must be rejected");
376
+ assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
377
+ }
378
+
379
+ #[test]
380
+ fn parse_sql_body_rejects_whitespace_only_sql() {
381
+ // A present-but-blank `sql` trims to empty -> 400 (the `Some(_)` arm,
382
+ // and the `false` side of the `!s.is_empty()` guard).
383
+ let resp = parse_sql_body(r#"{"sql": " "}"#).expect_err("empty sql must be rejected");
384
+ assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
385
+ }
386
+
387
+ #[test]
388
+ fn parse_sql_body_rejects_missing_sql_field() {
389
+ // Valid JSON object with no `sql` key -> the `None` arm -> 400.
390
+ let resp = parse_sql_body("{}").expect_err("missing sql must be rejected");
391
+ assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
392
+ }
359
393
  }
@@ -987,7 +987,7 @@ impl DirSQLBuilder {
987
987
  /// written to `<root>/.dirsql/cache.db` (override via
988
988
  /// [`persist_path`](Self::persist_path)) so subsequent startups only
989
989
  /// re-parse files that have actually changed. See
990
- /// `docs/guide/persistence.md` for the reconcile contract.
990
+ /// `docs/howto/persist.md` for the reconcile contract.
991
991
  pub fn persist(mut self, persist: bool) -> Self {
992
992
  self.persist = persist;
993
993
  self
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