dirsql 0.4.24__tar.gz → 0.4.26__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 (191) hide show
  1. {dirsql-0.4.24 → dirsql-0.4.26}/Cargo.lock +1 -1
  2. {dirsql-0.4.24 → dirsql-0.4.26}/PKG-INFO +1 -1
  3. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/_dirsql.pyi +2 -0
  4. {dirsql-0.4.24 → dirsql-0.4.26}/docs/getting-started.md +1 -0
  5. {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/columns-from-paths.md +1 -0
  6. {dirsql-0.4.24/packages/python → dirsql-0.4.26}/docs/howto/define-tables.md +1 -0
  7. {dirsql-0.4.24/packages/python → dirsql-0.4.26}/docs/howto/embed.md +3 -0
  8. {dirsql-0.4.24/packages/rust → dirsql-0.4.26}/docs/howto/extract-from-contents.md +2 -0
  9. {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/parse-files-into-columns.md +1 -0
  10. {dirsql-0.4.24/packages/python → dirsql-0.4.26}/docs/howto/react-to-changes.md +1 -0
  11. {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/skip-files.md +1 -0
  12. {dirsql-0.4.24/packages/rust → dirsql-0.4.26}/docs/howto/write-a-plugin.md +1 -0
  13. {dirsql-0.4.24/packages/rust → dirsql-0.4.26}/docs/index.md +3 -0
  14. {dirsql-0.4.24/packages/rust → dirsql-0.4.26}/docs/reference/config.md +16 -2
  15. {dirsql-0.4.24 → dirsql-0.4.26}/docs/reference/sdk.md +11 -8
  16. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/Cargo.toml +1 -1
  17. dirsql-0.4.26/packages/python/changelog.d/2026-08-20-declared-table-name.md +3 -0
  18. {dirsql-0.4.24/packages/rust → dirsql-0.4.26/packages/python}/docs/getting-started.md +1 -0
  19. {dirsql-0.4.24/packages/rust → dirsql-0.4.26/packages/python}/docs/howto/columns-from-paths.md +1 -0
  20. {dirsql-0.4.24 → dirsql-0.4.26/packages/python}/docs/howto/define-tables.md +1 -0
  21. {dirsql-0.4.24 → dirsql-0.4.26/packages/python}/docs/howto/embed.md +3 -0
  22. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/howto/extract-from-contents.md +2 -0
  23. {dirsql-0.4.24/packages/rust → dirsql-0.4.26/packages/python}/docs/howto/parse-files-into-columns.md +1 -0
  24. {dirsql-0.4.24/packages/rust → dirsql-0.4.26/packages/python}/docs/howto/react-to-changes.md +1 -0
  25. {dirsql-0.4.24/packages/rust → dirsql-0.4.26/packages/python}/docs/howto/skip-files.md +1 -0
  26. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/howto/write-a-plugin.md +1 -0
  27. {dirsql-0.4.24 → dirsql-0.4.26/packages/python}/docs/index.md +3 -0
  28. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/reference/config.md +16 -2
  29. {dirsql-0.4.24/packages/rust → dirsql-0.4.26/packages/python}/docs/reference/sdk.md +11 -8
  30. dirsql-0.4.26/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +7 -0
  31. dirsql-0.4.26/packages/python/migrations.d/2026-08-20-declared-table-name.md +52 -0
  32. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/src/lib.rs +8 -12
  33. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +1 -0
  34. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/benches/db_bench.rs +20 -8
  35. {dirsql-0.4.24/packages/python → dirsql-0.4.26/packages/rust}/docs/getting-started.md +1 -0
  36. {dirsql-0.4.24/packages/python → dirsql-0.4.26/packages/rust}/docs/howto/columns-from-paths.md +1 -0
  37. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/howto/define-tables.md +1 -0
  38. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/howto/embed.md +3 -0
  39. {dirsql-0.4.24 → dirsql-0.4.26/packages/rust}/docs/howto/extract-from-contents.md +2 -0
  40. {dirsql-0.4.24/packages/python → dirsql-0.4.26/packages/rust}/docs/howto/parse-files-into-columns.md +1 -0
  41. {dirsql-0.4.24 → dirsql-0.4.26/packages/rust}/docs/howto/react-to-changes.md +1 -0
  42. {dirsql-0.4.24/packages/python → dirsql-0.4.26/packages/rust}/docs/howto/skip-files.md +1 -0
  43. {dirsql-0.4.24 → dirsql-0.4.26/packages/rust}/docs/howto/write-a-plugin.md +1 -0
  44. {dirsql-0.4.24/packages/python → dirsql-0.4.26/packages/rust}/docs/index.md +3 -0
  45. {dirsql-0.4.24 → dirsql-0.4.26/packages/rust}/docs/reference/config.md +16 -2
  46. {dirsql-0.4.24/packages/python → dirsql-0.4.26/packages/rust}/docs/reference/sdk.md +11 -8
  47. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/cli/run.rs +1 -0
  48. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/config.rs +93 -32
  49. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/db.rs +70 -351
  50. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/default_config.toml +4 -0
  51. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/lib.rs +96 -27
  52. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/persist.rs +10 -8
  53. {dirsql-0.4.24 → dirsql-0.4.26}/Cargo.toml +0 -0
  54. {dirsql-0.4.24 → dirsql-0.4.26}/README.md +0 -0
  55. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/__init__.py +0 -0
  56. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/_async.py +0 -0
  57. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/__init__.py +0 -0
  58. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/discover_plugins/__init__.py +0 -0
  59. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
  60. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
  61. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
  62. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
  63. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
  64. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/main.py +0 -0
  65. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/resolve_config_extensions.py +0 -0
  66. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/py.typed +0 -0
  67. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/resolve_config_extensions.py +0 -0
  68. {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/resolve_extension.py +0 -0
  69. {dirsql-0.4.24 → dirsql-0.4.26}/docs/.claude/CLAUDE.md +0 -0
  70. {dirsql-0.4.24 → dirsql-0.4.26}/docs/.vitepress/config.ts +0 -0
  71. {dirsql-0.4.24 → dirsql-0.4.26}/docs/.vitepress/theme/index.ts +0 -0
  72. {dirsql-0.4.24 → dirsql-0.4.26}/docs/.vitepress/theme/lang.ts +0 -0
  73. {dirsql-0.4.24 → dirsql-0.4.26}/docs/AGENTS.md +0 -0
  74. {dirsql-0.4.24 → dirsql-0.4.26}/docs/explanation.md +0 -0
  75. {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/load-extension.md +0 -0
  76. {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/persist.md +0 -0
  77. {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/query-json.md +0 -0
  78. {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/query-without-config.md +0 -0
  79. {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/search-by-meaning.md +0 -0
  80. {dirsql-0.4.24 → dirsql-0.4.26}/docs/package.json +0 -0
  81. {dirsql-0.4.24 → dirsql-0.4.26}/docs/plugins.md +0 -0
  82. {dirsql-0.4.24 → dirsql-0.4.26}/docs/pnpm-lock.yaml +0 -0
  83. {dirsql-0.4.24 → dirsql-0.4.26}/docs/pnpm-workspace.yaml +0 -0
  84. {dirsql-0.4.24 → dirsql-0.4.26}/docs/reference/cli.md +0 -0
  85. {dirsql-0.4.24 → dirsql-0.4.26}/docs/reference/columns.md +0 -0
  86. {dirsql-0.4.24 → dirsql-0.4.26}/docs/reference/hooks.md +0 -0
  87. {dirsql-0.4.24 → dirsql-0.4.26}/docs/reference/http-api.md +0 -0
  88. {dirsql-0.4.24 → dirsql-0.4.26}/docs/reference/path-tables.md +0 -0
  89. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/CHANGELOG.md +0 -0
  90. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/MIGRATIONS.md +0 -0
  91. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/README.md +0 -0
  92. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  93. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
  94. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  95. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
  96. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  97. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  98. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  99. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
  100. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  101. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
  102. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
  103. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
  104. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
  105. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
  106. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
  107. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
  108. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
  109. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/README.md +0 -0
  110. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/conftest.py +0 -0
  111. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/.claude/CLAUDE.md +0 -0
  112. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/.vitepress/config.ts +0 -0
  113. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  114. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  115. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/AGENTS.md +0 -0
  116. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/explanation.md +0 -0
  117. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/howto/load-extension.md +0 -0
  118. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/howto/persist.md +0 -0
  119. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/howto/query-json.md +0 -0
  120. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/howto/query-without-config.md +0 -0
  121. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/howto/search-by-meaning.md +0 -0
  122. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/package.json +0 -0
  123. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/plugins.md +0 -0
  124. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/pnpm-lock.yaml +0 -0
  125. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/pnpm-workspace.yaml +0 -0
  126. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/reference/cli.md +0 -0
  127. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/reference/columns.md +0 -0
  128. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/reference/hooks.md +0 -0
  129. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/reference/http-api.md +0 -0
  130. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/reference/path-tables.md +0 -0
  131. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
  132. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
  133. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
  134. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
  135. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  136. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  137. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  138. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  139. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  140. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
  141. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  142. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
  143. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
  144. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/README.md +0 -0
  145. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/testing-conventions.toml +0 -0
  146. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/__init__.py +0 -0
  147. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/conftest.py +0 -0
  148. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/e2e/__init__.py +0 -0
  149. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
  150. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/integration/__init__.py +0 -0
  151. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/integration/binding/__init__.py +0 -0
  152. {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/integration/hermetic/__init__.py +0 -0
  153. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/CHANGELOG.md +0 -0
  154. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/Cargo.toml +0 -0
  155. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/MIGRATIONS.md +0 -0
  156. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/README.md +0 -0
  157. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/benches/differ_bench.rs +0 -0
  158. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/benches/matcher_bench.rs +0 -0
  159. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/benches/scanner_bench.rs +0 -0
  160. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/explanation.md +0 -0
  161. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/howto/load-extension.md +0 -0
  162. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/howto/persist.md +0 -0
  163. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/howto/query-json.md +0 -0
  164. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/howto/query-without-config.md +0 -0
  165. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/howto/search-by-meaning.md +0 -0
  166. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/plugins.md +0 -0
  167. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/reference/cli.md +0 -0
  168. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/reference/columns.md +0 -0
  169. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/reference/hooks.md +0 -0
  170. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/reference/http-api.md +0 -0
  171. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/reference/path-tables.md +0 -0
  172. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/bin/dirsql.rs +0 -0
  173. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/cli/execute.rs +0 -0
  174. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/cli/init.rs +0 -0
  175. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/cli/mod.rs +0 -0
  176. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/cli/router.rs +0 -0
  177. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/cli/serialize.rs +0 -0
  178. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/cli/server.rs +0 -0
  179. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/command.rs +0 -0
  180. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/differ.rs +0 -0
  181. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/functions.rs +0 -0
  182. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/infer.rs +0 -0
  183. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/matcher.rs +0 -0
  184. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/parsed_cache.rs +0 -0
  185. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/parsed_vtab.rs +0 -0
  186. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/path_table.rs +0 -0
  187. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/scanner.rs +0 -0
  188. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/sql_literal.rs +0 -0
  189. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/vtab.rs +0 -0
  190. {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/watcher.rs +0 -0
  191. {dirsql-0.4.24 → dirsql-0.4.26}/pyproject.toml +0 -0
@@ -499,7 +499,7 @@ dependencies = [
499
499
 
500
500
  [[package]]
501
501
  name = "dirsql-py-ext"
502
- version = "0.4.24"
502
+ version = "0.4.26"
503
503
  dependencies = [
504
504
  "dirsql",
505
505
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dirsql
3
- Version: 0.4.24
3
+ Version: 0.4.26
4
4
  Requires-Dist: tomli>=2 ; python_full_version < '3.11'
5
5
  Requires-Dist: bin-shim>=0.1
6
6
  Summary: Ephemeral SQL index over a local directory
@@ -30,6 +30,7 @@ class ExtensionSpec(TypedDict):
30
30
  class Table:
31
31
  """A table definition. Construct via keyword arguments only."""
32
32
 
33
+ name: str
33
34
  ddl: str
34
35
  glob: str
35
36
  strict: bool
@@ -37,6 +38,7 @@ class Table:
37
38
  def __init__(
38
39
  self,
39
40
  *,
41
+ name: str,
40
42
  ddl: str,
41
43
  glob: str,
42
44
  on_file: Callable[[str], list[Row]],
@@ -164,6 +164,7 @@ Now create a `.dirsql.toml` that points a table at it:
164
164
  ```bash
165
165
  cat > .dirsql.toml <<'EOF'
166
166
  [[table]]
167
+ name = "notes"
167
168
  ddl = "CREATE TABLE notes (title TEXT, author TEXT)"
168
169
  glob = "notes/**/*.md"
169
170
  on-file = "sh note.sh {path}"
@@ -33,6 +33,7 @@ Point a table at it in `.dirsql.toml`:
33
33
 
34
34
  ```toml
35
35
  [[table]]
36
+ name = "photos"
36
37
  ddl = "CREATE TABLE photos (year TEXT, month TEXT, basename TEXT)"
37
38
  glob = "photos/*/*/*.jpg"
38
39
  on-file = "python3 pathcols.py {path}"
@@ -26,6 +26,7 @@ Then declare the table in `.dirsql.toml`:
26
26
 
27
27
  ```toml
28
28
  [[table]]
29
+ name = "posts"
29
30
  ddl = "CREATE TABLE posts (title TEXT, slug TEXT)"
30
31
  glob = "posts/**/*.md"
31
32
  on-file = "python3 extract.py {path}"
@@ -60,6 +60,7 @@ async def main() -> None:
60
60
  "./comments-root",
61
61
  tables=[
62
62
  Table(
63
+ name="comments",
63
64
  ddl="CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
64
65
  glob="comments/*/*.json",
65
66
  on_file=on_file,
@@ -83,6 +84,7 @@ const db = new DirSQL({
83
84
  root: "./comments-root",
84
85
  tables: [
85
86
  {
87
+ name: "comments",
86
88
  ddl: "CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
87
89
  glob: "comments/*/*.json",
88
90
  onFile: (path) => [
@@ -129,6 +131,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
129
131
  let db = DirSQL::builder()
130
132
  .root("./comments-root")
131
133
  .table(Table::new(
134
+ "comments",
132
135
  "CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
133
136
  "comments/*/*.json",
134
137
  on_file,
@@ -18,6 +18,7 @@ stdout works. With [`jq`](https://jqlang.org/):
18
18
 
19
19
  ```toml
20
20
  [[table]]
21
+ name = "books"
21
22
  ddl = "CREATE TABLE books (title TEXT, author TEXT, year INTEGER)"
22
23
  glob = "books/*.json"
23
24
  on-file = "jq -c '[{title, author, year}]' {path}"
@@ -53,6 +54,7 @@ row per line, slurp it:
53
54
 
54
55
  ```toml
55
56
  [[table]]
57
+ name = "events"
56
58
  ddl = "CREATE TABLE events (event TEXT, user TEXT)"
57
59
  glob = "logs/*.jsonl"
58
60
  on-file = "jq -c -s '.' {path}"
@@ -84,6 +84,7 @@ command in verbatim:
84
84
 
85
85
  ```toml
86
86
  [[table]]
87
+ name = "posts"
87
88
  ddl = "CREATE TABLE posts (title TEXT, author TEXT)"
88
89
  glob = "posts/*.md"
89
90
  on-file = "python3 extract.py {path}"
@@ -14,6 +14,7 @@ prints each file's basename:
14
14
  ```toml
15
15
  # .dirsql.toml
16
16
  [[table]]
17
+ name = "files"
17
18
  ddl = "CREATE TABLE files (basename TEXT)"
18
19
  glob = "**/*"
19
20
  on-file = '''sh -c 'printf "[{\"basename\":\"%s\"}]" "${1##*/}"' sh {path}'''
@@ -22,6 +22,7 @@ Exclude the noise in `.dirsql.toml`:
22
22
  ignore = ["notes/drafts/**", "**/*.tmp"]
23
23
 
24
24
  [[table]]
25
+ name = "notes"
25
26
  ddl = "CREATE TABLE notes (basename TEXT)"
26
27
  glob = "notes/**/*"
27
28
  on-file = '''sh -c 'printf "[{\"basename\":\"%s\"}]" "${1##*/}"' sh {path}'''
@@ -108,6 +108,7 @@ path = "sqlite_vec"
108
108
  entrypoint = "sqlite3_vec_init"
109
109
 
110
110
  [[table]]
111
+ name = "notes"
111
112
  ddl = "CREATE TABLE notes (path TEXT, text TEXT, embedding TEXT)"
112
113
  glob = "notes/*.md"
113
114
  on-file = "uv run --with model2vec python embed.py {path} {root}"
@@ -34,6 +34,7 @@ db = DirSQL(
34
34
  "./my-project",
35
35
  tables=[
36
36
  Table(
37
+ name="records",
37
38
  ddl="CREATE TABLE records (name TEXT, size INTEGER, type TEXT)",
38
39
  glob="data/*.json",
39
40
  on_file=lambda path: [json.loads(open(path, encoding="utf-8").read())],
@@ -52,6 +53,7 @@ let db = DirSQL::new(
52
53
  "./my-project",
53
54
  vec![
54
55
  Table::new(
56
+ "records",
55
57
  "CREATE TABLE records (name TEXT, size INTEGER, type TEXT)",
56
58
  "data/*.json",
57
59
  |path| vec![serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap()],
@@ -70,6 +72,7 @@ const db = new DirSQL({
70
72
  root: './my-project',
71
73
  tables: [
72
74
  new Table({
75
+ name: 'records',
73
76
  ddl: 'CREATE TABLE records (name TEXT, size INTEGER, type TEXT)',
74
77
  glob: 'data/*.json',
75
78
  onFile: (path) => [JSON.parse(readFileSync(path, 'utf8'))],
@@ -166,7 +166,8 @@ what its required `on-file` command emits — dirsql injects nothing (see
166
166
 
167
167
  | Key | Required | Description |
168
168
  |---|---|---|
169
- | `ddl` | yes | A SQLite `CREATE TABLE` statement. The table name is parsed from it. Only the columns declared here are kept; keys the `on-file` command emits that are not declared are dropped. |
169
+ | `name` | yes | The table's SQL name — the name you query it by. Declared, never derived from `ddl`: dirsql does not read the DDL text. The `ddl` must create a table by this name; if it doesn't, loading fails. |
170
+ | `ddl` | yes | A SQLite `CREATE TABLE` statement, run verbatim. Only the columns declared here are kept; keys the `on-file` command emits that are not declared are dropped. |
170
171
  | `glob` | yes | Glob pattern matched against root-relative paths. Every table whose glob matches a file receives that file's rows — a file can populate multiple tables. A `{name}` segment is rewritten to `*` (it matches one path segment but captures nothing). |
171
172
  | `on-file` | **yes** | A command run once per matched file; its stdout (a JSON array of row objects) becomes the file's rows. Must be non-empty. A `[[table]]` with no `on-file` is a load error (see [parse errors](#parse-errors)). See [Command hooks](./hooks.md#on-file). |
172
173
  | `strict` | no (default `false`) | When `true`, rows whose keys do not exactly match the declared columns are rejected with an error: extra keys error, and every declared column must be supplied by the `on-file` output. When `false`, extra keys are dropped and missing columns become `NULL`. |
@@ -180,11 +181,13 @@ instead of declaring a table.
180
181
 
181
182
  ```toml
182
183
  [[table]]
184
+ name = "comments"
183
185
  ddl = "CREATE TABLE comments (path TEXT, author TEXT, body TEXT)"
184
186
  glob = "_comments/*/*.jsonl"
185
187
  on-file = "jq -c -s '.' {path}"
186
188
 
187
189
  [[table]]
190
+ name = "papers"
188
191
  ddl = "CREATE TABLE papers (paper_id TEXT, title TEXT)"
189
192
  glob = "**/meta.json"
190
193
  on-file = "uv run python extract_papers.py {path}"
@@ -241,7 +244,16 @@ SDKs raise/reject) when:
241
244
  - The TOML is malformed.
242
245
  - Any table contains an unknown key (top level, `[dirsql]`, `[[table]]`, or
243
246
  `[[dirsql.extension]]`). The error names the offending key.
244
- - A `[[table]]` entry omits `ddl` or `glob`.
247
+ - A `[[table]]` entry omits `name`, `ddl`, or `glob` (or `name` is
248
+ empty/whitespace).
249
+ - A `[[table]]` entry's `ddl` runs but creates no table by its `name`. The
250
+ error carries the entry's name and points at the fix:
251
+
252
+ > `table 'messages': its `ddl` ran but created no table called 'messages'. Set `name` to the table the `ddl` creates.`
253
+
254
+ dirsql asks SQLite's catalog rather than interpreting the DDL, so quoted
255
+ (`CREATE TABLE "messages"`), schema-qualified (`main.messages`) and
256
+ `IF NOT EXISTS` forms all match a plain `name = "messages"`.
245
257
  - A `[[table]]` entry omits `on-file` (or it is empty/whitespace). The error
246
258
  names the offending glob and points at the fix:
247
259
 
@@ -275,11 +287,13 @@ deterministic = true
275
287
  timeout = "600s"
276
288
 
277
289
  [[table]]
290
+ name = "comments"
278
291
  ddl = "CREATE TABLE comments (author TEXT, body TEXT)"
279
292
  glob = "_comments/*/*.jsonl"
280
293
  on-file = "jq -c -s '.' {path}"
281
294
 
282
295
  [[table]]
296
+ name = "documents"
283
297
  ddl = "CREATE TABLE documents (title TEXT, summary TEXT)"
284
298
  glob = "**/index.md"
285
299
  on-file = "uv run python extract_doc.py {path}"
@@ -317,27 +317,30 @@ rather than waiting — an intentional, language-idiomatic difference.
317
317
  ::: code-group
318
318
 
319
319
  ```python [Python]
320
- Table(*, ddl: str, glob: str, on_file: Callable[[str], list[dict]], strict: bool = False)
320
+ Table(*, name: str, ddl: str, glob: str, on_file: Callable[[str], list[dict]], strict: bool = False)
321
321
  ```
322
322
 
323
323
  ```typescript [TypeScript]
324
- new Table({ ddl, glob, onFile, strict? })
324
+ new Table({ name, ddl, glob, onFile, strict? })
325
325
  // or a plain object — TableDef and Table are interchangeable:
326
- { ddl: string, glob: string, onFile: (path: string) => Record<string, unknown>[], strict?: boolean }
326
+ { name: string, ddl: string, glob: string, onFile: (path: string) => Record<string, unknown>[], strict?: boolean }
327
327
  ```
328
328
 
329
329
  ```rust [Rust]
330
- Table::new(ddl, glob, on_file) // on_file: Fn(&str) -> Vec<Row>, infallible
331
- Table::try_new(ddl, glob, on_file) // on_file: Fn(&str) -> Result<Vec<Row>, _>
332
- Table::strict(ddl, glob, on_file) // Table::new with strict = true
330
+ Table::new(name, ddl, glob, on_file) // on_file: Fn(&str) -> Vec<Row>, infallible
331
+ Table::try_new(name, ddl, glob, on_file) // on_file: Fn(&str) -> Result<Vec<Row>, _>
332
+ Table::strict(name, ddl, glob, on_file) // Table::new with strict = true
333
333
  ```
334
334
 
335
335
  :::
336
336
 
337
337
  Maps files to table rows.
338
338
 
339
- - `ddl` — A SQLite `CREATE TABLE` statement; the table name is parsed from
340
- it. Table names must be unique across all tables.
339
+ - `name` — The table's SQL name, declared rather than derived from `ddl`.
340
+ Must be unique across all tables. Building fails if the `ddl` creates no
341
+ table by this name (checked against SQLite's catalog, before any file is
342
+ indexed).
343
+ - `ddl` — A SQLite `CREATE TABLE` statement, run verbatim.
341
344
  - `glob` — Glob pattern matched against root-relative paths. Every table whose
342
345
  glob matches a file receives that file's rows — a file can populate multiple
343
346
  tables. A `{name}` segment is rewritten to `*` (it matches one path segment
@@ -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.24"
7
+ version = "0.4.26"
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,3 @@
1
+ **Changed**
2
+
3
+ - **A table's name is now declared, not derived from `ddl`.** `Table` takes a required keyword-only `name` (`Table(name=..., ddl=..., glob=..., on_file=...)`), and a `[[table]]` entry in a `.dirsql.toml` requires a `name` key. The core no longer parses the DDL text to find the name; a `name` its `ddl` does not create fails at load with an error naming the entry. `Table.name` is now the declared `str` rather than an `Optional[str]` parsed from the DDL. (#962)
@@ -164,6 +164,7 @@ Now create a `.dirsql.toml` that points a table at it:
164
164
  ```bash
165
165
  cat > .dirsql.toml <<'EOF'
166
166
  [[table]]
167
+ name = "notes"
167
168
  ddl = "CREATE TABLE notes (title TEXT, author TEXT)"
168
169
  glob = "notes/**/*.md"
169
170
  on-file = "sh note.sh {path}"
@@ -33,6 +33,7 @@ Point a table at it in `.dirsql.toml`:
33
33
 
34
34
  ```toml
35
35
  [[table]]
36
+ name = "photos"
36
37
  ddl = "CREATE TABLE photos (year TEXT, month TEXT, basename TEXT)"
37
38
  glob = "photos/*/*/*.jpg"
38
39
  on-file = "python3 pathcols.py {path}"
@@ -26,6 +26,7 @@ Then declare the table in `.dirsql.toml`:
26
26
 
27
27
  ```toml
28
28
  [[table]]
29
+ name = "posts"
29
30
  ddl = "CREATE TABLE posts (title TEXT, slug TEXT)"
30
31
  glob = "posts/**/*.md"
31
32
  on-file = "python3 extract.py {path}"
@@ -60,6 +60,7 @@ async def main() -> None:
60
60
  "./comments-root",
61
61
  tables=[
62
62
  Table(
63
+ name="comments",
63
64
  ddl="CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
64
65
  glob="comments/*/*.json",
65
66
  on_file=on_file,
@@ -83,6 +84,7 @@ const db = new DirSQL({
83
84
  root: "./comments-root",
84
85
  tables: [
85
86
  {
87
+ name: "comments",
86
88
  ddl: "CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
87
89
  glob: "comments/*/*.json",
88
90
  onFile: (path) => [
@@ -129,6 +131,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
129
131
  let db = DirSQL::builder()
130
132
  .root("./comments-root")
131
133
  .table(Table::new(
134
+ "comments",
132
135
  "CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
133
136
  "comments/*/*.json",
134
137
  on_file,
@@ -18,6 +18,7 @@ stdout works. With [`jq`](https://jqlang.org/):
18
18
 
19
19
  ```toml
20
20
  [[table]]
21
+ name = "books"
21
22
  ddl = "CREATE TABLE books (title TEXT, author TEXT, year INTEGER)"
22
23
  glob = "books/*.json"
23
24
  on-file = "jq -c '[{title, author, year}]' {path}"
@@ -53,6 +54,7 @@ row per line, slurp it:
53
54
 
54
55
  ```toml
55
56
  [[table]]
57
+ name = "events"
56
58
  ddl = "CREATE TABLE events (event TEXT, user TEXT)"
57
59
  glob = "logs/*.jsonl"
58
60
  on-file = "jq -c -s '.' {path}"
@@ -84,6 +84,7 @@ command in verbatim:
84
84
 
85
85
  ```toml
86
86
  [[table]]
87
+ name = "posts"
87
88
  ddl = "CREATE TABLE posts (title TEXT, author TEXT)"
88
89
  glob = "posts/*.md"
89
90
  on-file = "python3 extract.py {path}"
@@ -14,6 +14,7 @@ prints each file's basename:
14
14
  ```toml
15
15
  # .dirsql.toml
16
16
  [[table]]
17
+ name = "files"
17
18
  ddl = "CREATE TABLE files (basename TEXT)"
18
19
  glob = "**/*"
19
20
  on-file = '''sh -c 'printf "[{\"basename\":\"%s\"}]" "${1##*/}"' sh {path}'''
@@ -22,6 +22,7 @@ Exclude the noise in `.dirsql.toml`:
22
22
  ignore = ["notes/drafts/**", "**/*.tmp"]
23
23
 
24
24
  [[table]]
25
+ name = "notes"
25
26
  ddl = "CREATE TABLE notes (basename TEXT)"
26
27
  glob = "notes/**/*"
27
28
  on-file = '''sh -c 'printf "[{\"basename\":\"%s\"}]" "${1##*/}"' sh {path}'''
@@ -108,6 +108,7 @@ path = "sqlite_vec"
108
108
  entrypoint = "sqlite3_vec_init"
109
109
 
110
110
  [[table]]
111
+ name = "notes"
111
112
  ddl = "CREATE TABLE notes (path TEXT, text TEXT, embedding TEXT)"
112
113
  glob = "notes/*.md"
113
114
  on-file = "uv run --with model2vec python embed.py {path} {root}"
@@ -34,6 +34,7 @@ db = DirSQL(
34
34
  "./my-project",
35
35
  tables=[
36
36
  Table(
37
+ name="records",
37
38
  ddl="CREATE TABLE records (name TEXT, size INTEGER, type TEXT)",
38
39
  glob="data/*.json",
39
40
  on_file=lambda path: [json.loads(open(path, encoding="utf-8").read())],
@@ -52,6 +53,7 @@ let db = DirSQL::new(
52
53
  "./my-project",
53
54
  vec![
54
55
  Table::new(
56
+ "records",
55
57
  "CREATE TABLE records (name TEXT, size INTEGER, type TEXT)",
56
58
  "data/*.json",
57
59
  |path| vec![serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap()],
@@ -70,6 +72,7 @@ const db = new DirSQL({
70
72
  root: './my-project',
71
73
  tables: [
72
74
  new Table({
75
+ name: 'records',
73
76
  ddl: 'CREATE TABLE records (name TEXT, size INTEGER, type TEXT)',
74
77
  glob: 'data/*.json',
75
78
  onFile: (path) => [JSON.parse(readFileSync(path, 'utf8'))],
@@ -166,7 +166,8 @@ what its required `on-file` command emits — dirsql injects nothing (see
166
166
 
167
167
  | Key | Required | Description |
168
168
  |---|---|---|
169
- | `ddl` | yes | A SQLite `CREATE TABLE` statement. The table name is parsed from it. Only the columns declared here are kept; keys the `on-file` command emits that are not declared are dropped. |
169
+ | `name` | yes | The table's SQL name — the name you query it by. Declared, never derived from `ddl`: dirsql does not read the DDL text. The `ddl` must create a table by this name; if it doesn't, loading fails. |
170
+ | `ddl` | yes | A SQLite `CREATE TABLE` statement, run verbatim. Only the columns declared here are kept; keys the `on-file` command emits that are not declared are dropped. |
170
171
  | `glob` | yes | Glob pattern matched against root-relative paths. Every table whose glob matches a file receives that file's rows — a file can populate multiple tables. A `{name}` segment is rewritten to `*` (it matches one path segment but captures nothing). |
171
172
  | `on-file` | **yes** | A command run once per matched file; its stdout (a JSON array of row objects) becomes the file's rows. Must be non-empty. A `[[table]]` with no `on-file` is a load error (see [parse errors](#parse-errors)). See [Command hooks](./hooks.md#on-file). |
172
173
  | `strict` | no (default `false`) | When `true`, rows whose keys do not exactly match the declared columns are rejected with an error: extra keys error, and every declared column must be supplied by the `on-file` output. When `false`, extra keys are dropped and missing columns become `NULL`. |
@@ -180,11 +181,13 @@ instead of declaring a table.
180
181
 
181
182
  ```toml
182
183
  [[table]]
184
+ name = "comments"
183
185
  ddl = "CREATE TABLE comments (path TEXT, author TEXT, body TEXT)"
184
186
  glob = "_comments/*/*.jsonl"
185
187
  on-file = "jq -c -s '.' {path}"
186
188
 
187
189
  [[table]]
190
+ name = "papers"
188
191
  ddl = "CREATE TABLE papers (paper_id TEXT, title TEXT)"
189
192
  glob = "**/meta.json"
190
193
  on-file = "uv run python extract_papers.py {path}"
@@ -241,7 +244,16 @@ SDKs raise/reject) when:
241
244
  - The TOML is malformed.
242
245
  - Any table contains an unknown key (top level, `[dirsql]`, `[[table]]`, or
243
246
  `[[dirsql.extension]]`). The error names the offending key.
244
- - A `[[table]]` entry omits `ddl` or `glob`.
247
+ - A `[[table]]` entry omits `name`, `ddl`, or `glob` (or `name` is
248
+ empty/whitespace).
249
+ - A `[[table]]` entry's `ddl` runs but creates no table by its `name`. The
250
+ error carries the entry's name and points at the fix:
251
+
252
+ > `table 'messages': its `ddl` ran but created no table called 'messages'. Set `name` to the table the `ddl` creates.`
253
+
254
+ dirsql asks SQLite's catalog rather than interpreting the DDL, so quoted
255
+ (`CREATE TABLE "messages"`), schema-qualified (`main.messages`) and
256
+ `IF NOT EXISTS` forms all match a plain `name = "messages"`.
245
257
  - A `[[table]]` entry omits `on-file` (or it is empty/whitespace). The error
246
258
  names the offending glob and points at the fix:
247
259
 
@@ -275,11 +287,13 @@ deterministic = true
275
287
  timeout = "600s"
276
288
 
277
289
  [[table]]
290
+ name = "comments"
278
291
  ddl = "CREATE TABLE comments (author TEXT, body TEXT)"
279
292
  glob = "_comments/*/*.jsonl"
280
293
  on-file = "jq -c -s '.' {path}"
281
294
 
282
295
  [[table]]
296
+ name = "documents"
283
297
  ddl = "CREATE TABLE documents (title TEXT, summary TEXT)"
284
298
  glob = "**/index.md"
285
299
  on-file = "uv run python extract_doc.py {path}"
@@ -317,27 +317,30 @@ rather than waiting — an intentional, language-idiomatic difference.
317
317
  ::: code-group
318
318
 
319
319
  ```python [Python]
320
- Table(*, ddl: str, glob: str, on_file: Callable[[str], list[dict]], strict: bool = False)
320
+ Table(*, name: str, ddl: str, glob: str, on_file: Callable[[str], list[dict]], strict: bool = False)
321
321
  ```
322
322
 
323
323
  ```typescript [TypeScript]
324
- new Table({ ddl, glob, onFile, strict? })
324
+ new Table({ name, ddl, glob, onFile, strict? })
325
325
  // or a plain object — TableDef and Table are interchangeable:
326
- { ddl: string, glob: string, onFile: (path: string) => Record<string, unknown>[], strict?: boolean }
326
+ { name: string, ddl: string, glob: string, onFile: (path: string) => Record<string, unknown>[], strict?: boolean }
327
327
  ```
328
328
 
329
329
  ```rust [Rust]
330
- Table::new(ddl, glob, on_file) // on_file: Fn(&str) -> Vec<Row>, infallible
331
- Table::try_new(ddl, glob, on_file) // on_file: Fn(&str) -> Result<Vec<Row>, _>
332
- Table::strict(ddl, glob, on_file) // Table::new with strict = true
330
+ Table::new(name, ddl, glob, on_file) // on_file: Fn(&str) -> Vec<Row>, infallible
331
+ Table::try_new(name, ddl, glob, on_file) // on_file: Fn(&str) -> Result<Vec<Row>, _>
332
+ Table::strict(name, ddl, glob, on_file) // Table::new with strict = true
333
333
  ```
334
334
 
335
335
  :::
336
336
 
337
337
  Maps files to table rows.
338
338
 
339
- - `ddl` — A SQLite `CREATE TABLE` statement; the table name is parsed from
340
- it. Table names must be unique across all tables.
339
+ - `name` — The table's SQL name, declared rather than derived from `ddl`.
340
+ Must be unique across all tables. Building fails if the `ddl` creates no
341
+ table by this name (checked against SQLite's catalog, before any file is
342
+ indexed).
343
+ - `ddl` — A SQLite `CREATE TABLE` statement, run verbatim.
341
344
  - `glob` — Glob pattern matched against root-relative paths. Every table whose
342
345
  glob matches a file receives that file's rows — a file can populate multiple
343
346
  tables. A `{name}` segment is rewritten to `*` (it matches one path segment
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "uv run python -m pytest tests/e2e/ -x -q",
3
+ "ran_at": 1787251467,
4
+ "exit_code": 0,
5
+ "commit": "706ed098a4e0bfabb3d498b8669fe194051940dd",
6
+ "branch": "claude/issue-962-0jjrfv"
7
+ }
@@ -0,0 +1,52 @@
1
+ ### `Table` and `[[table]]` require an explicit `name` (#962)
2
+
3
+ #### Summary
4
+
5
+ `Table` previously derived its SQL name by parsing the `CREATE TABLE` head of
6
+ `ddl`, exposing the result as an `Optional[str]` attribute. The name is now
7
+ **declared**: `Table` takes a required keyword-only `name`, and a `[[table]]`
8
+ entry in a `.dirsql.toml` requires a `name` key. Whether the `ddl` creates a
9
+ table by that name is checked against SQLite's catalog at load time.
10
+
11
+ #### Required changes
12
+
13
+ | Before | After | Fix |
14
+ | ------ | ----- | --- |
15
+ | `Table(ddl=..., glob=..., on_file=...)` | `TypeError: Table.__new__() missing 1 required keyword argument: 'name'` | Pass `name="<table>"`, matching the table the `ddl` creates. |
16
+ | `[[table]]` with `ddl` + `glob` + `on-file` | `await db.ready()` raises: `Missing required field 'name' in [[table]] entry` | Add `name = "<table>"` to the entry. |
17
+ | `table.name` may be `None` | `table.name` is the declared `str` | Drop any `if table.name is None` handling. |
18
+
19
+ #### Deprecations removed
20
+
21
+ _None._
22
+
23
+ #### Behavior changes without code changes
24
+
25
+ - A `[[table]]` whose `ddl` creates a table under a different name than its
26
+ `name` now raises at `ready()` with an error naming the entry
27
+ (`table 'messages': …`), before any file is ingested.
28
+ - Quoted (`CREATE TABLE "messages"`), schema-qualified and `IF NOT EXISTS` DDL
29
+ keep working unchanged: SQLite records the bare identifier, so a plain
30
+ `name="messages"` matches.
31
+
32
+ #### Verification
33
+
34
+ ```python
35
+ import asyncio, json
36
+ from dirsql import DirSQL, Table
37
+
38
+ db = DirSQL(
39
+ "./data-root",
40
+ tables=[
41
+ Table(
42
+ name="records",
43
+ ddl="CREATE TABLE records (id TEXT)",
44
+ glob="data/*.json",
45
+ on_file=lambda path: json.load(open(path, encoding="utf-8")),
46
+ )
47
+ ],
48
+ )
49
+ asyncio.run(db.ready())
50
+ # -> builds; `SELECT id FROM records` returns the file's rows.
51
+ # Omitting `name=` raises TypeError; a `name` the ddl never creates raises at ready().
52
+ ```
@@ -12,7 +12,7 @@
12
12
 
13
13
  #[cfg(feature = "extension-module")]
14
14
  mod python {
15
- use ::dirsql::{DirSQL, Extension, Row, RowEvent, Table, Value, db::parse_table_name};
15
+ use ::dirsql::{DirSQL, Extension, Row, RowEvent, Table, Value};
16
16
  use pyo3::exceptions::{PyOverflowError, PyRuntimeError};
17
17
  use pyo3::prelude::*;
18
18
  use pyo3::types::{PyBool, PyByteArray, PyBytes, PyDict, PyInt, PyList};
@@ -24,6 +24,9 @@ mod python {
24
24
  /// callable for `on_file`.
25
25
  #[pyclass(name = "Table", frozen)]
26
26
  struct PyTable {
27
+ /// The table's SQL name, declared rather than derived from `ddl`.
28
+ #[pyo3(get)]
29
+ name: String,
27
30
  #[pyo3(get)]
28
31
  ddl: String,
29
32
  #[pyo3(get)]
@@ -32,27 +35,19 @@ mod python {
32
35
  on_file: Py<PyAny>,
33
36
  #[pyo3(get)]
34
37
  strict: bool,
35
- /// Parsed table name (from `ddl`) via `dirsql::db::parse_table_name`,
36
- /// or `None` if the DDL doesn't match `CREATE TABLE <name> (...)`.
37
- /// `None` rather than a construction error so `DirSQL.ready()` keeps
38
- /// surfacing malformed DDLs as the loud failure path (the core's
39
- /// `DirSqlError::Ddl`).
40
- #[pyo3(get)]
41
- name: Option<String>,
42
38
  }
43
39
 
44
40
  #[pymethods]
45
41
  impl PyTable {
46
42
  #[new]
47
- #[pyo3(signature = (*, ddl, glob, on_file, strict=false))]
48
- fn new(ddl: String, glob: String, on_file: Py<PyAny>, strict: bool) -> Self {
49
- let name = parse_table_name(&ddl);
43
+ #[pyo3(signature = (*, name, ddl, glob, on_file, strict=false))]
44
+ fn new(name: String, ddl: String, glob: String, on_file: Py<PyAny>, strict: bool) -> Self {
50
45
  PyTable {
46
+ name,
51
47
  ddl,
52
48
  glob,
53
49
  on_file,
54
50
  strict,
55
- name,
56
51
  }
57
52
  }
58
53
  }
@@ -235,6 +230,7 @@ mod python {
235
230
  fn build_table(py: Python<'_>, t: &PyTable) -> Table {
236
231
  let on_file_ref = t.on_file.clone_ref(py);
237
232
  let mut table = Table::try_new(
233
+ t.name.clone(),
238
234
  t.ddl.clone(),
239
235
  t.glob.clone(),
240
236
  make_on_file_closure(on_file_ref),
@@ -3,6 +3,7 @@
3
3
  # injected by the launcher as an ordinary `-c` flag. Adds one table so an
4
4
  # installed plugin is observable ("installed = active") with zero config edits.
5
5
  [[table]]
6
+ name = "notes"
6
7
  ddl = "CREATE TABLE notes (path TEXT, basename TEXT)"
7
8
  glob = "*.md"
8
9
  on-file = '''sh -c 'rel=${1#"$2"/}; base=${1##*/}; printf "[{\"path\":\"%s\",\"basename\":\"%s\"}]" "$rel" "$base"' sh {path} {root}'''