dirsql 0.4.23__tar.gz → 0.4.25__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 (250) hide show
  1. {dirsql-0.4.23 → dirsql-0.4.25}/Cargo.lock +1 -1
  2. {dirsql-0.4.23 → dirsql-0.4.25}/PKG-INFO +1 -1
  3. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/_dirsql.pyi +2 -0
  4. {dirsql-0.4.23 → dirsql-0.4.25}/docs/.vitepress/config.ts +1 -0
  5. {dirsql-0.4.23 → dirsql-0.4.25}/docs/getting-started.md +1 -0
  6. {dirsql-0.4.23 → dirsql-0.4.25}/docs/howto/columns-from-paths.md +1 -0
  7. {dirsql-0.4.23/packages/python → dirsql-0.4.25}/docs/howto/define-tables.md +1 -0
  8. {dirsql-0.4.23/packages/python → dirsql-0.4.25}/docs/howto/embed.md +3 -0
  9. {dirsql-0.4.23/packages/rust → dirsql-0.4.25}/docs/howto/extract-from-contents.md +5 -0
  10. {dirsql-0.4.23 → dirsql-0.4.25}/docs/howto/parse-files-into-columns.md +1 -0
  11. dirsql-0.4.25/docs/howto/query-json.md +197 -0
  12. {dirsql-0.4.23/packages/python → dirsql-0.4.25}/docs/howto/react-to-changes.md +1 -0
  13. {dirsql-0.4.23 → dirsql-0.4.25}/docs/howto/skip-files.md +1 -0
  14. {dirsql-0.4.23/packages/rust → dirsql-0.4.25}/docs/howto/write-a-plugin.md +1 -0
  15. {dirsql-0.4.23/packages/rust → dirsql-0.4.25}/docs/index.md +3 -0
  16. {dirsql-0.4.23/packages/rust → dirsql-0.4.25}/docs/reference/config.md +16 -2
  17. {dirsql-0.4.23 → dirsql-0.4.25}/docs/reference/sdk.md +11 -8
  18. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/Cargo.toml +1 -1
  19. dirsql-0.4.25/packages/python/changelog.d/2026-08-20-declared-table-name.md +3 -0
  20. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/.vitepress/config.ts +1 -0
  21. {dirsql-0.4.23/packages/rust → dirsql-0.4.25/packages/python}/docs/getting-started.md +1 -0
  22. {dirsql-0.4.23/packages/rust → dirsql-0.4.25/packages/python}/docs/howto/columns-from-paths.md +1 -0
  23. {dirsql-0.4.23 → dirsql-0.4.25/packages/python}/docs/howto/define-tables.md +1 -0
  24. {dirsql-0.4.23 → dirsql-0.4.25/packages/python}/docs/howto/embed.md +3 -0
  25. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/howto/extract-from-contents.md +5 -0
  26. {dirsql-0.4.23/packages/rust → dirsql-0.4.25/packages/python}/docs/howto/parse-files-into-columns.md +1 -0
  27. dirsql-0.4.25/packages/python/docs/howto/query-json.md +197 -0
  28. {dirsql-0.4.23/packages/rust → dirsql-0.4.25/packages/python}/docs/howto/react-to-changes.md +1 -0
  29. {dirsql-0.4.23/packages/rust → dirsql-0.4.25/packages/python}/docs/howto/skip-files.md +1 -0
  30. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/howto/write-a-plugin.md +1 -0
  31. {dirsql-0.4.23 → dirsql-0.4.25/packages/python}/docs/index.md +3 -0
  32. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/reference/config.md +16 -2
  33. {dirsql-0.4.23/packages/rust → dirsql-0.4.25/packages/python}/docs/reference/sdk.md +11 -8
  34. dirsql-0.4.25/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +7 -0
  35. dirsql-0.4.25/packages/python/migrations.d/2026-08-20-declared-table-name.md +52 -0
  36. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/src/lib.rs +8 -12
  37. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +1 -0
  38. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/Cargo.toml +6 -0
  39. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/benches/db_bench.rs +20 -8
  40. {dirsql-0.4.23/packages/python → dirsql-0.4.25/packages/rust}/docs/getting-started.md +1 -0
  41. {dirsql-0.4.23/packages/python → dirsql-0.4.25/packages/rust}/docs/howto/columns-from-paths.md +1 -0
  42. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/docs/howto/define-tables.md +1 -0
  43. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/docs/howto/embed.md +3 -0
  44. {dirsql-0.4.23 → dirsql-0.4.25/packages/rust}/docs/howto/extract-from-contents.md +5 -0
  45. {dirsql-0.4.23/packages/python → dirsql-0.4.25/packages/rust}/docs/howto/parse-files-into-columns.md +1 -0
  46. dirsql-0.4.25/packages/rust/docs/howto/query-json.md +197 -0
  47. {dirsql-0.4.23 → dirsql-0.4.25/packages/rust}/docs/howto/react-to-changes.md +1 -0
  48. {dirsql-0.4.23/packages/python → dirsql-0.4.25/packages/rust}/docs/howto/skip-files.md +1 -0
  49. {dirsql-0.4.23 → dirsql-0.4.25/packages/rust}/docs/howto/write-a-plugin.md +1 -0
  50. {dirsql-0.4.23/packages/python → dirsql-0.4.25/packages/rust}/docs/index.md +3 -0
  51. {dirsql-0.4.23 → dirsql-0.4.25/packages/rust}/docs/reference/config.md +16 -2
  52. {dirsql-0.4.23/packages/python → dirsql-0.4.25/packages/rust}/docs/reference/sdk.md +11 -8
  53. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/cli/run.rs +1 -0
  54. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/config.rs +93 -32
  55. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/db.rs +70 -351
  56. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/default_config.toml +4 -0
  57. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/lib.rs +96 -27
  58. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/persist.rs +10 -8
  59. dirsql-0.4.23/packages/rust/changelog.d/2026-07-13-batch-ingest-transaction.md +0 -1
  60. dirsql-0.4.23/packages/rust/changelog.d/2026-07-13-chained-pre-post-query-hooks.md +0 -3
  61. dirsql-0.4.23/packages/rust/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -3
  62. dirsql-0.4.23/packages/rust/changelog.d/2026-07-13-fan-out-file-table-matching.md +0 -3
  63. dirsql-0.4.23/packages/rust/changelog.d/2026-07-13-persist-wal.md +0 -3
  64. dirsql-0.4.23/packages/rust/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -3
  65. dirsql-0.4.23/packages/rust/changelog.d/2026-07-13-repeatable-builder-config.md +0 -3
  66. dirsql-0.4.23/packages/rust/changelog.d/2026-07-13-repeatable-cli-config.md +0 -3
  67. dirsql-0.4.23/packages/rust/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -3
  68. dirsql-0.4.23/packages/rust/changelog.d/2026-07-13-subcommand-local-config-flags.md +0 -1
  69. dirsql-0.4.23/packages/rust/changelog.d/2026-07-19-path-table-query-fallback.md +0 -10
  70. dirsql-0.4.23/packages/rust/changelog.d/2026-07-19-path-table-vtab.md +0 -7
  71. dirsql-0.4.23/packages/rust/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -11
  72. dirsql-0.4.23/packages/rust/changelog.d/2026-07-20-path-table-glob-semantics.md +0 -11
  73. dirsql-0.4.23/packages/rust/changelog.d/2026-07-20-schema-inference.md +0 -12
  74. dirsql-0.4.23/packages/rust/changelog.d/2026-07-21-on-file-flag.md +0 -14
  75. dirsql-0.4.23/packages/rust/changelog.d/2026-07-21-remove-glob-captures.md +0 -3
  76. dirsql-0.4.23/packages/rust/changelog.d/2026-07-23-init-escalation-example.md +0 -10
  77. dirsql-0.4.23/packages/rust/changelog.d/2026-07-23-query-default-cli.md +0 -1
  78. dirsql-0.4.23/packages/rust/changelog.d/2026-07-24-hookless-table-config-error.md +0 -3
  79. dirsql-0.4.23/packages/rust/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -3
  80. dirsql-0.4.23/packages/rust/changelog.d/2026-07-29-on-file-failures-accumulate.md +0 -8
  81. dirsql-0.4.23/packages/rust/changelog.d/2026-08-02-drop-regex.md +0 -17
  82. dirsql-0.4.23/packages/rust/changelog.d/2026-08-02-per-file-scan-failures.md +0 -35
  83. dirsql-0.4.23/packages/rust/changelog.d/2026-08-02-release-profile.md +0 -7
  84. dirsql-0.4.23/packages/rust/changelog.d/2026-08-03-gitignore-by-default.md +0 -9
  85. dirsql-0.4.23/packages/rust/changelog.d/2026-08-03-nested-default-ignores.md +0 -11
  86. dirsql-0.4.23/packages/rust/changelog.d/2026-08-04-cast-lints.md +0 -1
  87. dirsql-0.4.23/packages/rust/changelog.d/2026-08-04-cli-run-shim.md +0 -3
  88. dirsql-0.4.23/packages/rust/changelog.d/2026-08-04-configless-extension.md +0 -1
  89. dirsql-0.4.23/packages/rust/changelog.d/2026-08-10-dirsql-function.md +0 -1
  90. dirsql-0.4.23/packages/rust/changelog.d/2026-08-10-remove-query-hooks.md +0 -3
  91. dirsql-0.4.23/packages/rust/changelog.d/2026-08-11-oneshot-query-no-timeout.md +0 -3
  92. dirsql-0.4.23/packages/rust/changelog.d/2026-08-11-persist-parsed-path-tables.md +0 -4
  93. dirsql-0.4.23/packages/rust/changelog.d/2026-08-11-retire-hook-timeout.md +0 -3
  94. dirsql-0.4.23/packages/rust/changelog.d/2026-08-12-unquote-inverts-quote-literal.md +0 -3
  95. dirsql-0.4.23/packages/rust/changelog.d/2026-08-20-unquoted-path-table-hint.md +0 -3
  96. dirsql-0.4.23/packages/rust/changelog.d/README.md +0 -17
  97. dirsql-0.4.23/packages/rust/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -52
  98. dirsql-0.4.23/packages/rust/migrations.d/2026-07-13-fan-out-file-table-matching.md +0 -70
  99. dirsql-0.4.23/packages/rust/migrations.d/2026-07-13-persist-wal.md +0 -38
  100. dirsql-0.4.23/packages/rust/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -54
  101. dirsql-0.4.23/packages/rust/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -46
  102. dirsql-0.4.23/packages/rust/migrations.d/2026-07-13-subcommand-local-config-flags.md +0 -50
  103. dirsql-0.4.23/packages/rust/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -67
  104. dirsql-0.4.23/packages/rust/migrations.d/2026-07-20-path-table-glob-semantics.md +0 -57
  105. dirsql-0.4.23/packages/rust/migrations.d/2026-07-21-remove-glob-captures.md +0 -53
  106. dirsql-0.4.23/packages/rust/migrations.d/2026-07-23-init-escalation-example.md +0 -64
  107. dirsql-0.4.23/packages/rust/migrations.d/2026-07-23-query-default-cli.md +0 -55
  108. dirsql-0.4.23/packages/rust/migrations.d/2026-07-24-hookless-table-config-error.md +0 -51
  109. dirsql-0.4.23/packages/rust/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -55
  110. dirsql-0.4.23/packages/rust/migrations.d/2026-08-02-per-file-scan-failures.md +0 -100
  111. dirsql-0.4.23/packages/rust/migrations.d/2026-08-03-gitignore-by-default.md +0 -52
  112. dirsql-0.4.23/packages/rust/migrations.d/2026-08-03-nested-default-ignores.md +0 -46
  113. dirsql-0.4.23/packages/rust/migrations.d/2026-08-10-remove-query-hooks.md +0 -47
  114. dirsql-0.4.23/packages/rust/migrations.d/2026-08-11-oneshot-query-no-timeout.md +0 -46
  115. dirsql-0.4.23/packages/rust/migrations.d/2026-08-11-persist-parsed-path-tables.md +0 -58
  116. dirsql-0.4.23/packages/rust/migrations.d/2026-08-11-retire-hook-timeout.md +0 -51
  117. dirsql-0.4.23/packages/rust/migrations.d/README.md +0 -19
  118. {dirsql-0.4.23 → dirsql-0.4.25}/Cargo.toml +0 -0
  119. {dirsql-0.4.23 → dirsql-0.4.25}/README.md +0 -0
  120. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/__init__.py +0 -0
  121. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/_async.py +0 -0
  122. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/cli/__init__.py +0 -0
  123. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/cli/discover_plugins/__init__.py +0 -0
  124. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
  125. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
  126. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
  127. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
  128. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
  129. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/cli/main.py +0 -0
  130. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/cli/resolve_config_extensions.py +0 -0
  131. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/py.typed +0 -0
  132. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/resolve_config_extensions.py +0 -0
  133. {dirsql-0.4.23 → dirsql-0.4.25}/dirsql/resolve_extension.py +0 -0
  134. {dirsql-0.4.23 → dirsql-0.4.25}/docs/.claude/CLAUDE.md +0 -0
  135. {dirsql-0.4.23 → dirsql-0.4.25}/docs/.vitepress/theme/index.ts +0 -0
  136. {dirsql-0.4.23 → dirsql-0.4.25}/docs/.vitepress/theme/lang.ts +0 -0
  137. {dirsql-0.4.23 → dirsql-0.4.25}/docs/AGENTS.md +0 -0
  138. {dirsql-0.4.23 → dirsql-0.4.25}/docs/explanation.md +0 -0
  139. {dirsql-0.4.23 → dirsql-0.4.25}/docs/howto/load-extension.md +0 -0
  140. {dirsql-0.4.23 → dirsql-0.4.25}/docs/howto/persist.md +0 -0
  141. {dirsql-0.4.23 → dirsql-0.4.25}/docs/howto/query-without-config.md +0 -0
  142. {dirsql-0.4.23 → dirsql-0.4.25}/docs/howto/search-by-meaning.md +0 -0
  143. {dirsql-0.4.23 → dirsql-0.4.25}/docs/package.json +0 -0
  144. {dirsql-0.4.23 → dirsql-0.4.25}/docs/plugins.md +0 -0
  145. {dirsql-0.4.23 → dirsql-0.4.25}/docs/pnpm-lock.yaml +0 -0
  146. {dirsql-0.4.23 → dirsql-0.4.25}/docs/pnpm-workspace.yaml +0 -0
  147. {dirsql-0.4.23 → dirsql-0.4.25}/docs/reference/cli.md +0 -0
  148. {dirsql-0.4.23 → dirsql-0.4.25}/docs/reference/columns.md +0 -0
  149. {dirsql-0.4.23 → dirsql-0.4.25}/docs/reference/hooks.md +0 -0
  150. {dirsql-0.4.23 → dirsql-0.4.25}/docs/reference/http-api.md +0 -0
  151. {dirsql-0.4.23 → dirsql-0.4.25}/docs/reference/path-tables.md +0 -0
  152. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/CHANGELOG.md +0 -0
  153. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/MIGRATIONS.md +0 -0
  154. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/README.md +0 -0
  155. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  156. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
  157. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  158. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
  159. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  160. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  161. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  162. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
  163. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  164. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
  165. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
  166. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
  167. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
  168. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
  169. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
  170. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
  171. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
  172. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/changelog.d/README.md +0 -0
  173. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/conftest.py +0 -0
  174. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/.claude/CLAUDE.md +0 -0
  175. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  176. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  177. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/AGENTS.md +0 -0
  178. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/explanation.md +0 -0
  179. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/howto/load-extension.md +0 -0
  180. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/howto/persist.md +0 -0
  181. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/howto/query-without-config.md +0 -0
  182. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/howto/search-by-meaning.md +0 -0
  183. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/package.json +0 -0
  184. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/plugins.md +0 -0
  185. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/pnpm-lock.yaml +0 -0
  186. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/pnpm-workspace.yaml +0 -0
  187. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/reference/cli.md +0 -0
  188. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/reference/columns.md +0 -0
  189. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/reference/hooks.md +0 -0
  190. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/reference/http-api.md +0 -0
  191. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/docs/reference/path-tables.md +0 -0
  192. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
  193. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
  194. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
  195. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
  196. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  197. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  198. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  199. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  200. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  201. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
  202. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  203. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
  204. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
  205. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/migrations.d/README.md +0 -0
  206. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/testing-conventions.toml +0 -0
  207. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/tests/__init__.py +0 -0
  208. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/tests/conftest.py +0 -0
  209. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/tests/e2e/__init__.py +0 -0
  210. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
  211. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/tests/integration/__init__.py +0 -0
  212. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/tests/integration/binding/__init__.py +0 -0
  213. {dirsql-0.4.23 → dirsql-0.4.25}/packages/python/tests/integration/hermetic/__init__.py +0 -0
  214. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/CHANGELOG.md +0 -0
  215. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/MIGRATIONS.md +0 -0
  216. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/README.md +0 -0
  217. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/benches/differ_bench.rs +0 -0
  218. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/benches/matcher_bench.rs +0 -0
  219. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/benches/scanner_bench.rs +0 -0
  220. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/docs/explanation.md +0 -0
  221. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/docs/howto/load-extension.md +0 -0
  222. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/docs/howto/persist.md +0 -0
  223. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/docs/howto/query-without-config.md +0 -0
  224. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/docs/howto/search-by-meaning.md +0 -0
  225. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/docs/plugins.md +0 -0
  226. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/docs/reference/cli.md +0 -0
  227. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/docs/reference/columns.md +0 -0
  228. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/docs/reference/hooks.md +0 -0
  229. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/docs/reference/http-api.md +0 -0
  230. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/docs/reference/path-tables.md +0 -0
  231. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/bin/dirsql.rs +0 -0
  232. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/cli/execute.rs +0 -0
  233. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/cli/init.rs +0 -0
  234. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/cli/mod.rs +0 -0
  235. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/cli/router.rs +0 -0
  236. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/cli/serialize.rs +0 -0
  237. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/cli/server.rs +0 -0
  238. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/command.rs +0 -0
  239. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/differ.rs +0 -0
  240. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/functions.rs +0 -0
  241. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/infer.rs +0 -0
  242. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/matcher.rs +0 -0
  243. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/parsed_cache.rs +0 -0
  244. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/parsed_vtab.rs +0 -0
  245. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/path_table.rs +0 -0
  246. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/scanner.rs +0 -0
  247. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/sql_literal.rs +0 -0
  248. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/vtab.rs +0 -0
  249. {dirsql-0.4.23 → dirsql-0.4.25}/packages/rust/src/watcher.rs +0 -0
  250. {dirsql-0.4.23 → dirsql-0.4.25}/pyproject.toml +0 -0
@@ -499,7 +499,7 @@ dependencies = [
499
499
 
500
500
  [[package]]
501
501
  name = "dirsql-py-ext"
502
- version = "0.4.23"
502
+ version = "0.4.25"
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.23
3
+ Version: 0.4.25
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]],
@@ -54,6 +54,7 @@ export default defineConfig({
54
54
  { text: 'Derive columns from file paths', link: '/howto/columns-from-paths' },
55
55
  { text: 'Extract rows from file contents', link: '/howto/extract-from-contents' },
56
56
  { text: 'Parse your files into columns', link: '/howto/parse-files-into-columns' },
57
+ { text: 'Query JSON file contents', link: '/howto/query-json' },
57
58
  { text: 'Search documents by meaning', link: '/howto/search-by-meaning' },
58
59
  { text: "Skip files you don't want indexed", link: '/howto/skip-files' },
59
60
  { text: 'Load a SQLite extension', link: '/howto/load-extension' },
@@ -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}"
@@ -77,6 +79,9 @@ SQLite value mapping is under
77
79
 
78
80
  ## Going further
79
81
 
82
+ - Just want to read a field or two out of some JSON files? SQLite's JSON
83
+ operators work directly on a path-table's `content` column, with no config
84
+ and no command — [Query JSON file contents](./query-json.md).
80
85
  - The command re-runs on every startup and on every change to a matched
81
86
  file. If it is expensive, [keep the index across restarts](./persist.md).
82
87
  - Embedding `dirsql` in a program instead? The SDK's `on_file` callback
@@ -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}"
@@ -0,0 +1,197 @@
1
+ # Query JSON file contents
2
+
3
+ A tree of JSON files is already a table — you just have to ask for it. The
4
+ hidden [`content`](../reference/path-tables.md#columns) column holds each
5
+ file's raw text, and SQLite's JSON operators read fields straight out of it.
6
+ No config, no parser, no schema.
7
+
8
+ ## 1. Pull a field out of `content`
9
+
10
+ Suppose each plugin ships a `metadata.json`:
11
+
12
+ ```
13
+ plugins/alpha/metadata.json
14
+ plugins/beta/metadata.json
15
+ plugins/gamma/metadata.json
16
+ ```
17
+
18
+ ```json
19
+ {
20
+ "name": "alpha",
21
+ "version": "1.4.0",
22
+ "disabled": false,
23
+ "runtime": { "engine": "wasm", "memory_mb": 64 },
24
+ "tags": ["search", "index"]
25
+ }
26
+ ```
27
+
28
+ The `->>` operator extracts a field. **The key is a string literal, not a bare
29
+ identifier** — this is the one thing that trips everyone up:
30
+
31
+ ```bash
32
+ dirsql query "SELECT content ->> disabled FROM './plugins/alpha/metadata.json'"
33
+ ```
34
+
35
+ ```
36
+ dirsql query: SQLite error: no such column: disabled in SELECT content ->> disabled FROM './plugins/alpha/metadata.json' at offset 19
37
+ ```
38
+
39
+ Unquoted, `disabled` is a column name to SQLite's parser, and no such column
40
+ exists. Quote it and the field comes back:
41
+
42
+ ```bash
43
+ dirsql query "SELECT content ->> 'disabled' FROM './plugins/alpha/metadata.json'"
44
+ ```
45
+
46
+ ```json
47
+ [{"content ->> 'disabled'":0}]
48
+ ```
49
+
50
+ The expression becomes the column name, so alias it:
51
+
52
+ ```bash
53
+ dirsql query "SELECT content ->> 'disabled' AS disabled FROM './plugins/alpha/metadata.json'"
54
+ ```
55
+
56
+ ```json
57
+ [{"disabled":0}]
58
+ ```
59
+
60
+ ## 2. Query the whole tree
61
+
62
+ `content` is a [path-table](../reference/path-tables.md) column, so the same
63
+ expression works over a glob — one row per file:
64
+
65
+ ```bash
66
+ dirsql query "SELECT content ->> 'name' AS name, content ->> 'version' AS version
67
+ FROM './**/metadata.json' ORDER BY name"
68
+ ```
69
+
70
+ ```json
71
+ [{"name":"alpha","version":"1.4.0"},{"name":"beta","version":"0.9.2"},{"name":"gamma","version":"2.0.1"}]
72
+ ```
73
+
74
+ `content` is read only when a query names it, so a glob over a large tree costs
75
+ nothing until you actually reach inside the files.
76
+
77
+ ## 3. Reach nested keys
78
+
79
+ A key that starts with `$` is a **JSON path**: dotted for nested objects,
80
+ bracketed for array elements. It is still a string literal.
81
+
82
+ ```bash
83
+ dirsql query "SELECT content ->> 'name' AS name,
84
+ content ->> '$.runtime.engine' AS engine,
85
+ content ->> '$.runtime.memory_mb' AS memory_mb
86
+ FROM './**/metadata.json' ORDER BY name"
87
+ ```
88
+
89
+ ```json
90
+ [{"engine":"wasm","memory_mb":64,"name":"alpha"},{"engine":"native","memory_mb":256,"name":"beta"},{"engine":"wasm","memory_mb":128,"name":"gamma"}]
91
+ ```
92
+
93
+ `content ->> 'name'` and `content ->> '$.name'` are the same lookup — the bare
94
+ form is shorthand for a top-level key. `json_extract(content, '$.name')` is the
95
+ function spelling of the same thing and takes the same paths.
96
+
97
+ ## 4. Filter and aggregate
98
+
99
+ Extracted fields are ordinary SQL values, so they work in `WHERE`, `GROUP BY`,
100
+ and joins:
101
+
102
+ ```bash
103
+ dirsql query "SELECT path FROM './**/metadata.json'
104
+ WHERE content ->> 'disabled' = 0 ORDER BY path"
105
+ ```
106
+
107
+ ```json
108
+ [{"path":"plugins/alpha/metadata.json"},{"path":"plugins/gamma/metadata.json"}]
109
+ ```
110
+
111
+ To count across an array field, expand it with `json_each`:
112
+
113
+ ```bash
114
+ dirsql query "SELECT t.value AS tag, COUNT(*) AS n
115
+ FROM './**/metadata.json' AS m, json_each(m.content, '$.tags') AS t
116
+ GROUP BY tag ORDER BY n DESC, tag"
117
+ ```
118
+
119
+ ```json
120
+ [{"n":2,"tag":"index"},{"n":2,"tag":"search"},{"n":1,"tag":"export"},{"n":1,"tag":"rerank"}]
121
+ ```
122
+
123
+ ## `->` and `->>`
124
+
125
+ Both take the same paths; they differ in what they hand back. `->>` returns the
126
+ **SQL value**; `->` returns the **JSON text** of that value, quotes and all:
127
+
128
+ ```bash
129
+ dirsql query "SELECT content -> 'name' AS arrow, content ->> 'name' AS arrow2
130
+ FROM './plugins/alpha/metadata.json'"
131
+ ```
132
+
133
+ ```json
134
+ [{"arrow":"\"alpha\"","arrow2":"alpha"}]
135
+ ```
136
+
137
+ Reach for `->>` to get a value out, and `->` to keep drilling — its JSON result
138
+ is a valid left operand for another `->` or `->>`.
139
+
140
+ ## How JSON types arrive
141
+
142
+ `->>` maps JSON types onto SQLite's, which has no boolean:
143
+
144
+ | In the file | In the row |
145
+ | --- | --- |
146
+ | `true` / `false` | `1` / `0` |
147
+ | `null` | `NULL` |
148
+ | number | INTEGER or REAL |
149
+ | string | TEXT, unquoted |
150
+ | object or array | its JSON text |
151
+ | key not present | `NULL` |
152
+
153
+ So `disabled: false` reads back as `0`, and `WHERE content ->> 'disabled' = 0`
154
+ is how you ask for the enabled ones — `= false` is not SQLite syntax.
155
+
156
+ A missing key and a `null` value both arrive as `NULL`. Use
157
+ `content -> 'key' IS NULL` to tell them apart: `->` yields the JSON text
158
+ `'null'` for a present null, and SQL `NULL` only when the key is absent.
159
+
160
+ ## When a file isn't valid JSON
161
+
162
+ The JSON operators reject a non-JSON `content`, and that fails the **whole
163
+ query** — one stray file, no rows at all:
164
+
165
+ ```
166
+ dirsql query: SQLite error: malformed JSON
167
+ ```
168
+
169
+ An empty file counts too: `content` is `''`, which is not valid JSON. Guard the
170
+ scan with `json_valid` when the glob might catch something it shouldn't:
171
+
172
+ ```bash
173
+ dirsql query "SELECT content ->> 'name' AS name FROM './**/metadata.json'
174
+ WHERE json_valid(content) ORDER BY name"
175
+ ```
176
+
177
+ Files that fail the guard drop out and the rest still answer. A file that is
178
+ unreadable or not UTF-8 has `NULL` content, which is not an error —
179
+ `json_valid(NULL)` is `NULL`, so the guard excludes those too.
180
+
181
+ ## Going further
182
+
183
+ - Only path-tables expose `content`. A named `[[table]]` has exactly the columns
184
+ its hook emits ([columns reference](../reference/columns.md)) — reading a
185
+ field with `->>` there means the hook already emitted it.
186
+ - Doing this on every query re-reads and re-parses every file. When the same
187
+ tree is queried repeatedly, move the extraction into a table:
188
+ [Extract rows from file contents](./extract-from-contents.md) declares the
189
+ columns in a config, and [Parse your files into columns](./parse-files-into-columns.md)
190
+ prototypes the same parser inline with `--on-file`. Either way the parsed rows
191
+ are indexed, watched, and [persistable](./persist.md).
192
+ - One JSON file holding *many* records is a parser's job, not an operator's —
193
+ `json_each` expands an array within a row, but one row per record needs
194
+ [`on-file`](../reference/hooks.md#on-file).
195
+ - The full operator and function set is SQLite's own:
196
+ [JSON functions](https://sqlite.org/json1.html). `dirsql` adds nothing to it
197
+ and takes nothing away.
@@ -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.23"
7
+ version = "0.4.25"
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)
@@ -54,6 +54,7 @@ export default defineConfig({
54
54
  { text: 'Derive columns from file paths', link: '/howto/columns-from-paths' },
55
55
  { text: 'Extract rows from file contents', link: '/howto/extract-from-contents' },
56
56
  { text: 'Parse your files into columns', link: '/howto/parse-files-into-columns' },
57
+ { text: 'Query JSON file contents', link: '/howto/query-json' },
57
58
  { text: 'Search documents by meaning', link: '/howto/search-by-meaning' },
58
59
  { text: "Skip files you don't want indexed", link: '/howto/skip-files' },
59
60
  { text: 'Load a SQLite extension', link: '/howto/load-extension' },
@@ -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}"
@@ -77,6 +79,9 @@ SQLite value mapping is under
77
79
 
78
80
  ## Going further
79
81
 
82
+ - Just want to read a field or two out of some JSON files? SQLite's JSON
83
+ operators work directly on a path-table's `content` column, with no config
84
+ and no command — [Query JSON file contents](./query-json.md).
80
85
  - The command re-runs on every startup and on every change to a matched
81
86
  file. If it is expensive, [keep the index across restarts](./persist.md).
82
87
  - Embedding `dirsql` in a program instead? The SDK's `on_file` callback
@@ -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}"