dirsql 0.3.124__tar.gz → 0.3.126__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 (207) hide show
  1. {dirsql-0.3.124 → dirsql-0.3.126}/Cargo.lock +1 -1
  2. {dirsql-0.3.124 → dirsql-0.3.126}/PKG-INFO +1 -1
  3. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/Cargo.toml +1 -1
  4. dirsql-0.3.126/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +3 -0
  5. dirsql-0.3.126/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +3 -0
  6. dirsql-0.3.126/packages/python/e2e-attestations/feat-634-slice4-hookless-error.json +7 -0
  7. dirsql-0.3.126/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +51 -0
  8. dirsql-0.3.126/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +51 -0
  9. dirsql-0.3.126/packages/rust/changelog.d/2026-07-24-hookless-table-config-error.md +3 -0
  10. dirsql-0.3.126/packages/rust/changelog.d/2026-07-24-remove-stat-fact-injection.md +3 -0
  11. dirsql-0.3.126/packages/rust/migrations.d/2026-07-24-hookless-table-config-error.md +51 -0
  12. dirsql-0.3.126/packages/rust/migrations.d/2026-07-24-remove-stat-fact-injection.md +55 -0
  13. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/config.rs +78 -26
  14. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/lib.rs +34 -117
  15. dirsql-0.3.124/packages/python/e2e-attestations/feat-634-prep-python-selfemit.json +0 -7
  16. dirsql-0.3.124/packages/python/e2e-attestations/feat-662-query-default-cli.json +0 -7
  17. {dirsql-0.3.124 → dirsql-0.3.126}/Cargo.toml +0 -0
  18. {dirsql-0.3.124 → dirsql-0.3.126}/README.md +0 -0
  19. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/__init__.py +0 -0
  20. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/_async.py +0 -0
  21. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/_dirsql.pyi +0 -0
  22. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/cli/__init__.py +0 -0
  23. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/cli/binary_path.py +0 -0
  24. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/cli/discover_plugins/__init__.py +0 -0
  25. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
  26. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
  27. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
  28. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
  29. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
  30. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/cli/is_windows.py +0 -0
  31. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/cli/main.py +0 -0
  32. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/cli/resolve_config_extensions.py +0 -0
  33. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/py.typed +0 -0
  34. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/resolve_config_extensions.py +0 -0
  35. {dirsql-0.3.124 → dirsql-0.3.126}/dirsql/resolve_extension.py +0 -0
  36. {dirsql-0.3.124 → dirsql-0.3.126}/docs/.claude/CLAUDE.md +0 -0
  37. {dirsql-0.3.124 → dirsql-0.3.126}/docs/.vitepress/config.ts +0 -0
  38. {dirsql-0.3.124 → dirsql-0.3.126}/docs/.vitepress/theme/index.ts +0 -0
  39. {dirsql-0.3.124 → dirsql-0.3.126}/docs/.vitepress/theme/lang.ts +0 -0
  40. {dirsql-0.3.124 → dirsql-0.3.126}/docs/AGENTS.md +0 -0
  41. {dirsql-0.3.124 → dirsql-0.3.126}/docs/explanation.md +0 -0
  42. {dirsql-0.3.124 → dirsql-0.3.126}/docs/getting-started.md +0 -0
  43. {dirsql-0.3.124 → dirsql-0.3.126}/docs/howto/columns-from-paths.md +0 -0
  44. {dirsql-0.3.124 → dirsql-0.3.126}/docs/howto/define-tables.md +0 -0
  45. {dirsql-0.3.124 → dirsql-0.3.126}/docs/howto/embed.md +0 -0
  46. {dirsql-0.3.124 → dirsql-0.3.126}/docs/howto/extract-from-contents.md +0 -0
  47. {dirsql-0.3.124 → dirsql-0.3.126}/docs/howto/load-extension.md +0 -0
  48. {dirsql-0.3.124 → dirsql-0.3.126}/docs/howto/parse-files-into-columns.md +0 -0
  49. {dirsql-0.3.124 → dirsql-0.3.126}/docs/howto/persist.md +0 -0
  50. {dirsql-0.3.124 → dirsql-0.3.126}/docs/howto/query-without-config.md +0 -0
  51. {dirsql-0.3.124 → dirsql-0.3.126}/docs/howto/react-to-changes.md +0 -0
  52. {dirsql-0.3.124 → dirsql-0.3.126}/docs/howto/search-by-meaning.md +0 -0
  53. {dirsql-0.3.124 → dirsql-0.3.126}/docs/howto/skip-files.md +0 -0
  54. {dirsql-0.3.124 → dirsql-0.3.126}/docs/howto/write-a-plugin.md +0 -0
  55. {dirsql-0.3.124 → dirsql-0.3.126}/docs/index.md +0 -0
  56. {dirsql-0.3.124 → dirsql-0.3.126}/docs/migrations.md +0 -0
  57. {dirsql-0.3.124 → dirsql-0.3.126}/docs/package.json +0 -0
  58. {dirsql-0.3.124 → dirsql-0.3.126}/docs/pnpm-lock.yaml +0 -0
  59. {dirsql-0.3.124 → dirsql-0.3.126}/docs/pnpm-workspace.yaml +0 -0
  60. {dirsql-0.3.124 → dirsql-0.3.126}/docs/reference/cli.md +0 -0
  61. {dirsql-0.3.124 → dirsql-0.3.126}/docs/reference/columns.md +0 -0
  62. {dirsql-0.3.124 → dirsql-0.3.126}/docs/reference/config.md +0 -0
  63. {dirsql-0.3.124 → dirsql-0.3.126}/docs/reference/hooks.md +0 -0
  64. {dirsql-0.3.124 → dirsql-0.3.126}/docs/reference/http-api.md +0 -0
  65. {dirsql-0.3.124 → dirsql-0.3.126}/docs/reference/path-tables.md +0 -0
  66. {dirsql-0.3.124 → dirsql-0.3.126}/docs/reference/sdk.md +0 -0
  67. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/CHANGELOG.md +0 -0
  68. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/MIGRATIONS.md +0 -0
  69. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/README.md +0 -0
  70. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  71. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
  72. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  73. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
  74. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  75. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  76. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  77. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/changelog.d/README.md +0 -0
  78. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/conftest.py +0 -0
  79. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/.claude/CLAUDE.md +0 -0
  80. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/.vitepress/config.ts +0 -0
  81. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  82. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  83. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/AGENTS.md +0 -0
  84. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/explanation.md +0 -0
  85. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/getting-started.md +0 -0
  86. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/howto/columns-from-paths.md +0 -0
  87. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/howto/define-tables.md +0 -0
  88. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/howto/embed.md +0 -0
  89. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/howto/extract-from-contents.md +0 -0
  90. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/howto/load-extension.md +0 -0
  91. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
  92. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/howto/persist.md +0 -0
  93. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/howto/query-without-config.md +0 -0
  94. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/howto/react-to-changes.md +0 -0
  95. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/howto/search-by-meaning.md +0 -0
  96. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/howto/skip-files.md +0 -0
  97. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/howto/write-a-plugin.md +0 -0
  98. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/index.md +0 -0
  99. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/migrations.md +0 -0
  100. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/package.json +0 -0
  101. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/pnpm-lock.yaml +0 -0
  102. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/pnpm-workspace.yaml +0 -0
  103. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/reference/cli.md +0 -0
  104. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/reference/columns.md +0 -0
  105. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/reference/config.md +0 -0
  106. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/reference/hooks.md +0 -0
  107. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/reference/http-api.md +0 -0
  108. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/reference/path-tables.md +0 -0
  109. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/docs/reference/sdk.md +0 -0
  110. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  111. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  112. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  113. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  114. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  115. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/migrations.d/README.md +0 -0
  116. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/src/lib.rs +0 -0
  117. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/tests/__init__.py +0 -0
  118. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/tests/conftest.py +0 -0
  119. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/tests/e2e/__init__.py +0 -0
  120. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
  121. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
  122. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/tests/integration/__init__.py +0 -0
  123. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/tests/integration/binding/__init__.py +0 -0
  124. {dirsql-0.3.124 → dirsql-0.3.126}/packages/python/tests/integration/hermetic/__init__.py +0 -0
  125. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/CHANGELOG.md +0 -0
  126. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/Cargo.toml +0 -0
  127. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/MIGRATIONS.md +0 -0
  128. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/README.md +0 -0
  129. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/benches/db_bench.rs +0 -0
  130. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/benches/differ_bench.rs +0 -0
  131. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/benches/matcher_bench.rs +0 -0
  132. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/benches/scanner_bench.rs +0 -0
  133. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-13-batch-ingest-transaction.md +0 -0
  134. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-13-chained-pre-post-query-hooks.md +0 -0
  135. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  136. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-13-fan-out-file-table-matching.md +0 -0
  137. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-13-persist-wal.md +0 -0
  138. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  139. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-13-repeatable-builder-config.md +0 -0
  140. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-13-repeatable-cli-config.md +0 -0
  141. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  142. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-13-subcommand-local-config-flags.md +0 -0
  143. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-19-path-table-query-fallback.md +0 -0
  144. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-19-path-table-vtab.md +0 -0
  145. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  146. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-20-path-table-glob-semantics.md +0 -0
  147. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-20-schema-inference.md +0 -0
  148. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-21-on-file-flag.md +0 -0
  149. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  150. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-23-init-escalation-example.md +0 -0
  151. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/2026-07-23-query-default-cli.md +0 -0
  152. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/changelog.d/README.md +0 -0
  153. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/explanation.md +0 -0
  154. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/getting-started.md +0 -0
  155. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/howto/columns-from-paths.md +0 -0
  156. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/howto/define-tables.md +0 -0
  157. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/howto/embed.md +0 -0
  158. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/howto/extract-from-contents.md +0 -0
  159. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/howto/load-extension.md +0 -0
  160. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
  161. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/howto/persist.md +0 -0
  162. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/howto/query-without-config.md +0 -0
  163. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/howto/react-to-changes.md +0 -0
  164. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/howto/search-by-meaning.md +0 -0
  165. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/howto/skip-files.md +0 -0
  166. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/howto/write-a-plugin.md +0 -0
  167. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/index.md +0 -0
  168. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/migrations.md +0 -0
  169. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/reference/cli.md +0 -0
  170. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/reference/columns.md +0 -0
  171. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/reference/config.md +0 -0
  172. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/reference/hooks.md +0 -0
  173. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/reference/http-api.md +0 -0
  174. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/reference/path-tables.md +0 -0
  175. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/docs/reference/sdk.md +0 -0
  176. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  177. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/migrations.d/2026-07-13-fan-out-file-table-matching.md +0 -0
  178. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/migrations.d/2026-07-13-persist-wal.md +0 -0
  179. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  180. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  181. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/migrations.d/2026-07-13-subcommand-local-config-flags.md +0 -0
  182. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  183. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/migrations.d/2026-07-20-path-table-glob-semantics.md +0 -0
  184. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  185. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/migrations.d/2026-07-23-init-escalation-example.md +0 -0
  186. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/migrations.d/2026-07-23-query-default-cli.md +0 -0
  187. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/migrations.d/README.md +0 -0
  188. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/bin/dirsql.rs +0 -0
  189. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/cli/execute.rs +0 -0
  190. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/cli/init.rs +0 -0
  191. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/cli/mod.rs +0 -0
  192. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/cli/router.rs +0 -0
  193. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/cli/serialize.rs +0 -0
  194. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/cli/server.rs +0 -0
  195. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/command.rs +0 -0
  196. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/db.rs +0 -0
  197. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/default_config.toml +0 -0
  198. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/differ.rs +0 -0
  199. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/infer.rs +0 -0
  200. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/matcher.rs +0 -0
  201. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/parsed_vtab.rs +0 -0
  202. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/path_table.rs +0 -0
  203. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/persist.rs +0 -0
  204. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/scanner.rs +0 -0
  205. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/vtab.rs +0 -0
  206. {dirsql-0.3.124 → dirsql-0.3.126}/packages/rust/src/watcher.rs +0 -0
  207. {dirsql-0.3.124 → dirsql-0.3.126}/pyproject.toml +0 -0
@@ -500,7 +500,7 @@ dependencies = [
500
500
 
501
501
  [[package]]
502
502
  name = "dirsql-py-ext"
503
- version = "0.3.124"
503
+ version = "0.3.126"
504
504
  dependencies = [
505
505
  "dirsql",
506
506
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dirsql
3
- Version: 0.3.124
3
+ Version: 0.3.126
4
4
  Summary: Ephemeral SQL index over a local directory
5
5
  Keywords: sql,filesystem,directory,sqlite,index
6
6
  Author: Kevin Scott
@@ -4,7 +4,7 @@ name = "dirsql-py-ext"
4
4
  # pypi/maturin handler can rewrite it via `write-version` before
5
5
  # `maturin build`. `pyproject.toml` declares `dynamic = ["version"]`
6
6
  # and maturin reads this field. Mirrors `packages/rust/Cargo.toml`.
7
- version = "0.3.124"
7
+ version = "0.3.126"
8
8
  # abi3 note: the `abi3-py311` pyo3 feature (below) builds ONE stable-ABI
9
9
  # `cp311-abi3` wheel per platform that loads on every CPython >= 3.11
10
10
  # (matching `pyproject.toml`'s `requires-python = ">=3.11"`), instead of
@@ -0,0 +1,3 @@
1
+ **Changed**
2
+
3
+ - **A `[[table]]` with no `on-file` hook is now a config-load error.** After the stat-fact injection layer was removed, a hook-less named table emitted no columns of its own, so every row was all-NULL. Loading such a config (`DirSQL(config=…)` / `.ready()`) now raises, with a message pointing at the fix: add an `on-file` hook that emits the columns, or, for stat columns with no code, query the path directly with a path-table (`FROM './'`). This completes the fact-removal epic (#624). (#634)
@@ -0,0 +1,3 @@
1
+ **Removed**
2
+
3
+ - **Removed the stat-fact injection layer** (core change, surfaced through the Python SDK). dirsql no longer auto-fills DDL columns named `path`/`basename`/`dir`/`ext`/`size`/`mtime`/`ctime` from filesystem stat. A `Table` now contains exactly what its `on_file` callback returns; a DDL column the callback never emits is `None`/`NULL`, not injected. To keep a stat column populated, emit it from the callback (e.g. derive `path` from the file argument), or query the path directly with a path-table (`FROM './'`). (#634)
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "just test-e2e",
3
+ "ran_at": 1784908753,
4
+ "exit_code": 0,
5
+ "commit": "f07fcf90987684b0edc4fd44f57f5003d329bd74",
6
+ "branch": "feat/634-slice4-hookless-error"
7
+ }
@@ -0,0 +1,51 @@
1
+ ### Hook-less `[[table]]` is now a config error (#634)
2
+
3
+ #### Summary
4
+
5
+ A `[[table]]` with no `on-file` hook previously loaded fine and — after the
6
+ stat-fact injection layer was removed — produced rows that were all-NULL.
7
+ Loading such a config through the Python SDK (`DirSQL(config=…)`, awaited via
8
+ `.ready()`) now raises. No API signature changes — this is a load-time
9
+ validation change surfaced from the core.
10
+
11
+ #### Required changes
12
+
13
+ | Before (loaded, all-NULL rows) | After (raises) | Fix |
14
+ | ------------------------------ | -------------- | --- |
15
+ | `.dirsql.toml` `[[table]]` with `ddl` + `glob` but no `on-file` | `.ready()` raises `[[table]] '<glob>' has no on-file hook …` | Add an `on-file` hook that emits the declared columns. |
16
+ | You only wanted stat columns and wrote no hook code | `.ready()` raises | Drop the `[[table]]` and query the path directly: `SELECT path, size, mtime FROM './'` (globbable: `FROM './**/*.md'`). |
17
+
18
+ #### Deprecations removed
19
+
20
+ _None._
21
+
22
+ #### Behavior changes without code changes
23
+
24
+ - A `[[table]]` with no `on-file` hook, which used to load (and, after injection
25
+ removal, yield all-NULL rows), now raises at config load, with an error naming
26
+ the offending glob and pointing at the `FROM './'` path-table replacement.
27
+
28
+ #### Verification
29
+
30
+ ```python
31
+ import asyncio
32
+ from dirsql import DirSQL
33
+
34
+ # .dirsql.toml with a hook-less table:
35
+ # [[table]]
36
+ # ddl = "CREATE TABLE files (path TEXT, size INTEGER)"
37
+ # glob = "**/*.md"
38
+
39
+ db = DirSQL(config=".dirsql.toml")
40
+ # Before this change: await db.ready() succeeded; SELECT * FROM files -> all-NULL rows.
41
+ # After this change:
42
+ try:
43
+ asyncio.run(db.ready())
44
+ except Exception as e:
45
+ print(e) # -> ... has no on-file hook ... query the path directly: `FROM './'`
46
+
47
+ # Replacement with no hook code — query the path directly (no config):
48
+ db2 = DirSQL(root=".")
49
+ asyncio.run(db2.ready())
50
+ print(asyncio.run(db2.query("SELECT path, size FROM './**/*.md'")))
51
+ ```
@@ -0,0 +1,51 @@
1
+ ### Stat-fact injection removed (#634)
2
+
3
+ #### Summary
4
+
5
+ dirsql previously injected filesystem-derived values into any DDL column named
6
+ `path`, `basename`, `dir`, `ext`, `size`, `mtime`, or `ctime` — filling them
7
+ even when a table's `on_file` callback emitted nothing for that column. That
8
+ injection layer (in the shared Rust core) is gone. A `Table` now contains
9
+ **exactly what its `on_file` callback returns**; a declared column the callback
10
+ never emits is `None`/`NULL`. No Python API signature changes — runtime
11
+ behavior only.
12
+
13
+ #### Required changes
14
+
15
+ | Before (injected) | After (NULL unless emitted) | Fix |
16
+ | ----------------- | --------------------------- | --- |
17
+ | DDL declares `path TEXT`, callback omits it → column held the root-relative path | Column is `None` | Emit it from the callback: `Table("CREATE TABLE t (path TEXT)", "**/*", on_file=lambda path: [{"path": path}])`. |
18
+ | DDL declares `size INTEGER`, callback omits it → column held the file size | Column is `None` | Emit it: `on_file=lambda path: [{"size": os.path.getsize(path)}]`. |
19
+ | Want stat columns with **no** callback at all | (was injection) | Query the path directly with a path-table: `FROM './'`. |
20
+
21
+ #### Deprecations removed
22
+
23
+ _None._
24
+
25
+ #### Behavior changes without code changes
26
+
27
+ - A DDL column named `path`/`basename`/`dir`/`ext`/`size`/`mtime`/`ctime` that
28
+ the `on_file` callback does not emit is now `None`/`NULL` instead of an
29
+ injected filesystem value.
30
+ - A **strict** table whose DDL declares such a column but whose callback does
31
+ not emit it now raises a schema-validation error rather than being silently
32
+ filled.
33
+
34
+ #### Verification
35
+
36
+ ```python
37
+ from dirsql import DirSQL, Table
38
+
39
+ # Callback emits only "size"; DDL also declares "path".
40
+ db = DirSQL(root, tables=[Table(
41
+ ddl="CREATE TABLE files (path TEXT, size INTEGER)",
42
+ glob="**/*.txt",
43
+ on_file=lambda _path: [{"size": 42}],
44
+ )])
45
+ rows = db.query("SELECT path, size FROM files")
46
+ # Before: rows[0]["path"] == "a.txt" (injected)
47
+ # After: rows[0]["path"] is None (not emitted)
48
+
49
+ # Restore by emitting it:
50
+ # on_file=lambda path: [{"path": path, "size": 42}]
51
+ ```
@@ -0,0 +1,3 @@
1
+ **Changed**
2
+
3
+ - **A `[[table]]` with no `on-file` hook is now a load error.** After the stat-fact injection layer was removed, a hook-less named table emitted no columns of its own, so every row was all-NULL — useless and surprising. `load_config_str` (and every path that loads a config, including `DirSQL::from_config_path` and the CLI's `-c`) now rejects such a table with a message pointing at the fix: add an `on-file` hook that emits the columns, or, for stat columns with no code, query the path directly with a path-table (`FROM './'`). This completes the fact-removal epic (#624). (#634)
@@ -0,0 +1,3 @@
1
+ **Removed**
2
+
3
+ - **Removed the stat-fact injection layer.** dirsql no longer auto-fills DDL columns named `path`/`basename`/`dir`/`ext`/`size`/`mtime`/`ctime` from filesystem stat. A named table now contains exactly what its `on-file` hook emits; a DDL column the hook never emits is `NULL` (standard SQL), not injected. To keep a stat column populated, emit it from the hook (e.g. derive `path` from the file argument), or query the path directly with a path-table (`FROM './'`). (#634)
@@ -0,0 +1,51 @@
1
+ ### Hook-less `[[table]]` is now a config error (#634)
2
+
3
+ #### Summary
4
+
5
+ A `[[table]]` (or SDK-registered table) with no `on-file` hook previously
6
+ loaded fine and — after the stat-fact injection layer was removed — produced
7
+ rows that were all-NULL. dirsql now rejects a hook-less table at config load
8
+ (`ConfigError::HooklessTable`), so the failure is loud and actionable instead
9
+ of a silently useless table. No API signature changes — this is a
10
+ load-time validation change. `TableConfig.on_file` is now `String` (was
11
+ `Option<String>`) since a parsed table always carries a hook.
12
+
13
+ #### Required changes
14
+
15
+ | Before (loaded, all-NULL rows) | After (load error) | Fix |
16
+ | ------------------------------ | ------------------ | --- |
17
+ | `[[table]]` declares `ddl` + `glob` but no `on-file` | Load fails: `[[table]] '<glob>' has no on-file hook …` | Add an `on-file` hook that emits the declared columns, e.g. `on-file = 'rel=${1#"$2"/}; jq -n --arg path "$rel" '\''[{path:$path}]'\'''`. |
18
+ | You only wanted stat columns and wrote no hook code | Load fails | Drop the `[[table]]` and query the path directly with a path-table: `SELECT path, size, mtime FROM './'` (globbable: `FROM './**/*.md'`). |
19
+
20
+ #### Deprecations removed
21
+
22
+ _None._
23
+
24
+ #### Behavior changes without code changes
25
+
26
+ - A `[[table]]` with no `on-file` hook, which used to load (and, after injection
27
+ removal, yield all-NULL rows), now fails at config load with an error naming
28
+ the offending glob and pointing at the `FROM './'` path-table replacement.
29
+
30
+ #### Verification
31
+
32
+ ```bash
33
+ # .dirsql.toml with a hook-less table:
34
+ # [[table]]
35
+ # ddl = "CREATE TABLE files (path TEXT, size INTEGER)"
36
+ # glob = "**/*.md"
37
+
38
+ # Before this change:
39
+ dirsql query "SELECT * FROM files" -c ./.dirsql.toml
40
+ # -> [] or all-NULL rows (loaded, but useless)
41
+
42
+ # After this change:
43
+ dirsql query "SELECT * FROM files" -c ./.dirsql.toml
44
+ # -> error: [[table]] '**/*.md' has no on-file hook, so every row would be
45
+ # all-NULL. Add an `on-file` hook that emits the columns, or, for stat
46
+ # columns with no code, query the path directly: `FROM './'`
47
+
48
+ # Replacement with no hook code — query the path directly:
49
+ dirsql query "SELECT path, size FROM './**/*.md'"
50
+ # -> rows with real path/size, no config needed
51
+ ```
@@ -0,0 +1,55 @@
1
+ ### Stat-fact injection removed (#634)
2
+
3
+ #### Summary
4
+
5
+ dirsql previously injected filesystem-derived values into any DDL column named
6
+ `path`, `basename`, `dir`, `ext`, `size`, `mtime`, or `ctime` — filling them
7
+ even when the `on-file` hook emitted nothing for that column. That injection
8
+ layer is gone. A named table now contains **exactly what its hook emits**; a
9
+ declared column the hook never emits is `NULL` (standard SQL). No API signature
10
+ changes — this is a runtime behavior change.
11
+
12
+ #### Required changes
13
+
14
+ | Before (injected) | After (NULL unless emitted) | Fix |
15
+ | ----------------- | --------------------------- | --- |
16
+ | DDL declares `path TEXT`, hook emits neither `path` nor a value for it → column held the root-relative path | Column is `NULL` | Emit it from the hook. Config `on-file` shell hook (`$1` = abs path, `$2` = index root): `rel=${1#"$2"/}; jq -n --arg path "$rel" '[{path:$path}]'`. Rust SDK closure: `\|path\| vec![HashMap::from([("path".into(), Value::Text(path.to_string()))])]`. |
17
+ | DDL declares `size INTEGER`, hook emits neither → column held the file size | Column is `NULL` | Emit it from the hook: `jq -n --argjson size "$(stat -c%s "$1")" '[{size:$size}]'`, or in Rust read `std::fs::metadata(path)?.len()`. |
18
+ | Want stat columns with **no** hook code at all | (was injection) | Query the path directly with a path-table: `FROM './'`. |
19
+
20
+ #### Deprecations removed
21
+
22
+ _None._
23
+
24
+ #### Behavior changes without code changes
25
+
26
+ - A DDL column named `path`/`basename`/`dir`/`ext`/`size`/`mtime`/`ctime` that
27
+ the `on-file` hook does not emit is now `NULL` instead of an injected
28
+ filesystem value. Configs and SDK tables that relied on injection must emit
29
+ the column themselves (see the table above).
30
+ - A **strict** table whose DDL declares such a column but whose hook does not
31
+ emit it now fails schema validation (`missing columns for table …`) rather
32
+ than being silently filled.
33
+
34
+ #### Verification
35
+
36
+ Given `a.txt` in the index root and a non-strict table whose DDL is
37
+ `CREATE TABLE files (path TEXT, size INTEGER)` and whose hook emits only
38
+ `size`:
39
+
40
+ ```bash
41
+ # Config flags follow the subcommand: `dirsql query <sql> -c <cfg>`.
42
+
43
+ # Before this change (hook emits only size):
44
+ dirsql query "SELECT path, size FROM files" -c ./.dirsql.toml
45
+ # -> [{"path":"a.txt","size":42}] (path injected)
46
+
47
+ # After this change (same config):
48
+ dirsql query "SELECT path, size FROM files" -c ./.dirsql.toml
49
+ # -> [{"path":null,"size":42}] (path NULL — not emitted)
50
+
51
+ # Restore it by emitting path from the hook:
52
+ # on-file = 'rel=${1#"$2"/}; jq -n --arg path "$rel" '\''[{path:$path}]'\'''
53
+ dirsql query "SELECT path, size FROM files" -c ./.dirsql.toml
54
+ # -> [{"path":"a.txt", ...}] (path populated again)
55
+ ```
@@ -21,6 +21,13 @@ pub enum ConfigError {
21
21
  #[error("Field '{0}' must not be empty")]
22
22
  EmptyField(&'static str),
23
23
 
24
+ #[error(
25
+ "[[table]] '{glob}' has no on-file hook, so every row would be all-NULL. \
26
+ Add an `on-file` hook that emits the columns, or, for stat columns with \
27
+ no code, query the path directly: `FROM './'`"
28
+ )]
29
+ HooklessTable { glob: String },
30
+
24
31
  #[error("Field '{field}' must be a positive number of seconds, got {value}")]
25
32
  InvalidTimeout { field: &'static str, value: i64 },
26
33
 
@@ -221,11 +228,12 @@ pub struct TableConfig {
221
228
  pub ddl: String,
222
229
  pub glob: String,
223
230
  pub strict: Option<bool>,
224
- /// Optional per-file command (`on-file`). When set, each matched file's
225
- /// rows come from running this command (which reads the file and prints a
226
- /// JSON array of row objects) instead of the empty filesystem-facts-only
227
- /// row. See `dirsql::command` for the execution contract.
228
- pub on_file: Option<String>,
231
+ /// The required per-file command (`on-file`). Each matched file's rows come
232
+ /// from running this command, which reads the file and prints a JSON array
233
+ /// of row objects. A table without it would emit no columns of its own
234
+ /// every row all-NULL — so it is rejected at load. See `dirsql::command`
235
+ /// for the execution contract.
236
+ pub on_file: String,
229
237
  }
230
238
 
231
239
  #[derive(Deserialize)]
@@ -323,7 +331,8 @@ pub fn load_config_str(content: &str) -> Result<Config> {
323
331
  Some(cmd) if cmd.trim().is_empty() => {
324
332
  return Err(ConfigError::EmptyField("on-file"));
325
333
  }
326
- other => other,
334
+ Some(cmd) => cmd,
335
+ None => return Err(ConfigError::HooklessTable { glob }),
327
336
  };
328
337
 
329
338
  tables.push(TableConfig {
@@ -367,10 +376,12 @@ ignore = ["node_modules/**", ".git/**"]
367
376
  [[table]]
368
377
  ddl = "CREATE TABLE comments (thread_id TEXT, path TEXT)"
369
378
  glob = "_comments/{thread_id}/index.jsonl"
379
+ on-file = "cat {path}"
370
380
 
371
381
  [[table]]
372
382
  ddl = "CREATE TABLE items (path TEXT, size INTEGER)"
373
383
  glob = "catalog/*.json"
384
+ on-file = "cat {path}"
374
385
  strict = true
375
386
  "#;
376
387
  let config = load_config_str(toml).unwrap();
@@ -391,6 +402,7 @@ strict = true
391
402
  let toml = r#"
392
403
  [[table]]
393
404
  glob = "*.json"
405
+ on-file = "cat {path}"
394
406
  "#;
395
407
  let err = load_config_str(toml).unwrap_err();
396
408
  assert!(err.to_string().contains("ddl"));
@@ -438,6 +450,7 @@ ignore = ["*.tmp"]
438
450
  [[table]]
439
451
  ddl = "CREATE TABLE t (x TEXT)"
440
452
  glob = "*.json"
453
+ on-file = "cat {path}"
441
454
  "#;
442
455
  let config = load_config_str(toml).unwrap();
443
456
  assert!(config.ignore.is_empty());
@@ -478,14 +491,17 @@ persist_path = "/var/cache/dirsql.db"
478
491
  [[table]]
479
492
  ddl = "CREATE TABLE a (path TEXT)"
480
493
  glob = "a/*.json"
494
+ on-file = "cat {path}"
481
495
 
482
496
  [[table]]
483
497
  ddl = "CREATE TABLE b (path TEXT)"
484
498
  glob = "b/*.csv"
499
+ on-file = "cat {path}"
485
500
 
486
501
  [[table]]
487
502
  ddl = "CREATE TABLE c (path TEXT)"
488
503
  glob = "c/*.yaml"
504
+ on-file = "cat {path}"
489
505
  "#;
490
506
  let config = load_config_str(toml).unwrap();
491
507
  assert_eq!(config.tables.len(), 3);
@@ -502,6 +518,7 @@ glob = "c/*.yaml"
502
518
  [[table]]
503
519
  ddl = "CREATE TABLE t (path TEXT)"
504
520
  glob = "*.json"
521
+ on-file = "cat {path}"
505
522
  format = "json"
506
523
  "#;
507
524
  let err = load_config_str(toml).unwrap_err();
@@ -568,6 +585,7 @@ entrypoint = "sqlite3_vec_init"
568
585
  [[table]]
569
586
  ddl = "CREATE TABLE t (path TEXT)"
570
587
  glob = "*.json"
588
+ on-file = "cat {path}"
571
589
  "#;
572
590
  let config = load_config_str(toml).unwrap();
573
591
  assert_eq!(config.extensions.len(), 1);
@@ -608,6 +626,7 @@ entrypoint = "sqlite3_x_init"
608
626
  [[table]]
609
627
  ddl = "CREATE TABLE t (path TEXT)"
610
628
  glob = "*.json"
629
+ on-file = "cat {path}"
611
630
  "#;
612
631
  let config = load_config_str(toml).unwrap();
613
632
  assert!(config.extensions.is_empty());
@@ -639,20 +658,26 @@ on-file = "uv run python extract_papers.py {path}"
639
658
  let config = load_config_str(toml).unwrap();
640
659
  assert_eq!(config.tables.len(), 1);
641
660
  assert_eq!(
642
- config.tables[0].on_file.as_deref(),
643
- Some("uv run python extract_papers.py {path}")
661
+ config.tables[0].on_file,
662
+ "uv run python extract_papers.py {path}"
644
663
  );
645
664
  }
646
665
 
647
666
  #[test]
648
- fn on_file_absent_is_none() {
667
+ fn on_file_absent_is_a_hookless_load_error() {
649
668
  let toml = r#"
650
669
  [[table]]
651
670
  ddl = "CREATE TABLE t (path TEXT)"
652
671
  glob = "*.json"
653
672
  "#;
654
- let config = load_config_str(toml).unwrap();
655
- assert!(config.tables[0].on_file.is_none());
673
+ let err = load_config_str(toml).unwrap_err();
674
+ assert!(
675
+ matches!(&err, ConfigError::HooklessTable { glob } if glob == "*.json"),
676
+ "got: {err:?}"
677
+ );
678
+ let msg = err.to_string();
679
+ assert!(msg.contains("on-file"), "got: {msg}");
680
+ assert!(msg.contains("FROM './'"), "got: {msg}");
656
681
  }
657
682
 
658
683
  #[test]
@@ -679,6 +704,7 @@ pre-query = "uv run python to_sql.py {args}"
679
704
  [[table]]
680
705
  ddl = "CREATE TABLE t (path TEXT)"
681
706
  glob = "*.json"
707
+ on-file = "cat {path}"
682
708
  "#;
683
709
  let config = load_config_str(toml).unwrap();
684
710
  assert_eq!(
@@ -693,6 +719,7 @@ glob = "*.json"
693
719
  [[table]]
694
720
  ddl = "CREATE TABLE t (path TEXT)"
695
721
  glob = "*.json"
722
+ on-file = "cat {path}"
696
723
  "#;
697
724
  let config = load_config_str(toml).unwrap();
698
725
  assert!(config.pre_query.is_none());
@@ -720,6 +747,7 @@ post-query = "jq '{results: .}'"
720
747
  [[table]]
721
748
  ddl = "CREATE TABLE t (path TEXT)"
722
749
  glob = "*.json"
750
+ on-file = "cat {path}"
723
751
  "#;
724
752
  let config = load_config_str(toml).unwrap();
725
753
  assert_eq!(config.post_query.as_deref(), Some("jq '{results: .}'"));
@@ -731,6 +759,7 @@ glob = "*.json"
731
759
  [[table]]
732
760
  ddl = "CREATE TABLE t (path TEXT)"
733
761
  glob = "*.json"
762
+ on-file = "cat {path}"
734
763
  "#;
735
764
  let config = load_config_str(toml).unwrap();
736
765
  assert!(config.post_query.is_none());
@@ -778,6 +807,7 @@ entrypoint = "sqlite3_vec_init"
778
807
  [[table]]
779
808
  ddl = "CREATE TABLE t (path TEXT)"
780
809
  glob = "*.json"
810
+ on-file = "cat {path}"
781
811
  "#);
782
812
  let merged = combine_configs(&[(src("/proj/.dirsql.toml"), config.clone())]).unwrap();
783
813
  assert_eq!(merged.ignore, config.ignore);
@@ -795,15 +825,18 @@ glob = "*.json"
795
825
  [[table]]
796
826
  ddl = "CREATE TABLE a (path TEXT)"
797
827
  glob = "a/*.json"
828
+ on-file = "cat {path}"
798
829
 
799
830
  [[table]]
800
831
  ddl = "CREATE TABLE b (path TEXT)"
801
832
  glob = "b/*.json"
833
+ on-file = "cat {path}"
802
834
  "#);
803
835
  let b = cfg(r#"
804
836
  [[table]]
805
837
  ddl = "CREATE TABLE c (path TEXT)"
806
838
  glob = "c/*.json"
839
+ on-file = "cat {path}"
807
840
  "#);
808
841
  let merged = combine_configs(&[(src("/a"), a), (src("/b"), b)]).unwrap();
809
842
  let ddls: Vec<&str> = merged.tables.iter().map(|t| t.ddl.as_str()).collect();
@@ -848,8 +881,12 @@ glob = "c/*.json"
848
881
 
849
882
  #[test]
850
883
  fn combine_duplicate_table_name_errors_naming_both_sources() {
851
- let a = cfg("[[table]]\nddl = \"CREATE TABLE t (x TEXT)\"\nglob = \"a/*.json\"\n");
852
- let b = cfg("[[table]]\nddl = \"CREATE TABLE t (y TEXT)\"\nglob = \"b/*.json\"\n");
884
+ let a = cfg(
885
+ "[[table]]\nddl = \"CREATE TABLE t (x TEXT)\"\nglob = \"a/*.json\"\non-file = \"cat {path}\"\n",
886
+ );
887
+ let b = cfg(
888
+ "[[table]]\nddl = \"CREATE TABLE t (y TEXT)\"\nglob = \"b/*.json\"\non-file = \"cat {path}\"\n",
889
+ );
853
890
  let err = combine_configs(&[
854
891
  (src("/proj/.dirsql.toml"), a),
855
892
  (src("/plugin/frag.toml"), b),
@@ -878,8 +915,8 @@ glob = "c/*.json"
878
915
  // The single-entry identity path runs no collision check, exactly like
879
916
  // a plain single-config load.
880
917
  let config = cfg(concat!(
881
- "[[table]]\nddl = \"CREATE TABLE t (x TEXT)\"\nglob = \"a/*.json\"\n",
882
- "[[table]]\nddl = \"CREATE TABLE t (y TEXT)\"\nglob = \"b/*.json\"\n",
918
+ "[[table]]\nddl = \"CREATE TABLE t (x TEXT)\"\nglob = \"a/*.json\"\non-file = \"cat {path}\"\n",
919
+ "[[table]]\nddl = \"CREATE TABLE t (y TEXT)\"\nglob = \"b/*.json\"\non-file = \"cat {path}\"\n",
883
920
  ));
884
921
  let merged = combine_configs(&[(src("/a"), config)]).unwrap();
885
922
  assert_eq!(merged.tables.len(), 2);
@@ -888,8 +925,8 @@ glob = "c/*.json"
888
925
  #[test]
889
926
  fn combine_intra_config_duplicate_in_multi_merge_errors() {
890
927
  let a = cfg(concat!(
891
- "[[table]]\nddl = \"CREATE TABLE t (x TEXT)\"\nglob = \"a/*.json\"\n",
892
- "[[table]]\nddl = \"CREATE TABLE t (y TEXT)\"\nglob = \"b/*.json\"\n",
928
+ "[[table]]\nddl = \"CREATE TABLE t (x TEXT)\"\nglob = \"a/*.json\"\non-file = \"cat {path}\"\n",
929
+ "[[table]]\nddl = \"CREATE TABLE t (y TEXT)\"\nglob = \"b/*.json\"\non-file = \"cat {path}\"\n",
893
930
  ));
894
931
  let b = cfg("[dirsql]\nignore = [\"c/**\"]\n");
895
932
  let err = combine_configs(&[(src("/a"), a), (src("/b"), b)]).unwrap_err();
@@ -909,8 +946,12 @@ glob = "c/*.json"
909
946
 
910
947
  #[test]
911
948
  fn combine_duplicate_table_name_detected_through_quoting() {
912
- let a = cfg("[[table]]\nddl = 'CREATE TABLE \"t\" (x TEXT)'\nglob = \"a/*.json\"\n");
913
- let b = cfg("[[table]]\nddl = \"CREATE TABLE t (y TEXT)\"\nglob = \"b/*.json\"\n");
949
+ let a = cfg(
950
+ "[[table]]\nddl = 'CREATE TABLE \"t\" (x TEXT)'\nglob = \"a/*.json\"\non-file = \"cat {path}\"\n",
951
+ );
952
+ let b = cfg(
953
+ "[[table]]\nddl = \"CREATE TABLE t (y TEXT)\"\nglob = \"b/*.json\"\non-file = \"cat {path}\"\n",
954
+ );
914
955
  let err = combine_configs(&[(src("/a"), a), (src("/b"), b)]).unwrap_err();
915
956
  assert!(
916
957
  matches!(&err, ConfigError::DuplicateTable { name, .. } if name == "t"),
@@ -920,8 +961,12 @@ glob = "c/*.json"
920
961
 
921
962
  #[test]
922
963
  fn combine_unparseable_ddl_concatenates_without_collision_check() {
923
- let a = cfg("[[table]]\nddl = \"not a create table\"\nglob = \"a/*.json\"\n");
924
- let b = cfg("[[table]]\nddl = \"also not a create table\"\nglob = \"b/*.json\"\n");
964
+ let a = cfg(
965
+ "[[table]]\nddl = \"not a create table\"\nglob = \"a/*.json\"\non-file = \"cat {path}\"\n",
966
+ );
967
+ let b = cfg(
968
+ "[[table]]\nddl = \"also not a create table\"\nglob = \"b/*.json\"\non-file = \"cat {path}\"\n",
969
+ );
925
970
  let merged = combine_configs(&[(src("/a"), a), (src("/b"), b)]).unwrap();
926
971
  assert_eq!(merged.tables.len(), 2);
927
972
  }
@@ -967,8 +1012,12 @@ glob = "c/*.json"
967
1012
 
968
1013
  #[test]
969
1014
  fn combine_error_display_includes_package_source_verbatim() {
970
- let a = cfg("[[table]]\nddl = \"CREATE TABLE t (x TEXT)\"\nglob = \"a/*.json\"\n");
971
- let b = cfg("[[table]]\nddl = \"CREATE TABLE t (y TEXT)\"\nglob = \"b/*.json\"\n");
1015
+ let a = cfg(
1016
+ "[[table]]\nddl = \"CREATE TABLE t (x TEXT)\"\nglob = \"a/*.json\"\non-file = \"cat {path}\"\n",
1017
+ );
1018
+ let b = cfg(
1019
+ "[[table]]\nddl = \"CREATE TABLE t (y TEXT)\"\nglob = \"b/*.json\"\non-file = \"cat {path}\"\n",
1020
+ );
972
1021
  let err = combine_configs(&[
973
1022
  (src("/proj/.dirsql.toml"), a),
974
1023
  (Source::Package("dirsql-plugin-notes".to_string()), b),
@@ -982,11 +1031,13 @@ glob = "c/*.json"
982
1031
  #[test]
983
1032
  fn combine_three_configs_concatenates_across_all() {
984
1033
  let a = cfg(
985
- "[dirsql]\nignore = [\"a/**\"]\n\n[[table]]\nddl = \"CREATE TABLE a (x TEXT)\"\nglob = \"a/*\"\n",
1034
+ "[dirsql]\nignore = [\"a/**\"]\n\n[[table]]\nddl = \"CREATE TABLE a (x TEXT)\"\nglob = \"a/*\"\non-file = \"cat {path}\"\n",
1035
+ );
1036
+ let b = cfg(
1037
+ "[[table]]\nddl = \"CREATE TABLE b (x TEXT)\"\nglob = \"b/*\"\non-file = \"cat {path}\"\n",
986
1038
  );
987
- let b = cfg("[[table]]\nddl = \"CREATE TABLE b (x TEXT)\"\nglob = \"b/*\"\n");
988
1039
  let c = cfg(
989
- "[dirsql]\nignore = [\"c/**\"]\n\n[[table]]\nddl = \"CREATE TABLE c (x TEXT)\"\nglob = \"c/*\"\n",
1040
+ "[dirsql]\nignore = [\"c/**\"]\n\n[[table]]\nddl = \"CREATE TABLE c (x TEXT)\"\nglob = \"c/*\"\non-file = \"cat {path}\"\n",
990
1041
  );
991
1042
  let merged = combine_configs(&[(src("/a"), a), (src("/b"), b), (src("/c"), c)]).unwrap();
992
1043
  assert_eq!(merged.ignore, vec!["a/**", "c/**"]);
@@ -1026,6 +1077,7 @@ hook-timeout = 300
1026
1077
  [[table]]
1027
1078
  ddl = "CREATE TABLE t (x TEXT)"
1028
1079
  glob = "*.json"
1080
+ on-file = "cat {path}"
1029
1081
  "#;
1030
1082
  let config = load_config_str(toml).unwrap();
1031
1083
  assert!(config.hook_timeout.is_none());