dirsql 0.4.108__tar.gz → 0.4.109__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 (427) hide show
  1. {dirsql-0.4.108 → dirsql-0.4.109}/Cargo.lock +2 -2
  2. {dirsql-0.4.108 → dirsql-0.4.109}/PKG-INFO +1 -1
  3. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/Cargo.toml +1 -1
  4. dirsql-0.4.109/packages/python/e2e-attestations/bot-1416-watch-speed-1008.json +7 -0
  5. dirsql-0.4.109/packages/python/e2e-attestations/bot-1462-paired-speed-harness-1008.json +7 -0
  6. dirsql-0.4.109/packages/python/tests/e2e/speed_of_light.py +205 -0
  7. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/Cargo.toml +1 -1
  8. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/db.rs +1 -1
  9. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/lib.rs +69 -6
  10. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/on_file.rs +43 -5
  11. dirsql-0.4.108/packages/python/tests/e2e/speed_of_light.py +0 -124
  12. {dirsql-0.4.108 → dirsql-0.4.109}/Cargo.toml +0 -0
  13. {dirsql-0.4.108 → dirsql-0.4.109}/README.md +0 -0
  14. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/__init__.py +0 -0
  15. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/_async.py +0 -0
  16. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/_dirsql.pyi +0 -0
  17. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/cli/__init__.py +0 -0
  18. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/cli/discover_plugins/__init__.py +0 -0
  19. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
  20. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
  21. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
  22. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
  23. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/cli/main.py +0 -0
  24. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/cli/resolve_config_extensions.py +0 -0
  25. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/plan_entry_path.py +0 -0
  26. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/py.typed +0 -0
  27. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/read_config.py +0 -0
  28. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/resolve_configs_extension_specs.py +0 -0
  29. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/resolve_extension.py +0 -0
  30. {dirsql-0.4.108 → dirsql-0.4.109}/dirsql/resolve_package.py +0 -0
  31. {dirsql-0.4.108 → dirsql-0.4.109}/docs/.claude/CLAUDE.md +0 -0
  32. {dirsql-0.4.108 → dirsql-0.4.109}/docs/.vitepress/config.ts +0 -0
  33. {dirsql-0.4.108 → dirsql-0.4.109}/docs/.vitepress/theme/index.ts +0 -0
  34. {dirsql-0.4.108 → dirsql-0.4.109}/docs/.vitepress/theme/lang.ts +0 -0
  35. {dirsql-0.4.108 → dirsql-0.4.109}/docs/AGENTS.md +0 -0
  36. {dirsql-0.4.108 → dirsql-0.4.109}/docs/context/.gitattributes +0 -0
  37. {dirsql-0.4.108 → dirsql-0.4.109}/docs/context/recipes.md +0 -0
  38. {dirsql-0.4.108 → dirsql-0.4.109}/docs/context/troubleshooting.md +0 -0
  39. {dirsql-0.4.108 → dirsql-0.4.109}/docs/context/usage.md +0 -0
  40. {dirsql-0.4.108 → dirsql-0.4.109}/docs/explanation.md +0 -0
  41. {dirsql-0.4.108 → dirsql-0.4.109}/docs/getting-started.md +0 -0
  42. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/agent-skill.md +0 -0
  43. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/columns-from-paths.md +0 -0
  44. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/define-tables.md +0 -0
  45. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/embed.md +0 -0
  46. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/extract-from-contents.md +0 -0
  47. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/load-extension.md +0 -0
  48. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/parse-files-into-columns.md +0 -0
  49. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/persist.md +0 -0
  50. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/query-json.md +0 -0
  51. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/query-without-config.md +0 -0
  52. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/react-to-changes.md +0 -0
  53. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/search-by-meaning.md +0 -0
  54. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/search-indexes.md +0 -0
  55. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/skip-files.md +0 -0
  56. {dirsql-0.4.108 → dirsql-0.4.109}/docs/howto/write-a-plugin.md +0 -0
  57. {dirsql-0.4.108 → dirsql-0.4.109}/docs/index.md +0 -0
  58. {dirsql-0.4.108 → dirsql-0.4.109}/docs/package.json +0 -0
  59. {dirsql-0.4.108 → dirsql-0.4.109}/docs/plugins.md +0 -0
  60. {dirsql-0.4.108 → dirsql-0.4.109}/docs/pnpm-lock.yaml +0 -0
  61. {dirsql-0.4.108 → dirsql-0.4.109}/docs/pnpm-workspace.yaml +0 -0
  62. {dirsql-0.4.108 → dirsql-0.4.109}/docs/reference/cli.md +0 -0
  63. {dirsql-0.4.108 → dirsql-0.4.109}/docs/reference/columns.md +0 -0
  64. {dirsql-0.4.108 → dirsql-0.4.109}/docs/reference/config.md +0 -0
  65. {dirsql-0.4.108 → dirsql-0.4.109}/docs/reference/glob.md +0 -0
  66. {dirsql-0.4.108 → dirsql-0.4.109}/docs/reference/hooks.md +0 -0
  67. {dirsql-0.4.108 → dirsql-0.4.109}/docs/reference/http-api.md +0 -0
  68. {dirsql-0.4.108 → dirsql-0.4.109}/docs/reference/path-tables.md +0 -0
  69. {dirsql-0.4.108 → dirsql-0.4.109}/docs/reference/sdk.md +0 -0
  70. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/CHANGELOG.md +0 -0
  71. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/MIGRATIONS.md +0 -0
  72. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/README.md +0 -0
  73. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  74. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
  75. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  76. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
  77. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  78. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  79. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  80. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
  81. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  82. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
  83. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
  84. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
  85. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
  86. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
  87. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
  88. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
  89. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
  90. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-08-20-curtaincall-dev-dependency.md +0 -0
  91. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-08-20-declared-table-name.md +0 -0
  92. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-09-04-config-paths-from-argv-module.md +0 -0
  93. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-09-05-config-extension-loader-split.md +0 -0
  94. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-09-05-resolve-config-extensions-split.md +0 -0
  95. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-09-05-resolve-extension-split.md +0 -0
  96. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-09-09-launcher-config-path-scan.md +0 -0
  97. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-09-17-extension-resolution-via-core.md +0 -0
  98. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-09-18-export-scan-failure.md +0 -0
  99. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-09-18-flatten-row-event-in-core.md +0 -0
  100. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-09-18-programmatic-extension-plan.md +0 -0
  101. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
  102. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-09-24-query-rows-in-projection-order.md +0 -0
  103. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-02-readme-docs-host.md +0 -0
  104. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-03-one-glob-rule-for-config-globs.md +0 -0
  105. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-03-path-table-directory-one-level.md +0 -0
  106. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-04-path-table-dotfiles-hidden.md +0 -0
  107. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-05-brace-groups-follow-bash.md +0 -0
  108. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-05-cli-context.md +0 -0
  109. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-05-gitignore-requires-repo.md +0 -0
  110. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-05-path-table-node-modules-named.md +0 -0
  111. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-05-path-table-symlinks.md +0 -0
  112. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-05-path-table-trailing-slash.md +0 -0
  113. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-05-unbalanced-brackets-literal.md +0 -0
  114. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-06-config-braces.md +0 -0
  115. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-06-config-directory.md +0 -0
  116. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-06-config-dotnames.md +0 -0
  117. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-06-config-gitignore.md +0 -0
  118. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-06-config-globs-anchor-at-the-config.md +0 -0
  119. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-06-config-links.md +0 -0
  120. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-06-one-glob-compiler.md +0 -0
  121. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-06-plugin-no-default-records.md +0 -0
  122. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-06-watch-broadcast.md +0 -0
  123. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-06-zero-match-config-table-warning.md +0 -0
  124. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-07-bracket-slash-literal.md +0 -0
  125. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-07-dotdot-and-double-slashes.md +0 -0
  126. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-07-dotdot-as-written.md +0 -0
  127. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-07-glob-walks-node-modules.md +0 -0
  128. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-07-literal-gitignore.md +0 -0
  129. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-07-on-file-ndjson.md +0 -0
  130. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-07-parallel-hooks.md +0 -0
  131. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-07-persist-cache-outside-root.md +0 -0
  132. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-07-posix-classes-unicode.md +0 -0
  133. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-07-spread-few-large-files.md +0 -0
  134. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-08-small-walks-stay-on-one-thread.md +0 -0
  135. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/2026-10-08-watch-requires-named-table.md +0 -0
  136. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/changelog.d/README.md +0 -0
  137. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/conftest.py +0 -0
  138. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/.claude/CLAUDE.md +0 -0
  139. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/.vitepress/config.ts +0 -0
  140. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  141. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  142. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/AGENTS.md +0 -0
  143. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/context/.gitattributes +0 -0
  144. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/context/recipes.md +0 -0
  145. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/context/troubleshooting.md +0 -0
  146. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/context/usage.md +0 -0
  147. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/explanation.md +0 -0
  148. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/getting-started.md +0 -0
  149. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/agent-skill.md +0 -0
  150. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/columns-from-paths.md +0 -0
  151. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/define-tables.md +0 -0
  152. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/embed.md +0 -0
  153. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/extract-from-contents.md +0 -0
  154. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/load-extension.md +0 -0
  155. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
  156. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/persist.md +0 -0
  157. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/query-json.md +0 -0
  158. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/query-without-config.md +0 -0
  159. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/react-to-changes.md +0 -0
  160. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/search-by-meaning.md +0 -0
  161. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/search-indexes.md +0 -0
  162. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/skip-files.md +0 -0
  163. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/howto/write-a-plugin.md +0 -0
  164. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/index.md +0 -0
  165. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/package.json +0 -0
  166. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/plugins.md +0 -0
  167. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/pnpm-lock.yaml +0 -0
  168. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/pnpm-workspace.yaml +0 -0
  169. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/reference/cli.md +0 -0
  170. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/reference/columns.md +0 -0
  171. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/reference/config.md +0 -0
  172. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/reference/glob.md +0 -0
  173. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/reference/hooks.md +0 -0
  174. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/reference/http-api.md +0 -0
  175. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/reference/path-tables.md +0 -0
  176. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/docs/reference/sdk.md +0 -0
  177. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1334-listing-exemptions.json +0 -0
  178. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1397-watch-broadcast.json +0 -0
  179. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1398-inotify-error.json +0 -0
  180. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1399-server-cors.json +0 -0
  181. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1401-watch-scope.json +0 -0
  182. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1406-watch-no-tables-1008.json +0 -0
  183. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1407-child-place-depth.json +0 -0
  184. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1414-stat-speed.json +0 -0
  185. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1415-server-speed.json +0 -0
  186. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1418-node-modules.json +0 -0
  187. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1419-dotdot-slashes.json +0 -0
  188. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1420-bracket-slash.json +0 -0
  189. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1421-posix-unicode.json +0 -0
  190. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1422-literal-gitignore.json +0 -0
  191. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1426-walk-spawn-threshold-1008.json +0 -0
  192. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1428-ndjson-hooks.json +0 -0
  193. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1429-parallel-hooks.json +0 -0
  194. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1430-dotdot-as-written.json +0 -0
  195. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1431-persist-cache-dir.json +0 -0
  196. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1437-test-cache-isolation.json +0 -0
  197. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1440-fix-main-build.json +0 -0
  198. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1448-wildcard-ignored-prefix.json +0 -0
  199. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1451-named-dir-never-hidden.json +0 -0
  200. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1454-split-few-files.json +0 -0
  201. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1457-incremental-refresh-1008.json +0 -0
  202. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1459-rescan-on-overflow-1008.json +0 -0
  203. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-1461-row-footprint-1008.json +0 -0
  204. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/bot-fix-main-place-depth-20261007.json +0 -0
  205. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/cc-keen-knuth-f11gyq.json +0 -0
  206. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1056-py-ofpf9.json +0 -0
  207. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1066-p1-resolve-extension.json +0 -0
  208. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1078-argv-config-paths-core.json +0 -0
  209. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1079-p2-resolve-config-extensions.json +0 -0
  210. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1080-share-vtab-scaffolding.json +0 -0
  211. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1081-indicatif-progress.json +0 -0
  212. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1096-watch-moved-dir.json +0 -0
  213. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1109-watch-moved-out.json +0 -0
  214. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1119-ext-plan.json +0 -0
  215. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1120-py-ext.json +0 -0
  216. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1122-ext-cleanup.json +0 -0
  217. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1130-codec-crates.json +0 -0
  218. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1131-flatten-row-event.json +0 -0
  219. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1139-sse-flatten.json +0 -0
  220. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1140-scan-failure-export.json +0 -0
  221. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1148-clippy-all-targets.json +0 -0
  222. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1164-sigint-fatal.json +0 -0
  223. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1170-projection-order.json +0 -0
  224. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1172-on-file-path.json +0 -0
  225. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1173-py-projection-order.json +0 -0
  226. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1184-win-rel-paths.json +0 -0
  227. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1185-win-abs-table-names.json +0 -0
  228. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1186-win-test-harness.json +0 -0
  229. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1196-join-index.json +0 -0
  230. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1199-glob-prefix.json +0 -0
  231. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1201-single-walk.json +0 -0
  232. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1204-embed-batch.json +0 -0
  233. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1207-win-argv-quote.json +0 -0
  234. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1208-win-nonverbatim-paths.json +0 -0
  235. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1215-on-file-batch.json +0 -0
  236. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1216-on-file-cleanup.json +0 -0
  237. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1223-config-glob-rule.json +0 -0
  238. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1223-dir-one-level.json +0 -0
  239. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1225-plugin-no-default.json +0 -0
  240. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1226-stale-docs.json +0 -0
  241. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1232-anchor-plumbing.json +0 -0
  242. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1232-config-anchor.json +0 -0
  243. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1232-multi-watch.json +0 -0
  244. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1232-zero-match.json +0 -0
  245. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1238-parallel-walk.json +0 -0
  246. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1241-content-prefetch.json +0 -0
  247. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1243-ingest-perf.json +0 -0
  248. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1249-dotfiles.json +0 -0
  249. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1256-symlinks.json +0 -0
  250. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1257-trailing-slash.json +0 -0
  251. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1258-config-braces.json +0 -0
  252. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1258-config-directory.json +0 -0
  253. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1258-config-dotnames.json +0 -0
  254. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1258-config-gitignore.json +0 -0
  255. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1258-config-links.json +0 -0
  256. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1258-one-pattern.json +0 -0
  257. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1262-brace-literal.json +0 -0
  258. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1264-context.json +0 -0
  259. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1267-posix-classes.json +0 -0
  260. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1268-unbalanced-brackets.json +0 -0
  261. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1269-utf8-chars.json +0 -0
  262. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1271-node-modules-named.json +0 -0
  263. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1272-ancestor-gitignore.json +0 -0
  264. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1273-walk-prune.json +0 -0
  265. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1285-ingest-fast.json +0 -0
  266. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1286-nested-repo.json +0 -0
  267. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1305-glob-speed.json +0 -0
  268. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1308-glob-speed.json +0 -0
  269. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1310-glob-speed.json +0 -0
  270. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1311-glob-speed.json +0 -0
  271. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1312-glob-speed.json +0 -0
  272. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1318-lazy-stat.json +0 -0
  273. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1320-walk-speed.json +0 -0
  274. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1322-walk-readdir.json +0 -0
  275. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1325-parallel-walk.json +0 -0
  276. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1326-stream-rows.json +0 -0
  277. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1330-python-dirsql-patch.json +0 -0
  278. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1330-python-extensions-patch.json +0 -0
  279. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1330-scanner-effects.json +0 -0
  280. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1330-scanner-gitignore.json +0 -0
  281. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1330-vtab-prefetch-flag.json +0 -0
  282. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1330-vtab-read.json +0 -0
  283. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-1351-dot-dirs.json +0 -0
  284. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
  285. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
  286. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-epic-953-slice2-reedline.json +0 -0
  287. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-epic-953-slice3-format.json +0 -0
  288. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-epic-953-stacked-prs-x59wm3.json +0 -0
  289. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
  290. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
  291. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +0 -0
  292. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-issue-986-red-test-e7sjrb.json +0 -0
  293. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-tackle-1034-cachesplit.json +0 -0
  294. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-tackle-1042-py12.json +0 -0
  295. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-tackle-956-xzen74.json +0 -0
  296. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6-worker-calls.json +0 -0
  297. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6.json +0 -0
  298. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/e2e-attestations/claude-tackle-975-n8mc2h.json +0 -0
  299. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  300. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  301. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  302. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  303. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  304. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
  305. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  306. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
  307. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
  308. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-08-20-declared-table-name.md +0 -0
  309. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
  310. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-09-24-query-rows-in-projection-order.md +0 -0
  311. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-02-readme-docs-host.md +0 -0
  312. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-03-one-glob-rule-for-config-globs.md +0 -0
  313. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-03-path-table-directory-one-level.md +0 -0
  314. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-04-path-table-dotfiles-hidden.md +0 -0
  315. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-05-brace-groups-follow-bash.md +0 -0
  316. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-05-cli-context.md +0 -0
  317. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-05-gitignore-requires-repo.md +0 -0
  318. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-05-path-table-node-modules-named.md +0 -0
  319. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-05-path-table-symlinks.md +0 -0
  320. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-05-path-table-trailing-slash.md +0 -0
  321. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-05-unbalanced-brackets-literal.md +0 -0
  322. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-06-config-braces.md +0 -0
  323. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-06-config-directory.md +0 -0
  324. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-06-config-dotnames.md +0 -0
  325. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-06-config-gitignore.md +0 -0
  326. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-06-config-globs-anchor-at-the-config.md +0 -0
  327. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-06-config-links.md +0 -0
  328. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-06-one-glob-compiler.md +0 -0
  329. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-06-plugin-no-default-records.md +0 -0
  330. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-06-watch-broadcast.md +0 -0
  331. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-06-zero-match-config-table-warning.md +0 -0
  332. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-07-bracket-slash-literal.md +0 -0
  333. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-07-dotdot-and-double-slashes.md +0 -0
  334. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-07-dotdot-as-written.md +0 -0
  335. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-07-glob-walks-node-modules.md +0 -0
  336. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-07-literal-gitignore.md +0 -0
  337. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-07-on-file-ndjson.md +0 -0
  338. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-07-parallel-hooks.md +0 -0
  339. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-07-persist-cache-outside-root.md +0 -0
  340. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-07-posix-classes-unicode.md +0 -0
  341. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-07-spread-few-large-files.md +0 -0
  342. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-08-small-walks-stay-on-one-thread.md +0 -0
  343. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/2026-10-08-watch-requires-named-table.md +0 -0
  344. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/migrations.d/README.md +0 -0
  345. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/src/lib.rs +0 -0
  346. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/testing-conventions.toml +0 -0
  347. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/tests/__init__.py +0 -0
  348. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/tests/conftest.py +0 -0
  349. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/tests/e2e/__init__.py +0 -0
  350. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
  351. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
  352. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/tests/integration/__init__.py +0 -0
  353. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/tests/integration/binding/__init__.py +0 -0
  354. {dirsql-0.4.108 → dirsql-0.4.109}/packages/python/tests/integration/hermetic/__init__.py +0 -0
  355. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/CHANGELOG.md +0 -0
  356. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/MIGRATIONS.md +0 -0
  357. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/README.md +0 -0
  358. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/benches/db_bench.rs +0 -0
  359. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/benches/differ_bench.rs +0 -0
  360. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/benches/matcher_bench.rs +0 -0
  361. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/benches/scanner_bench.rs +0 -0
  362. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/context/.gitattributes +0 -0
  363. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/context/recipes.md +0 -0
  364. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/context/troubleshooting.md +0 -0
  365. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/context/usage.md +0 -0
  366. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/explanation.md +0 -0
  367. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/getting-started.md +0 -0
  368. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/agent-skill.md +0 -0
  369. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/columns-from-paths.md +0 -0
  370. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/define-tables.md +0 -0
  371. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/embed.md +0 -0
  372. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/extract-from-contents.md +0 -0
  373. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/load-extension.md +0 -0
  374. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
  375. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/persist.md +0 -0
  376. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/query-json.md +0 -0
  377. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/query-without-config.md +0 -0
  378. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/react-to-changes.md +0 -0
  379. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/search-by-meaning.md +0 -0
  380. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/search-indexes.md +0 -0
  381. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/skip-files.md +0 -0
  382. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/howto/write-a-plugin.md +0 -0
  383. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/index.md +0 -0
  384. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/plugins.md +0 -0
  385. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/reference/cli.md +0 -0
  386. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/reference/columns.md +0 -0
  387. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/reference/config.md +0 -0
  388. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/reference/glob.md +0 -0
  389. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/reference/hooks.md +0 -0
  390. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/reference/http-api.md +0 -0
  391. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/reference/path-tables.md +0 -0
  392. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/docs/reference/sdk.md +0 -0
  393. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/bin/dirsql.rs +0 -0
  394. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/brace.rs +0 -0
  395. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/cli/context.rs +0 -0
  396. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/cli/execute.rs +0 -0
  397. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/cli/init.rs +0 -0
  398. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/cli/mod.rs +0 -0
  399. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/cli/repl.rs +0 -0
  400. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/cli/router.rs +0 -0
  401. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/cli/run.rs +0 -0
  402. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/cli/serialize.rs +0 -0
  403. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/cli/server.rs +0 -0
  404. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/cli/table.rs +0 -0
  405. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/command.rs +0 -0
  406. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/config.rs +0 -0
  407. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/default_config.toml +0 -0
  408. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/differ.rs +0 -0
  409. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/extension_resolution.rs +0 -0
  410. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/functions.rs +0 -0
  411. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/infer.rs +0 -0
  412. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/launcher.rs +0 -0
  413. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/listing.rs +0 -0
  414. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/matcher.rs +0 -0
  415. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/parsed_vtab.rs +0 -0
  416. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/path_table.rs +0 -0
  417. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/persist.rs +0 -0
  418. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/posix_class.rs +0 -0
  419. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/progress.rs +0 -0
  420. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/row_event_flat.rs +0 -0
  421. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/scanner.rs +0 -0
  422. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/sql_literal.rs +0 -0
  423. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/tree_walk.rs +0 -0
  424. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/vtab.rs +0 -0
  425. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/vtab_scaffold.rs +0 -0
  426. {dirsql-0.4.108 → dirsql-0.4.109}/packages/rust/src/watcher.rs +0 -0
  427. {dirsql-0.4.108 → dirsql-0.4.109}/pyproject.toml +0 -0
@@ -573,7 +573,7 @@ dependencies = [
573
573
 
574
574
  [[package]]
575
575
  name = "dirsql"
576
- version = "0.4.108"
576
+ version = "0.4.109"
577
577
  dependencies = [
578
578
  "assert_cmd",
579
579
  "axum",
@@ -625,7 +625,7 @@ dependencies = [
625
625
 
626
626
  [[package]]
627
627
  name = "dirsql-py-ext"
628
- version = "0.4.108"
628
+ version = "0.4.109"
629
629
  dependencies = [
630
630
  "dirsql",
631
631
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dirsql
3
- Version: 0.4.108
3
+ Version: 0.4.109
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
@@ -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.108"
7
+ version = "0.4.109"
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
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "uv run python -m pytest tests/e2e/watch_speed_test.py tests/e2e/on_file_query_test.py tests/e2e/server_speed_test.py -q -p no:cacheprovider",
3
+ "ran_at": 1791548609,
4
+ "exit_code": 0,
5
+ "commit": "ea38a739b990bc5135cc32ba9b61193fd0a2c1e1",
6
+ "branch": "bot/1416-watch-speed-1008"
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "uv run python -m pytest tests/e2e/glob_speed_one_level_test.py -x -q -rA",
3
+ "ran_at": 1791492173,
4
+ "exit_code": 0,
5
+ "commit": "ce22059009267d7759e47aa47cba10e28fd6543c",
6
+ "branch": "bot/1462-paired-speed-harness-1008"
7
+ }
@@ -0,0 +1,205 @@
1
+ """Harness for the use-case speed-of-light tests.
2
+
3
+ Each use-case test asks one question of a generated corpus twice: once through
4
+ the fastest native pipeline (find, sort, join, awk, a single parser process)
5
+ and once through the real `dirsql` launcher. The rows must be identical and
6
+ dirsql's wall time, after subtracting the launcher's measured startup, must be
7
+ within ten percent of native. The bar is a ratio, never a millisecond number,
8
+ so it holds on any machine.
9
+
10
+ Native and dirsql run as alternating pairs (native first, then dirsql first,
11
+ and so on) after one discarded warm-up pair, so drift in machine speed hits
12
+ both sides alike. The verdict is the median of the per-pair ratios. Startup is
13
+ the median of `dirsql query 'SELECT 1'` runs with the first dropped, and
14
+ native's own is the median of `bash -c true` the same way; each is subtracted
15
+ from its side. A corpus too small to time is grown by doubling until the
16
+ native pipeline takes a second, unless the corpus ceiling stops it sooner.
17
+ Output is captured as bytes and decoded after the clock stops.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import json
23
+ import os
24
+ import shutil
25
+ import statistics
26
+ import subprocess
27
+ import tempfile
28
+ import time
29
+ from dataclasses import dataclass
30
+ from typing import NamedTuple
31
+
32
+ ONE_SECOND = 1.0
33
+ TOLERANCE = 1.1
34
+ STARTUP_PROBES = 11
35
+ PAIRS = 100
36
+ HOPELESS_STREAK = 3
37
+ NATIVE_ENV = {**os.environ, "LC_ALL": "C"}
38
+
39
+
40
+ class Startup(NamedTuple):
41
+ dirsql: float
42
+ native: float
43
+
44
+
45
+ @dataclass
46
+ class Paired:
47
+ native_rows: object
48
+ dirsql_rows: object
49
+ native_seconds: list
50
+ dirsql_seconds: list
51
+
52
+
53
+ def cli() -> str:
54
+ dirsql = shutil.which("dirsql")
55
+ assert dirsql is not None, (
56
+ "`dirsql` console script not on PATH -- run `uv run maturin develop`"
57
+ )
58
+ return dirsql
59
+
60
+
61
+ def timed(argv, cwd, timeout, env=None):
62
+ started = time.perf_counter()
63
+ proc = subprocess.run(
64
+ argv,
65
+ cwd=str(cwd),
66
+ stdin=subprocess.DEVNULL,
67
+ capture_output=True,
68
+ timeout=timeout,
69
+ env=env,
70
+ check=False,
71
+ )
72
+ seconds = time.perf_counter() - started
73
+ proc.stdout = proc.stdout.decode()
74
+ proc.stderr = proc.stderr.decode()
75
+ return proc, seconds
76
+
77
+
78
+ def timed_native(argv, cwd, timeout=600):
79
+ return timed(argv, cwd, timeout, env=NATIVE_ENV)
80
+
81
+
82
+ def median_after_first(samples):
83
+ return statistics.median(samples[1:])
84
+
85
+
86
+ def probe_seconds(argv, cwd, env=None) -> float:
87
+ samples = []
88
+ for _ in range(STARTUP_PROBES):
89
+ proc, seconds = timed(argv, cwd, timeout=60, env=env)
90
+ assert proc.returncode == 0, proc.stderr
91
+ samples.append(seconds)
92
+ return median_after_first(samples)
93
+
94
+
95
+ def startup_seconds(argv=None, cwd=None) -> Startup:
96
+ argv = [cli(), "query", "SELECT 1"] if argv is None else argv
97
+ with tempfile.TemporaryDirectory() as empty:
98
+ dirsql = probe_seconds(argv, cwd or empty)
99
+ native = probe_seconds(["bash", "-c", "true"], empty, NATIVE_ENV)
100
+ return Startup(dirsql, native)
101
+
102
+
103
+ def dirsql_rows(proc, columns):
104
+ assert proc.returncode == 0, (
105
+ f"dirsql failed: stdout={proc.stdout!r} stderr={proc.stderr!r}"
106
+ )
107
+ return [tuple(row[column] for column in columns) for row in json.loads(proc.stdout)]
108
+
109
+
110
+ def grow_until_native_takes_a_second(build, native, start, ceiling):
111
+ """Grow the corpus by doubling until `native` runs for a second.
112
+
113
+ `build(lo, hi)` adds items `lo` through `hi - 1` to the corpus already
114
+ holding `lo` items, so each doubling writes only the new half.
115
+ """
116
+ built, size = 0, start
117
+ while True:
118
+ build(built, size)
119
+ os.sync()
120
+ built = size
121
+ _, seconds = native()
122
+ if seconds >= ONE_SECOND or size >= ceiling:
123
+ return size
124
+ size *= 2
125
+
126
+
127
+ def dirsql_timeout(native_seconds: float) -> float:
128
+ return max(60.0, 30 * native_seconds)
129
+
130
+
131
+ def pair_ratios(native_seconds, dirsql_seconds, startup):
132
+ ratios = []
133
+ for native, dirsql in zip(native_seconds, dirsql_seconds):
134
+ net = native - startup.native
135
+ assert net > 0, (
136
+ f"native {native:.3f}s is under its startup {startup.native:.3f}s"
137
+ )
138
+ ratios.append((dirsql - startup.dirsql) / net)
139
+ return ratios
140
+
141
+
142
+ def is_hopeless(native, dirsql, startup):
143
+ return dirsql - startup.dirsql > 10 * TOLERANCE * (native - startup.native)
144
+
145
+
146
+ def run_or_fail(run, name):
147
+ try:
148
+ return run()
149
+ except subprocess.TimeoutExpired as expired:
150
+ raise AssertionError(
151
+ f"{name} did not finish within {expired.timeout:.0f}s"
152
+ ) from None
153
+
154
+
155
+ def paired(native, dirsql, startup, pairs=PAIRS):
156
+ """Alternate `native()` and `dirsql(timeout)`, native first on even pairs.
157
+
158
+ Both return `(rows, seconds)`. The first pair is a discarded warm-up that
159
+ also sets dirsql's timeout. A run that raises `TimeoutExpired` fails the
160
+ test at once. Three hopeless pairs in a row end the series early: noise
161
+ does not account for an order of magnitude, so more pairs cannot bring
162
+ the median under the bar.
163
+ """
164
+ native_rows, native_warm = run_or_fail(native, "native")
165
+ timeout = dirsql_timeout(native_warm)
166
+
167
+ def run_dirsql():
168
+ return run_or_fail(lambda: dirsql(timeout), "dirsql")
169
+
170
+ dirsql_rows_, _ = run_dirsql()
171
+ native_times, dirsql_times, streak = [], [], 0
172
+ for index in range(pairs):
173
+ if index % 2 == 0:
174
+ native_rows, native_seconds = run_or_fail(native, "native")
175
+ dirsql_rows_, dirsql_seconds = run_dirsql()
176
+ else:
177
+ dirsql_rows_, dirsql_seconds = run_dirsql()
178
+ native_rows, native_seconds = run_or_fail(native, "native")
179
+ native_times.append(native_seconds)
180
+ dirsql_times.append(dirsql_seconds)
181
+ streak = (
182
+ streak + 1 if is_hopeless(native_seconds, dirsql_seconds, startup) else 0
183
+ )
184
+ if streak == HOPELESS_STREAK:
185
+ break
186
+ return Paired(native_rows, dirsql_rows_, native_times, dirsql_times)
187
+
188
+
189
+ def summarize(ratios):
190
+ low, high = min(ratios), max(ratios)
191
+ median = statistics.median(ratios)
192
+ return low, median, high, (high - low) / median
193
+
194
+
195
+ def assert_speed_of_light(name, result, startup):
196
+ ratios = pair_ratios(result.native_seconds, result.dirsql_seconds, startup)
197
+ low, median, high, spread = summarize(ratios)
198
+ line = (
199
+ f"{name}: {len(ratios)} pairs, ratio min {low:.3f} median {median:.3f}"
200
+ f" max {high:.3f} spread {spread:.0%}, native median"
201
+ f" {statistics.median(result.native_seconds):.3f}s, startup"
202
+ f" dirsql {startup.dirsql:.3f}s native {startup.native:.3f}s"
203
+ )
204
+ print(f"SPEED {line}")
205
+ assert median <= TOLERANCE, f"{line}; median is over {TOLERANCE}x"
@@ -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.108"
9
+ version = "0.4.109"
10
10
  edition.workspace = true
11
11
  # Literal `license` (not `license.workspace = true`) because
12
12
  # putitoutthere's preflight check reads `[package].license` directly
@@ -779,7 +779,7 @@ impl Db {
779
779
  };
780
780
  let mut stored: Vec<(i64, Vec<Value>)> = Vec::new();
781
781
  {
782
- let mut stmt = self.conn.prepare(&select)?;
782
+ let mut stmt = self.conn.prepare_cached(&select)?;
783
783
  let mut cursor = stmt.query([])?;
784
784
  while let Some(row) = cursor.next()? {
785
785
  let cells = (0..columns.len())
@@ -655,15 +655,31 @@ impl DirSQL {
655
655
  /// the TypeScript binding).
656
656
  #[doc(hidden)]
657
657
  pub fn apply_file_events(&self, events: Vec<FileEvent>) -> Vec<RowEvent> {
658
+ self.apply_file_events_draining(events, Vec::new)
659
+ }
660
+
661
+ /// [`apply_file_events`](Self::apply_file_events), asking `late` for events
662
+ /// that arrived while the batch was being routed, until it returns none,
663
+ /// before any per-table hook runs. One write reaches the watcher as
664
+ /// several events; a hook run for the first would run again for the rest.
665
+ fn apply_file_events_draining(
666
+ &self,
667
+ events: Vec<FileEvent>,
668
+ mut late: impl FnMut() -> Vec<FileEvent>,
669
+ ) -> Vec<RowEvent> {
658
670
  let mut pending = PendingRefresh::default();
659
671
  let mut out = Vec::new();
660
672
  let mut rescan = false;
661
- for fe in events {
662
- if fe == FileEvent::Rescan {
663
- rescan = true;
664
- continue;
673
+ let mut batch = events;
674
+ while !batch.is_empty() {
675
+ for fe in batch {
676
+ if fe == FileEvent::Rescan {
677
+ rescan = true;
678
+ continue;
679
+ }
680
+ out.extend(self.route_file_event(fe, &mut pending));
665
681
  }
666
- out.extend(self.route_file_event(fe, &mut pending));
682
+ batch = late();
667
683
  }
668
684
  if rescan {
669
685
  out.extend(self.rescan(&mut pending));
@@ -710,7 +726,17 @@ impl DirSQL {
710
726
  events
711
727
  };
712
728
 
713
- Ok(self.apply_file_events(file_events))
729
+ Ok(self.apply_file_events_draining(file_events, || self.queued_file_events()))
730
+ }
731
+
732
+ /// The events the watcher already holds, without waiting for more.
733
+ fn queued_file_events(&self) -> Vec<FileEvent> {
734
+ self.inner
735
+ .watcher
736
+ .lock()
737
+ .ok()
738
+ .and_then(|guard| guard.as_ref().map(Watcher::try_recv_all))
739
+ .unwrap_or_default()
714
740
  }
715
741
 
716
742
  /// Process a single [`FileEvent`], mutating the DB and cache as needed.
@@ -4135,6 +4161,18 @@ mod internal_tests {
4135
4161
  assert!(e2.to_string().contains("watch() is active"), "got: {e2}");
4136
4162
  }
4137
4163
 
4164
+ #[test]
4165
+ fn queued_file_events_hands_over_what_the_watcher_holds_without_waiting() {
4166
+ let (dir, db) = simple_db();
4167
+ assert!(db.queued_file_events().is_empty(), "no watcher yet");
4168
+ db.start_watching().unwrap();
4169
+ std::fs::write(dir.path().join("a.none"), "x").unwrap();
4170
+ let mut held = Vec::new();
4171
+ while !held.iter().any(|e| matches!(e, FileEvent::Created(_))) {
4172
+ held.extend(db.queued_file_events());
4173
+ }
4174
+ }
4175
+
4138
4176
  #[test]
4139
4177
  fn poll_events_locks_out_watch() {
4140
4178
  let (_dir, db) = simple_db();
@@ -5503,6 +5541,31 @@ mod internal_tests {
5503
5541
  assert_eq!(row_names(&db), vec!["a.txt", "b.txt"]);
5504
5542
  }
5505
5543
 
5544
+ #[test]
5545
+ fn events_arriving_while_a_batch_is_routed_share_its_per_table_rerun() {
5546
+ let dir = TempDir::new().unwrap();
5547
+ let root = dir.path().to_path_buf();
5548
+ let a = root.join("a.txt");
5549
+ let b = root.join("b.txt");
5550
+ let fake = FakeFs::default().with_subtree(
5551
+ root.clone(),
5552
+ vec![(a.clone(), "items".into()), (b.clone(), "items".into())],
5553
+ );
5554
+ let (items, calls) = recording_per_table("items", "**/*.txt");
5555
+ let db =
5556
+ DirSQL::with_ignore_and_fs(&root, vec![items], Vec::<String>::new(), Arc::new(fake))
5557
+ .unwrap();
5558
+
5559
+ let mut arrivals = vec![vec![FileEvent::Modified(b.clone())]];
5560
+ let events = db.apply_file_events_draining(vec![FileEvent::Created(a.clone())], || {
5561
+ arrivals.pop().unwrap_or_default()
5562
+ });
5563
+
5564
+ assert_eq!(*calls.lock().unwrap(), vec![vec![a, b]]);
5565
+ assert_eq!(events.len(), 2);
5566
+ assert_eq!(row_names(&db), vec!["a.txt", "b.txt"]);
5567
+ }
5568
+
5506
5569
  #[test]
5507
5570
  fn apply_file_events_refreshes_a_per_table_hook_without_walking_the_tree() {
5508
5571
  let dir = TempDir::new().unwrap();
@@ -73,12 +73,16 @@ pub(crate) fn run_streaming(
73
73
  .iter()
74
74
  .map(|path| command::non_verbatim(&path.to_string_lossy()))
75
75
  .collect();
76
- let cpus = std::thread::available_parallelism().map_or(1, std::num::NonZero::get);
77
76
  let mut runs = chunks(&args, ARG_BUDGET.saturating_sub(argv_bytes(&argv)));
78
77
  if runs.len() == 1 {
79
- runs = spread(&args, &file_sizes(paths), cpus);
78
+ runs = spread_runs(&args, &file_sizes(paths), cpus);
80
79
  }
81
- let workers = cpus.min(runs.len());
80
+ if let [only] = runs.as_slice() {
81
+ let mut full = argv;
82
+ full.extend(only.iter().cloned());
83
+ return run_invocation(command, &full, cwd, &mut |rows| sink(rows));
84
+ }
85
+ let workers = cpus().min(runs.len());
82
86
 
83
87
  let next = AtomicUsize::new(0);
84
88
  let aborted = AtomicBool::new(false);
@@ -97,7 +101,7 @@ pub(crate) fn run_streaming(
97
101
  }
98
102
  let mut full = argv.clone();
99
103
  full.extend(runs[index].iter().cloned());
100
- let outcome = run_invocation(command, &full, cwd, &|rows| {
104
+ let outcome = run_invocation(command, &full, cwd, &mut |rows| {
101
105
  let _ = rows_tx.send(rows);
102
106
  });
103
107
  if let Err(message) = outcome {
@@ -134,7 +138,7 @@ fn run_invocation(
134
138
  command: &str,
135
139
  full: &[String],
136
140
  cwd: &Path,
137
- send: &dyn Fn(Vec<JsonRow>),
141
+ send: &mut dyn FnMut(Vec<JsonRow>),
138
142
  ) -> Result<(), String> {
139
143
  let mut bad_output: Option<String> = None;
140
144
  let mut lines_seen = 0usize;
@@ -208,6 +212,24 @@ fn chunks(args: &[String], budget: usize) -> Vec<&[String]> {
208
212
  /// another invocation costs more than it saves.
209
213
  const MIN_RUN_BYTES: u64 = 4 * 1024 * 1024;
210
214
 
215
+ fn cpus() -> usize {
216
+ std::thread::available_parallelism().map_or(1, std::num::NonZero::get)
217
+ }
218
+
219
+ /// [`spread`] over the machine's CPUs, asking for the count only when the
220
+ /// data could fill more than one run: the query reads cgroup files each time.
221
+ fn spread_runs<'a>(
222
+ args: &'a [String],
223
+ sizes: &[u64],
224
+ cpus: impl FnOnce() -> usize,
225
+ ) -> Vec<&'a [String]> {
226
+ let by_data = usize::try_from(sizes.iter().sum::<u64>() / MIN_RUN_BYTES).unwrap_or(usize::MAX);
227
+ if by_data.min(args.len()) <= 1 {
228
+ return vec![args];
229
+ }
230
+ spread(args, sizes, cpus())
231
+ }
232
+
211
233
  /// Each path's size in bytes; a path that cannot be read counts as empty.
212
234
  fn file_sizes(paths: &[PathBuf]) -> Vec<u64> {
213
235
  paths
@@ -423,6 +445,22 @@ mod tests {
423
445
  assert_eq!(lens(&spread(&args, &[mib; 4], 16)), [4]);
424
446
  }
425
447
 
448
+ #[test]
449
+ fn spread_runs_does_not_count_cpus_for_data_that_fits_one_run() {
450
+ let args = args(&["a", "b", "c", "d"]);
451
+ let mib = 1024 * 1024;
452
+ let runs = spread_runs(&args, &[mib; 4], || panic!("counted the cpus"));
453
+ assert_eq!(lens(&runs), [4]);
454
+ }
455
+
456
+ #[test]
457
+ fn spread_runs_counts_cpus_once_the_data_fills_more_than_one_run() {
458
+ let args = args(&["a", "b", "c", "d"]);
459
+ let mib = 1024 * 1024;
460
+ let runs = spread_runs(&args, &[8 * mib; 4], || 2);
461
+ assert_eq!(lens(&runs), [2, 2]);
462
+ }
463
+
426
464
  #[test]
427
465
  fn spread_isolates_a_dominant_file() {
428
466
  let args = args(&["a", "b", "c"]);
@@ -1,124 +0,0 @@
1
- """Harness for the use-case speed-of-light tests.
2
-
3
- Each use-case test asks one question of a generated corpus twice: once through
4
- the fastest native pipeline (find, sort, join, awk, a single parser process)
5
- and once through the real `dirsql` launcher. The rows must be identical and
6
- dirsql's wall time, after subtracting the launcher's measured startup, must be
7
- within ten percent of native. The bar is a ratio, never a millisecond number,
8
- so it holds on any machine.
9
-
10
- Startup is the mean of ten `dirsql --help` runs; `--help` and `SELECT 1` cost
11
- the same, so it stands in for the fixed per-invocation cost. A corpus too
12
- small to time is grown by doubling until the native pipeline takes at least a
13
- second, so the comparison is above the noise floor. Each side is run three
14
- times and the fastest run counts.
15
- """
16
-
17
- from __future__ import annotations
18
-
19
- import json
20
- import shutil
21
- import subprocess
22
- import time
23
-
24
- ONE_SECOND = 1.0
25
- TOLERANCE = 1.1
26
- STARTUP_PROBES = 10
27
- BEST_OF = 3
28
-
29
-
30
- def cli() -> str:
31
- dirsql = shutil.which("dirsql")
32
- assert dirsql is not None, (
33
- "`dirsql` console script not on PATH -- run `uv run maturin develop`"
34
- )
35
- return dirsql
36
-
37
-
38
- def timed(argv, cwd, timeout, env=None):
39
- started = time.perf_counter()
40
- proc = subprocess.run(
41
- argv,
42
- cwd=str(cwd),
43
- stdin=subprocess.DEVNULL,
44
- capture_output=True,
45
- text=True,
46
- timeout=timeout,
47
- env=env,
48
- check=False,
49
- )
50
- return proc, time.perf_counter() - started
51
-
52
-
53
- def startup_seconds(argv=None, cwd=None) -> float:
54
- argv = [cli(), "--help"] if argv is None else argv
55
- samples = []
56
- for _ in range(STARTUP_PROBES):
57
- proc, seconds = timed(argv, cwd or ".", timeout=60)
58
- assert proc.returncode == 0, proc.stderr
59
- samples.append(seconds)
60
- return sum(samples) / len(samples)
61
-
62
-
63
- def dirsql_rows(proc, columns):
64
- assert proc.returncode == 0, (
65
- f"dirsql failed: stdout={proc.stdout!r} stderr={proc.stderr!r}"
66
- )
67
- return [tuple(row[column] for column in columns) for row in json.loads(proc.stdout)]
68
-
69
-
70
- def grow_until_native_takes_a_second(build, native, start, ceiling):
71
- """Grow the corpus by doubling until `native` runs for a second.
72
-
73
- `build(lo, hi)` adds items `lo` through `hi - 1` to the corpus already
74
- holding `lo` items, so each doubling writes only the new half.
75
- """
76
- built, size = 0, start
77
- while True:
78
- build(built, size)
79
- built = size
80
- _, seconds = native()
81
- if seconds >= ONE_SECOND or size >= ceiling:
82
- return size
83
- size *= 2
84
-
85
-
86
- def best_of(run, name, hopeless=None):
87
- """Run `run` three times; return the rows and wall time of the fastest.
88
-
89
- `run` returns `(rows, seconds)`. A run that raises `TimeoutExpired` fails
90
- the test immediately with the timeout it blew through. A run slower than
91
- `hopeless` seconds ends the series early: noise does not account for an
92
- order of magnitude, so no retry could bring the best under the bar.
93
- """
94
- fastest = None
95
- for _ in range(BEST_OF):
96
- try:
97
- rows, seconds = run()
98
- except subprocess.TimeoutExpired as expired:
99
- raise AssertionError(
100
- f"{name} did not finish within {expired.timeout:.0f}s"
101
- ) from None
102
- if fastest is None or seconds < fastest[1]:
103
- fastest = (rows, seconds)
104
- if hopeless is not None and seconds > hopeless:
105
- break
106
- return fastest
107
-
108
-
109
- def hopeless_seconds(native_seconds: float, startup: float) -> float:
110
- return startup + 10 * TOLERANCE * native_seconds
111
-
112
-
113
- def dirsql_timeout(native_seconds: float) -> float:
114
- return max(60.0, 30 * native_seconds)
115
-
116
-
117
- def assert_speed_of_light(name, native_seconds, dirsql_seconds, startup):
118
- measured = dirsql_seconds - startup
119
- budget = TOLERANCE * native_seconds
120
- assert measured <= budget, (
121
- f"{name}: dirsql {dirsql_seconds:.3f}s minus startup {startup:.3f}s"
122
- f" = {measured:.3f}s, over {TOLERANCE}x native {native_seconds:.3f}s"
123
- f" = {budget:.3f}s"
124
- )
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