dirsql 0.4.60__tar.gz → 0.4.61__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 (259) hide show
  1. {dirsql-0.4.60 → dirsql-0.4.61}/Cargo.lock +2 -3
  2. {dirsql-0.4.60 → dirsql-0.4.61}/PKG-INFO +1 -1
  3. {dirsql-0.4.60/packages/rust → dirsql-0.4.61}/docs/reference/config.md +37 -0
  4. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/Cargo.toml +1 -1
  5. {dirsql-0.4.60 → dirsql-0.4.61/packages/python}/docs/reference/config.md +37 -0
  6. dirsql-0.4.61/packages/python/e2e-attestations/claude-1201-single-walk.json +7 -0
  7. dirsql-0.4.61/packages/python/e2e-attestations/claude-1204-embed-batch.json +7 -0
  8. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/Cargo.toml +2 -3
  9. {dirsql-0.4.60/packages/python → dirsql-0.4.61/packages/rust}/docs/reference/config.md +37 -0
  10. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/config.rs +58 -0
  11. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/db.rs +242 -10
  12. dirsql-0.4.61/packages/rust/src/functions.rs +1887 -0
  13. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/lib.rs +21 -137
  14. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/parsed_vtab.rs +3 -3
  15. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/scanner.rs +223 -98
  16. dirsql-0.4.61/packages/rust/src/vtab.rs +708 -0
  17. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/vtab_scaffold.rs +198 -12
  18. dirsql-0.4.60/packages/rust/src/functions.rs +0 -1040
  19. dirsql-0.4.60/packages/rust/src/vtab.rs +0 -498
  20. {dirsql-0.4.60 → dirsql-0.4.61}/Cargo.toml +0 -0
  21. {dirsql-0.4.60 → dirsql-0.4.61}/README.md +0 -0
  22. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/__init__.py +0 -0
  23. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/_async.py +0 -0
  24. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/_dirsql.pyi +0 -0
  25. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/cli/__init__.py +0 -0
  26. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/cli/discover_plugins/__init__.py +0 -0
  27. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
  28. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
  29. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
  30. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
  31. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
  32. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/cli/main.py +0 -0
  33. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/cli/resolve_config_extensions.py +0 -0
  34. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/plan_entry_path.py +0 -0
  35. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/py.typed +0 -0
  36. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/read_config.py +0 -0
  37. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/resolve_configs_extension_specs.py +0 -0
  38. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/resolve_extension.py +0 -0
  39. {dirsql-0.4.60 → dirsql-0.4.61}/dirsql/resolve_package.py +0 -0
  40. {dirsql-0.4.60 → dirsql-0.4.61}/docs/.claude/CLAUDE.md +0 -0
  41. {dirsql-0.4.60 → dirsql-0.4.61}/docs/.vitepress/config.ts +0 -0
  42. {dirsql-0.4.60 → dirsql-0.4.61}/docs/.vitepress/theme/index.ts +0 -0
  43. {dirsql-0.4.60 → dirsql-0.4.61}/docs/.vitepress/theme/lang.ts +0 -0
  44. {dirsql-0.4.60 → dirsql-0.4.61}/docs/AGENTS.md +0 -0
  45. {dirsql-0.4.60 → dirsql-0.4.61}/docs/explanation.md +0 -0
  46. {dirsql-0.4.60 → dirsql-0.4.61}/docs/getting-started.md +0 -0
  47. {dirsql-0.4.60 → dirsql-0.4.61}/docs/howto/columns-from-paths.md +0 -0
  48. {dirsql-0.4.60 → dirsql-0.4.61}/docs/howto/define-tables.md +0 -0
  49. {dirsql-0.4.60 → dirsql-0.4.61}/docs/howto/embed.md +0 -0
  50. {dirsql-0.4.60 → dirsql-0.4.61}/docs/howto/extract-from-contents.md +0 -0
  51. {dirsql-0.4.60 → dirsql-0.4.61}/docs/howto/load-extension.md +0 -0
  52. {dirsql-0.4.60 → dirsql-0.4.61}/docs/howto/parse-files-into-columns.md +0 -0
  53. {dirsql-0.4.60 → dirsql-0.4.61}/docs/howto/persist.md +0 -0
  54. {dirsql-0.4.60 → dirsql-0.4.61}/docs/howto/query-json.md +0 -0
  55. {dirsql-0.4.60 → dirsql-0.4.61}/docs/howto/query-without-config.md +0 -0
  56. {dirsql-0.4.60 → dirsql-0.4.61}/docs/howto/react-to-changes.md +0 -0
  57. {dirsql-0.4.60 → dirsql-0.4.61}/docs/howto/search-by-meaning.md +0 -0
  58. {dirsql-0.4.60 → dirsql-0.4.61}/docs/howto/search-indexes.md +0 -0
  59. {dirsql-0.4.60 → dirsql-0.4.61}/docs/howto/skip-files.md +0 -0
  60. {dirsql-0.4.60 → dirsql-0.4.61}/docs/howto/write-a-plugin.md +0 -0
  61. {dirsql-0.4.60 → dirsql-0.4.61}/docs/index.md +0 -0
  62. {dirsql-0.4.60 → dirsql-0.4.61}/docs/package.json +0 -0
  63. {dirsql-0.4.60 → dirsql-0.4.61}/docs/plugins.md +0 -0
  64. {dirsql-0.4.60 → dirsql-0.4.61}/docs/pnpm-lock.yaml +0 -0
  65. {dirsql-0.4.60 → dirsql-0.4.61}/docs/pnpm-workspace.yaml +0 -0
  66. {dirsql-0.4.60 → dirsql-0.4.61}/docs/reference/cli.md +0 -0
  67. {dirsql-0.4.60 → dirsql-0.4.61}/docs/reference/columns.md +0 -0
  68. {dirsql-0.4.60 → dirsql-0.4.61}/docs/reference/hooks.md +0 -0
  69. {dirsql-0.4.60 → dirsql-0.4.61}/docs/reference/http-api.md +0 -0
  70. {dirsql-0.4.60 → dirsql-0.4.61}/docs/reference/path-tables.md +0 -0
  71. {dirsql-0.4.60 → dirsql-0.4.61}/docs/reference/sdk.md +0 -0
  72. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/CHANGELOG.md +0 -0
  73. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/MIGRATIONS.md +0 -0
  74. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/README.md +0 -0
  75. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  76. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
  77. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  78. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
  79. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  80. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  81. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  82. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
  83. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  84. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
  85. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
  86. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
  87. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
  88. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
  89. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
  90. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
  91. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
  92. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-08-20-curtaincall-dev-dependency.md +0 -0
  93. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-08-20-declared-table-name.md +0 -0
  94. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-09-04-config-paths-from-argv-module.md +0 -0
  95. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-09-05-config-extension-loader-split.md +0 -0
  96. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-09-05-resolve-config-extensions-split.md +0 -0
  97. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-09-05-resolve-extension-split.md +0 -0
  98. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-09-09-launcher-config-path-scan.md +0 -0
  99. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-09-17-extension-resolution-via-core.md +0 -0
  100. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-09-18-export-scan-failure.md +0 -0
  101. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-09-18-flatten-row-event-in-core.md +0 -0
  102. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-09-18-programmatic-extension-plan.md +0 -0
  103. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
  104. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/2026-09-24-query-rows-in-projection-order.md +0 -0
  105. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/changelog.d/README.md +0 -0
  106. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/conftest.py +0 -0
  107. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/.claude/CLAUDE.md +0 -0
  108. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/.vitepress/config.ts +0 -0
  109. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  110. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  111. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/AGENTS.md +0 -0
  112. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/explanation.md +0 -0
  113. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/getting-started.md +0 -0
  114. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/howto/columns-from-paths.md +0 -0
  115. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/howto/define-tables.md +0 -0
  116. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/howto/embed.md +0 -0
  117. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/howto/extract-from-contents.md +0 -0
  118. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/howto/load-extension.md +0 -0
  119. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
  120. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/howto/persist.md +0 -0
  121. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/howto/query-json.md +0 -0
  122. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/howto/query-without-config.md +0 -0
  123. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/howto/react-to-changes.md +0 -0
  124. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/howto/search-by-meaning.md +0 -0
  125. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/howto/search-indexes.md +0 -0
  126. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/howto/skip-files.md +0 -0
  127. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/howto/write-a-plugin.md +0 -0
  128. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/index.md +0 -0
  129. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/package.json +0 -0
  130. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/plugins.md +0 -0
  131. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/pnpm-lock.yaml +0 -0
  132. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/pnpm-workspace.yaml +0 -0
  133. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/reference/cli.md +0 -0
  134. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/reference/columns.md +0 -0
  135. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/reference/hooks.md +0 -0
  136. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/reference/http-api.md +0 -0
  137. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/reference/path-tables.md +0 -0
  138. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/docs/reference/sdk.md +0 -0
  139. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/cc-keen-knuth-f11gyq.json +0 -0
  140. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1056-py-ofpf9.json +0 -0
  141. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1066-p1-resolve-extension.json +0 -0
  142. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1078-argv-config-paths-core.json +0 -0
  143. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1079-p2-resolve-config-extensions.json +0 -0
  144. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1080-share-vtab-scaffolding.json +0 -0
  145. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1081-indicatif-progress.json +0 -0
  146. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1096-watch-moved-dir.json +0 -0
  147. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1109-watch-moved-out.json +0 -0
  148. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1119-ext-plan.json +0 -0
  149. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1120-py-ext.json +0 -0
  150. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1122-ext-cleanup.json +0 -0
  151. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1130-codec-crates.json +0 -0
  152. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1131-flatten-row-event.json +0 -0
  153. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1139-sse-flatten.json +0 -0
  154. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1140-scan-failure-export.json +0 -0
  155. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1148-clippy-all-targets.json +0 -0
  156. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1164-sigint-fatal.json +0 -0
  157. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1170-projection-order.json +0 -0
  158. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1172-on-file-path.json +0 -0
  159. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1173-py-projection-order.json +0 -0
  160. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1184-win-rel-paths.json +0 -0
  161. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1185-win-abs-table-names.json +0 -0
  162. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1186-win-test-harness.json +0 -0
  163. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1207-win-argv-quote.json +0 -0
  164. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-1208-win-nonverbatim-paths.json +0 -0
  165. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
  166. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
  167. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-epic-953-slice2-reedline.json +0 -0
  168. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-epic-953-slice3-format.json +0 -0
  169. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-epic-953-stacked-prs-x59wm3.json +0 -0
  170. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
  171. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
  172. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +0 -0
  173. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-issue-986-red-test-e7sjrb.json +0 -0
  174. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-tackle-1034-cachesplit.json +0 -0
  175. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-tackle-1042-py12.json +0 -0
  176. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-tackle-956-xzen74.json +0 -0
  177. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6-worker-calls.json +0 -0
  178. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6.json +0 -0
  179. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/e2e-attestations/claude-tackle-975-n8mc2h.json +0 -0
  180. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  181. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  182. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  183. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  184. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  185. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
  186. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  187. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
  188. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
  189. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/migrations.d/2026-08-20-declared-table-name.md +0 -0
  190. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/migrations.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
  191. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/migrations.d/2026-09-24-query-rows-in-projection-order.md +0 -0
  192. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/migrations.d/README.md +0 -0
  193. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/src/lib.rs +0 -0
  194. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/testing-conventions.toml +0 -0
  195. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/tests/__init__.py +0 -0
  196. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/tests/conftest.py +0 -0
  197. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/tests/e2e/__init__.py +0 -0
  198. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
  199. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
  200. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/tests/e2e/speed_of_light.py +0 -0
  201. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/tests/integration/__init__.py +0 -0
  202. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/tests/integration/binding/__init__.py +0 -0
  203. {dirsql-0.4.60 → dirsql-0.4.61}/packages/python/tests/integration/hermetic/__init__.py +0 -0
  204. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/CHANGELOG.md +0 -0
  205. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/MIGRATIONS.md +0 -0
  206. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/README.md +0 -0
  207. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/benches/db_bench.rs +0 -0
  208. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/benches/differ_bench.rs +0 -0
  209. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/benches/matcher_bench.rs +0 -0
  210. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/benches/scanner_bench.rs +0 -0
  211. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/explanation.md +0 -0
  212. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/getting-started.md +0 -0
  213. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/howto/columns-from-paths.md +0 -0
  214. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/howto/define-tables.md +0 -0
  215. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/howto/embed.md +0 -0
  216. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/howto/extract-from-contents.md +0 -0
  217. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/howto/load-extension.md +0 -0
  218. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
  219. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/howto/persist.md +0 -0
  220. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/howto/query-json.md +0 -0
  221. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/howto/query-without-config.md +0 -0
  222. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/howto/react-to-changes.md +0 -0
  223. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/howto/search-by-meaning.md +0 -0
  224. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/howto/search-indexes.md +0 -0
  225. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/howto/skip-files.md +0 -0
  226. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/howto/write-a-plugin.md +0 -0
  227. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/index.md +0 -0
  228. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/plugins.md +0 -0
  229. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/reference/cli.md +0 -0
  230. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/reference/columns.md +0 -0
  231. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/reference/hooks.md +0 -0
  232. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/reference/http-api.md +0 -0
  233. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/reference/path-tables.md +0 -0
  234. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/docs/reference/sdk.md +0 -0
  235. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/bin/dirsql.rs +0 -0
  236. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/cli/execute.rs +0 -0
  237. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/cli/init.rs +0 -0
  238. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/cli/mod.rs +0 -0
  239. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/cli/repl.rs +0 -0
  240. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/cli/router.rs +0 -0
  241. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/cli/run.rs +0 -0
  242. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/cli/serialize.rs +0 -0
  243. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/cli/server.rs +0 -0
  244. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/cli/table.rs +0 -0
  245. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/command.rs +0 -0
  246. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/default_config.toml +0 -0
  247. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/differ.rs +0 -0
  248. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/extension_resolution.rs +0 -0
  249. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/infer.rs +0 -0
  250. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/launcher.rs +0 -0
  251. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/matcher.rs +0 -0
  252. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/parsed_cache.rs +0 -0
  253. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/path_table.rs +0 -0
  254. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/persist.rs +0 -0
  255. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/progress.rs +0 -0
  256. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/row_event_flat.rs +0 -0
  257. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/sql_literal.rs +0 -0
  258. {dirsql-0.4.60 → dirsql-0.4.61}/packages/rust/src/watcher.rs +0 -0
  259. {dirsql-0.4.60 → dirsql-0.4.61}/pyproject.toml +0 -0
@@ -552,7 +552,7 @@ checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
552
552
 
553
553
  [[package]]
554
554
  name = "dirsql"
555
- version = "0.4.60"
555
+ version = "0.4.61"
556
556
  dependencies = [
557
557
  "assert_cmd",
558
558
  "axum",
@@ -585,7 +585,6 @@ dependencies = [
585
585
  "tokio-stream",
586
586
  "toml",
587
587
  "typed-path",
588
- "walkdir",
589
588
  ]
590
589
 
591
590
  [[package]]
@@ -601,7 +600,7 @@ dependencies = [
601
600
 
602
601
  [[package]]
603
602
  name = "dirsql-py-ext"
604
- version = "0.4.60"
603
+ version = "0.4.61"
605
604
  dependencies = [
606
605
  "dirsql",
607
606
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dirsql
3
- Version: 0.4.60
3
+ Version: 0.4.61
4
4
  Requires-Dist: bin-shim>=0.1
5
5
  Summary: Ephemeral SQL index over a local directory
6
6
  Keywords: sql,filesystem,directory,sqlite,index
@@ -111,6 +111,7 @@ its `embed()` function exactly this way.
111
111
  | `command` | yes (non-empty) | The worker command. Argv-split with the same no-shell quoting rules as [command hooks](./hooks.md#argv-not-a-shell); runs in the config file's directory. |
112
112
  | `deterministic` | no (default `false`) | When `true`, the function is registered with `SQLITE_DETERMINISTIC`, letting SQLite cache and reuse results for identical arguments within a query. Only set it when the worker really is a pure function of its arguments. |
113
113
  | `timeout` | no | Per-**call** time bound: a positive integer is whole seconds (`timeout = 600`), a string is an integer suffixed `s` or `ms` (`"600s"`, `"250ms"`). When absent, the function mechanism's own 30-second default applies. |
114
+ | `batch` | no | A positive integer: the most calls one **batched request** carries. When set, a statement's values are gathered and sent to the worker in bulk (see [Batching](#batching)); the worker must then speak the batched protocol shape as well as the single-call one. When absent, the worker only ever sees single calls. |
114
115
 
115
116
  ```toml
116
117
  [[dirsql.function]]
@@ -173,6 +174,42 @@ request line in, one response line out, per call:
173
174
  - **stderr passes through** to `dirsql`'s stderr, so a worker's progress
174
175
  bars and download logs reach the terminal.
175
176
 
177
+ ### Batching
178
+
179
+ One round trip per row is the wrong shape for a worker whose cost is
180
+ per-request rather than per-value — an embedding model encodes a list of
181
+ texts in little more time than one. A function declaring `batch = N` is sent
182
+ values in bulk instead:
183
+
184
+ - **Request:** `{"calls": [[<arg>, ...], ...]}` — up to `N` calls, each
185
+ encoded exactly as a single call's argument list.
186
+ - **Response:** `{"results": [<response>, ...]}` — one single-call response
187
+ (`{"ok": ...}` with its optional `"meta"`, or `{"err": ...}`) per call, in
188
+ order. A per-call `{"err": ...}` fails the query the way it would on a
189
+ single call. A top-level `{"err": "message"}` instead fails every call in
190
+ the request.
191
+ - The round trip is bounded by the per-call `timeout` **times the number of
192
+ calls** in the request.
193
+
194
+ A batching worker must still answer `{"call": [...]}`: `dirsql` gathers a
195
+ statement's values by running it twice. The first run makes one ordinary
196
+ round trip for the function's first value, binds that reply in place of every
197
+ later distinct argument tuple, and queues those tuples into batched requests
198
+ of at most `N`; the second run is served from the replies. A statement that
199
+ never calls a batched function runs once, exactly as before. Values are
200
+ deduplicated along the way, so the [progress line](./cli.md#progress-reporting)
201
+ counts distinct calls, whichever request shape carried them.
202
+
203
+ ```toml
204
+ [[dirsql.function]]
205
+ name = "embed"
206
+ args = [1, 2]
207
+ command = "dirsql-plugin-embeddings worker"
208
+ deterministic = true
209
+ timeout = "600s"
210
+ batch = 256
211
+ ```
212
+
176
213
  ## `[[table]]`
177
214
 
178
215
  Each entry maps a glob pattern to a SQL table. A table's columns are exactly
@@ -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.4.60"
7
+ version = "0.4.61"
8
8
  # abi3 note: the `abi3-py310` pyo3 feature (below) builds ONE stable-ABI
9
9
  # `cp310-abi3` wheel per platform that loads on every CPython >= 3.10
10
10
  # (matching `pyproject.toml`'s `requires-python = ">=3.10"`), instead of
@@ -111,6 +111,7 @@ its `embed()` function exactly this way.
111
111
  | `command` | yes (non-empty) | The worker command. Argv-split with the same no-shell quoting rules as [command hooks](./hooks.md#argv-not-a-shell); runs in the config file's directory. |
112
112
  | `deterministic` | no (default `false`) | When `true`, the function is registered with `SQLITE_DETERMINISTIC`, letting SQLite cache and reuse results for identical arguments within a query. Only set it when the worker really is a pure function of its arguments. |
113
113
  | `timeout` | no | Per-**call** time bound: a positive integer is whole seconds (`timeout = 600`), a string is an integer suffixed `s` or `ms` (`"600s"`, `"250ms"`). When absent, the function mechanism's own 30-second default applies. |
114
+ | `batch` | no | A positive integer: the most calls one **batched request** carries. When set, a statement's values are gathered and sent to the worker in bulk (see [Batching](#batching)); the worker must then speak the batched protocol shape as well as the single-call one. When absent, the worker only ever sees single calls. |
114
115
 
115
116
  ```toml
116
117
  [[dirsql.function]]
@@ -173,6 +174,42 @@ request line in, one response line out, per call:
173
174
  - **stderr passes through** to `dirsql`'s stderr, so a worker's progress
174
175
  bars and download logs reach the terminal.
175
176
 
177
+ ### Batching
178
+
179
+ One round trip per row is the wrong shape for a worker whose cost is
180
+ per-request rather than per-value — an embedding model encodes a list of
181
+ texts in little more time than one. A function declaring `batch = N` is sent
182
+ values in bulk instead:
183
+
184
+ - **Request:** `{"calls": [[<arg>, ...], ...]}` — up to `N` calls, each
185
+ encoded exactly as a single call's argument list.
186
+ - **Response:** `{"results": [<response>, ...]}` — one single-call response
187
+ (`{"ok": ...}` with its optional `"meta"`, or `{"err": ...}`) per call, in
188
+ order. A per-call `{"err": ...}` fails the query the way it would on a
189
+ single call. A top-level `{"err": "message"}` instead fails every call in
190
+ the request.
191
+ - The round trip is bounded by the per-call `timeout` **times the number of
192
+ calls** in the request.
193
+
194
+ A batching worker must still answer `{"call": [...]}`: `dirsql` gathers a
195
+ statement's values by running it twice. The first run makes one ordinary
196
+ round trip for the function's first value, binds that reply in place of every
197
+ later distinct argument tuple, and queues those tuples into batched requests
198
+ of at most `N`; the second run is served from the replies. A statement that
199
+ never calls a batched function runs once, exactly as before. Values are
200
+ deduplicated along the way, so the [progress line](./cli.md#progress-reporting)
201
+ counts distinct calls, whichever request shape carried them.
202
+
203
+ ```toml
204
+ [[dirsql.function]]
205
+ name = "embed"
206
+ args = [1, 2]
207
+ command = "dirsql-plugin-embeddings worker"
208
+ deterministic = true
209
+ timeout = "600s"
210
+ batch = 256
211
+ ```
212
+
176
213
  ## `[[table]]`
177
214
 
178
215
  Each entry maps a glob pattern to a SQL table. A table's columns are exactly
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "just test-e2e",
3
+ "ran_at": 1790945578,
4
+ "exit_code": 0,
5
+ "commit": "c74aacb34e2aa97f26338176180e7e063f83465b",
6
+ "branch": "claude/1201-single-walk"
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "just test-e2e",
3
+ "ran_at": 1790942055,
4
+ "exit_code": 0,
5
+ "commit": "b9f0529e785dd54fa49496fb3fa48bbcdb14764d",
6
+ "branch": "claude/1204-embed-batch"
7
+ }
@@ -6,7 +6,7 @@ description = "Ephemeral SQL index over a local directory"
6
6
  # version stays for the binding crates (publish = false). The literal
7
7
  # intentionally lags the published version: putitoutthere rewrites it to
8
8
  # the planned release version at build time and never commits it back.
9
- version = "0.4.60"
9
+ version = "0.4.61"
10
10
  edition.workspace = true
11
11
  # Literal `license` (not `license.workspace = true`) because
12
12
  # putitoutthere's preflight check reads `[package].license` directly
@@ -69,7 +69,7 @@ globset = "0.4"
69
69
  # library consumer never pulls it.
70
70
  hex = { version = "0.4", optional = true }
71
71
  # Hierarchical `.gitignore` matching for path-table scans (the fd/ripgrep
72
- # semantics), without adopting its walker: the scan keeps `walkdir`.
72
+ # semantics), without adopting its walker: the scan has its own.
73
73
  ignore = "0.4"
74
74
  indicatif = "0.18.6"
75
75
  notify = "7"
@@ -87,7 +87,6 @@ tokio.workspace = true
87
87
  tokio-stream = { version = "0.1", features = ["sync"], optional = true }
88
88
  toml = "0.8"
89
89
  typed-path = "0.12"
90
- walkdir = "2"
91
90
 
92
91
  [lints.rust]
93
92
  # `deny`, not `forbid`: rusqlite's API imposes five unavoidable `unsafe`
@@ -111,6 +111,7 @@ its `embed()` function exactly this way.
111
111
  | `command` | yes (non-empty) | The worker command. Argv-split with the same no-shell quoting rules as [command hooks](./hooks.md#argv-not-a-shell); runs in the config file's directory. |
112
112
  | `deterministic` | no (default `false`) | When `true`, the function is registered with `SQLITE_DETERMINISTIC`, letting SQLite cache and reuse results for identical arguments within a query. Only set it when the worker really is a pure function of its arguments. |
113
113
  | `timeout` | no | Per-**call** time bound: a positive integer is whole seconds (`timeout = 600`), a string is an integer suffixed `s` or `ms` (`"600s"`, `"250ms"`). When absent, the function mechanism's own 30-second default applies. |
114
+ | `batch` | no | A positive integer: the most calls one **batched request** carries. When set, a statement's values are gathered and sent to the worker in bulk (see [Batching](#batching)); the worker must then speak the batched protocol shape as well as the single-call one. When absent, the worker only ever sees single calls. |
114
115
 
115
116
  ```toml
116
117
  [[dirsql.function]]
@@ -173,6 +174,42 @@ request line in, one response line out, per call:
173
174
  - **stderr passes through** to `dirsql`'s stderr, so a worker's progress
174
175
  bars and download logs reach the terminal.
175
176
 
177
+ ### Batching
178
+
179
+ One round trip per row is the wrong shape for a worker whose cost is
180
+ per-request rather than per-value — an embedding model encodes a list of
181
+ texts in little more time than one. A function declaring `batch = N` is sent
182
+ values in bulk instead:
183
+
184
+ - **Request:** `{"calls": [[<arg>, ...], ...]}` — up to `N` calls, each
185
+ encoded exactly as a single call's argument list.
186
+ - **Response:** `{"results": [<response>, ...]}` — one single-call response
187
+ (`{"ok": ...}` with its optional `"meta"`, or `{"err": ...}`) per call, in
188
+ order. A per-call `{"err": ...}` fails the query the way it would on a
189
+ single call. A top-level `{"err": "message"}` instead fails every call in
190
+ the request.
191
+ - The round trip is bounded by the per-call `timeout` **times the number of
192
+ calls** in the request.
193
+
194
+ A batching worker must still answer `{"call": [...]}`: `dirsql` gathers a
195
+ statement's values by running it twice. The first run makes one ordinary
196
+ round trip for the function's first value, binds that reply in place of every
197
+ later distinct argument tuple, and queues those tuples into batched requests
198
+ of at most `N`; the second run is served from the replies. A statement that
199
+ never calls a batched function runs once, exactly as before. Values are
200
+ deduplicated along the way, so the [progress line](./cli.md#progress-reporting)
201
+ counts distinct calls, whichever request shape carried them.
202
+
203
+ ```toml
204
+ [[dirsql.function]]
205
+ name = "embed"
206
+ args = [1, 2]
207
+ command = "dirsql-plugin-embeddings worker"
208
+ deterministic = true
209
+ timeout = "600s"
210
+ batch = 256
211
+ ```
212
+
176
213
  ## `[[table]]`
177
214
 
178
215
  Each entry maps a glob pattern to a SQL table. A table's columns are exactly
@@ -45,6 +45,9 @@ pub enum ConfigError {
45
45
  )]
46
46
  InvalidFunctionTimeout { name: String, value: String },
47
47
 
48
+ #[error("[[dirsql.function]] '{name}': 'batch' must be a positive integer, got {value}")]
49
+ InvalidFunctionBatch { name: String, value: String },
50
+
48
51
  #[error("Field '{0}' must not be empty")]
49
52
  EmptyField(&'static str),
50
53
 
@@ -212,6 +215,11 @@ pub struct FunctionSpec {
212
215
  /// Optional per-round-trip-call timeout, overriding the function
213
216
  /// mechanism's own 30-second default.
214
217
  pub timeout: Option<Duration>,
218
+ /// Optional cap on the calls one batched request carries. When set, a
219
+ /// statement's values are sent to the worker in bulk (see
220
+ /// `dirsql::functions`); when absent the worker only ever sees single
221
+ /// calls.
222
+ pub batch: Option<usize>,
215
223
  }
216
224
 
217
225
  /// Configuration for a single table.
@@ -267,6 +275,9 @@ struct RawFunction {
267
275
  command: Option<String>,
268
276
  deterministic: Option<bool>,
269
277
  timeout: Option<RawFunctionTimeout>,
278
+ // Any shape, so a non-integer hits the same actionable error as a
279
+ // non-positive one.
280
+ batch: Option<toml::Value>,
270
281
  }
271
282
 
272
283
  /// The `timeout` key accepts positive whole seconds (`timeout = 600`) or a
@@ -417,12 +428,27 @@ fn parse_function(raw: RawFunction) -> Result<FunctionSpec> {
417
428
  Some(raw_timeout) => Some(parse_function_timeout(&name, &raw_timeout)?),
418
429
  };
419
430
 
431
+ let batch = match raw.batch {
432
+ None => None,
433
+ Some(value) => Some(
434
+ value
435
+ .as_integer()
436
+ .and_then(|n| usize::try_from(n).ok())
437
+ .filter(|n| *n > 0)
438
+ .ok_or_else(|| ConfigError::InvalidFunctionBatch {
439
+ name: name.clone(),
440
+ value: value.to_string(),
441
+ })?,
442
+ ),
443
+ };
444
+
420
445
  Ok(FunctionSpec {
421
446
  name,
422
447
  args,
423
448
  command,
424
449
  deterministic: raw.deterministic.unwrap_or(false),
425
450
  timeout,
451
+ batch,
426
452
  })
427
453
  }
428
454
 
@@ -1162,6 +1188,7 @@ args = [1, 2]
1162
1188
  command = "dirsql-plugin-embeddings worker"
1163
1189
  deterministic = true
1164
1190
  timeout = "600s"
1191
+ batch = 64
1165
1192
  "#;
1166
1193
  let config = load_config_str(toml).unwrap();
1167
1194
  assert_eq!(
@@ -1172,6 +1199,7 @@ timeout = "600s"
1172
1199
  command: "dirsql-plugin-embeddings worker".to_string(),
1173
1200
  deterministic: true,
1174
1201
  timeout: Some(Duration::from_secs(600)),
1202
+ batch: Some(64),
1175
1203
  }]
1176
1204
  );
1177
1205
  }
@@ -1187,6 +1215,36 @@ command = "worker"
1187
1215
  let config = load_config_str(toml).unwrap();
1188
1216
  assert!(!config.functions[0].deterministic);
1189
1217
  assert!(config.functions[0].timeout.is_none());
1218
+ assert!(config.functions[0].batch.is_none());
1219
+ }
1220
+
1221
+ /// `batch = 0` would send empty requests, a negative cap means nothing,
1222
+ /// and a string is not a count; each is the one actionable error.
1223
+ #[test]
1224
+ fn function_batch_rejects_anything_but_a_positive_integer() {
1225
+ for value in ["0", "-4", "\"many\"", "2.5"] {
1226
+ let toml = format!(
1227
+ r#"
1228
+ [[dirsql.function]]
1229
+ name = "f"
1230
+ args = [1]
1231
+ command = "worker"
1232
+ batch = {value}
1233
+ "#
1234
+ );
1235
+ let err = load_config_str(&toml).unwrap_err();
1236
+ match &err {
1237
+ ConfigError::InvalidFunctionBatch { name, value: got } => {
1238
+ assert_eq!(name, "f");
1239
+ assert_eq!(got, value);
1240
+ }
1241
+ other => panic!("batch = {value}: expected InvalidFunctionBatch, got {other:?}"),
1242
+ }
1243
+ assert_eq!(
1244
+ err.to_string(),
1245
+ format!("[[dirsql.function]] 'f': 'batch' must be a positive integer, got {value}")
1246
+ );
1247
+ }
1190
1248
  }
1191
1249
 
1192
1250
  #[test]