dirsql 0.4.22__tar.gz → 0.4.24__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 (246) hide show
  1. {dirsql-0.4.22 → dirsql-0.4.24}/Cargo.lock +1 -1
  2. {dirsql-0.4.22 → dirsql-0.4.24}/PKG-INFO +1 -1
  3. {dirsql-0.4.22 → dirsql-0.4.24}/docs/.vitepress/config.ts +1 -0
  4. {dirsql-0.4.22/packages/rust → dirsql-0.4.24}/docs/howto/extract-from-contents.md +3 -0
  5. dirsql-0.4.24/docs/howto/query-json.md +197 -0
  6. {dirsql-0.4.22 → dirsql-0.4.24}/docs/reference/path-tables.md +11 -0
  7. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/Cargo.toml +1 -1
  8. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/.vitepress/config.ts +1 -0
  9. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/howto/extract-from-contents.md +3 -0
  10. dirsql-0.4.24/packages/python/docs/howto/query-json.md +197 -0
  11. {dirsql-0.4.22/packages/rust → dirsql-0.4.24/packages/python}/docs/reference/path-tables.md +11 -0
  12. dirsql-0.4.24/packages/python/e2e-attestations/claude-issue-951-0eease.json +7 -0
  13. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/Cargo.toml +6 -0
  14. {dirsql-0.4.22 → dirsql-0.4.24/packages/rust}/docs/howto/extract-from-contents.md +3 -0
  15. dirsql-0.4.24/packages/rust/docs/howto/query-json.md +197 -0
  16. {dirsql-0.4.22/packages/python → dirsql-0.4.24/packages/rust}/docs/reference/path-tables.md +11 -0
  17. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/db.rs +146 -1
  18. dirsql-0.4.22/packages/rust/changelog.d/2026-07-13-batch-ingest-transaction.md +0 -1
  19. dirsql-0.4.22/packages/rust/changelog.d/2026-07-13-chained-pre-post-query-hooks.md +0 -3
  20. dirsql-0.4.22/packages/rust/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -3
  21. dirsql-0.4.22/packages/rust/changelog.d/2026-07-13-fan-out-file-table-matching.md +0 -3
  22. dirsql-0.4.22/packages/rust/changelog.d/2026-07-13-persist-wal.md +0 -3
  23. dirsql-0.4.22/packages/rust/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -3
  24. dirsql-0.4.22/packages/rust/changelog.d/2026-07-13-repeatable-builder-config.md +0 -3
  25. dirsql-0.4.22/packages/rust/changelog.d/2026-07-13-repeatable-cli-config.md +0 -3
  26. dirsql-0.4.22/packages/rust/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -3
  27. dirsql-0.4.22/packages/rust/changelog.d/2026-07-13-subcommand-local-config-flags.md +0 -1
  28. dirsql-0.4.22/packages/rust/changelog.d/2026-07-19-path-table-query-fallback.md +0 -10
  29. dirsql-0.4.22/packages/rust/changelog.d/2026-07-19-path-table-vtab.md +0 -7
  30. dirsql-0.4.22/packages/rust/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -11
  31. dirsql-0.4.22/packages/rust/changelog.d/2026-07-20-path-table-glob-semantics.md +0 -11
  32. dirsql-0.4.22/packages/rust/changelog.d/2026-07-20-schema-inference.md +0 -12
  33. dirsql-0.4.22/packages/rust/changelog.d/2026-07-21-on-file-flag.md +0 -14
  34. dirsql-0.4.22/packages/rust/changelog.d/2026-07-21-remove-glob-captures.md +0 -3
  35. dirsql-0.4.22/packages/rust/changelog.d/2026-07-23-init-escalation-example.md +0 -10
  36. dirsql-0.4.22/packages/rust/changelog.d/2026-07-23-query-default-cli.md +0 -1
  37. dirsql-0.4.22/packages/rust/changelog.d/2026-07-24-hookless-table-config-error.md +0 -3
  38. dirsql-0.4.22/packages/rust/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -3
  39. dirsql-0.4.22/packages/rust/changelog.d/2026-07-29-on-file-failures-accumulate.md +0 -8
  40. dirsql-0.4.22/packages/rust/changelog.d/2026-08-02-drop-regex.md +0 -17
  41. dirsql-0.4.22/packages/rust/changelog.d/2026-08-02-per-file-scan-failures.md +0 -35
  42. dirsql-0.4.22/packages/rust/changelog.d/2026-08-02-release-profile.md +0 -7
  43. dirsql-0.4.22/packages/rust/changelog.d/2026-08-03-gitignore-by-default.md +0 -9
  44. dirsql-0.4.22/packages/rust/changelog.d/2026-08-03-nested-default-ignores.md +0 -11
  45. dirsql-0.4.22/packages/rust/changelog.d/2026-08-04-cast-lints.md +0 -1
  46. dirsql-0.4.22/packages/rust/changelog.d/2026-08-04-cli-run-shim.md +0 -3
  47. dirsql-0.4.22/packages/rust/changelog.d/2026-08-04-configless-extension.md +0 -1
  48. dirsql-0.4.22/packages/rust/changelog.d/2026-08-10-dirsql-function.md +0 -1
  49. dirsql-0.4.22/packages/rust/changelog.d/2026-08-10-remove-query-hooks.md +0 -3
  50. dirsql-0.4.22/packages/rust/changelog.d/2026-08-11-oneshot-query-no-timeout.md +0 -3
  51. dirsql-0.4.22/packages/rust/changelog.d/2026-08-11-persist-parsed-path-tables.md +0 -4
  52. dirsql-0.4.22/packages/rust/changelog.d/2026-08-11-retire-hook-timeout.md +0 -3
  53. dirsql-0.4.22/packages/rust/changelog.d/2026-08-12-unquote-inverts-quote-literal.md +0 -3
  54. dirsql-0.4.22/packages/rust/changelog.d/README.md +0 -17
  55. dirsql-0.4.22/packages/rust/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -52
  56. dirsql-0.4.22/packages/rust/migrations.d/2026-07-13-fan-out-file-table-matching.md +0 -70
  57. dirsql-0.4.22/packages/rust/migrations.d/2026-07-13-persist-wal.md +0 -38
  58. dirsql-0.4.22/packages/rust/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -54
  59. dirsql-0.4.22/packages/rust/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -46
  60. dirsql-0.4.22/packages/rust/migrations.d/2026-07-13-subcommand-local-config-flags.md +0 -50
  61. dirsql-0.4.22/packages/rust/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -67
  62. dirsql-0.4.22/packages/rust/migrations.d/2026-07-20-path-table-glob-semantics.md +0 -57
  63. dirsql-0.4.22/packages/rust/migrations.d/2026-07-21-remove-glob-captures.md +0 -53
  64. dirsql-0.4.22/packages/rust/migrations.d/2026-07-23-init-escalation-example.md +0 -64
  65. dirsql-0.4.22/packages/rust/migrations.d/2026-07-23-query-default-cli.md +0 -55
  66. dirsql-0.4.22/packages/rust/migrations.d/2026-07-24-hookless-table-config-error.md +0 -51
  67. dirsql-0.4.22/packages/rust/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -55
  68. dirsql-0.4.22/packages/rust/migrations.d/2026-08-02-per-file-scan-failures.md +0 -100
  69. dirsql-0.4.22/packages/rust/migrations.d/2026-08-03-gitignore-by-default.md +0 -52
  70. dirsql-0.4.22/packages/rust/migrations.d/2026-08-03-nested-default-ignores.md +0 -46
  71. dirsql-0.4.22/packages/rust/migrations.d/2026-08-10-remove-query-hooks.md +0 -47
  72. dirsql-0.4.22/packages/rust/migrations.d/2026-08-11-oneshot-query-no-timeout.md +0 -46
  73. dirsql-0.4.22/packages/rust/migrations.d/2026-08-11-persist-parsed-path-tables.md +0 -58
  74. dirsql-0.4.22/packages/rust/migrations.d/2026-08-11-retire-hook-timeout.md +0 -51
  75. dirsql-0.4.22/packages/rust/migrations.d/README.md +0 -19
  76. {dirsql-0.4.22 → dirsql-0.4.24}/Cargo.toml +0 -0
  77. {dirsql-0.4.22 → dirsql-0.4.24}/README.md +0 -0
  78. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/__init__.py +0 -0
  79. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/_async.py +0 -0
  80. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/_dirsql.pyi +0 -0
  81. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/cli/__init__.py +0 -0
  82. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/cli/discover_plugins/__init__.py +0 -0
  83. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
  84. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
  85. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
  86. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
  87. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
  88. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/cli/main.py +0 -0
  89. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/cli/resolve_config_extensions.py +0 -0
  90. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/py.typed +0 -0
  91. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/resolve_config_extensions.py +0 -0
  92. {dirsql-0.4.22 → dirsql-0.4.24}/dirsql/resolve_extension.py +0 -0
  93. {dirsql-0.4.22 → dirsql-0.4.24}/docs/.claude/CLAUDE.md +0 -0
  94. {dirsql-0.4.22 → dirsql-0.4.24}/docs/.vitepress/theme/index.ts +0 -0
  95. {dirsql-0.4.22 → dirsql-0.4.24}/docs/.vitepress/theme/lang.ts +0 -0
  96. {dirsql-0.4.22 → dirsql-0.4.24}/docs/AGENTS.md +0 -0
  97. {dirsql-0.4.22 → dirsql-0.4.24}/docs/explanation.md +0 -0
  98. {dirsql-0.4.22 → dirsql-0.4.24}/docs/getting-started.md +0 -0
  99. {dirsql-0.4.22 → dirsql-0.4.24}/docs/howto/columns-from-paths.md +0 -0
  100. {dirsql-0.4.22 → dirsql-0.4.24}/docs/howto/define-tables.md +0 -0
  101. {dirsql-0.4.22 → dirsql-0.4.24}/docs/howto/embed.md +0 -0
  102. {dirsql-0.4.22 → dirsql-0.4.24}/docs/howto/load-extension.md +0 -0
  103. {dirsql-0.4.22 → dirsql-0.4.24}/docs/howto/parse-files-into-columns.md +0 -0
  104. {dirsql-0.4.22 → dirsql-0.4.24}/docs/howto/persist.md +0 -0
  105. {dirsql-0.4.22 → dirsql-0.4.24}/docs/howto/query-without-config.md +0 -0
  106. {dirsql-0.4.22 → dirsql-0.4.24}/docs/howto/react-to-changes.md +0 -0
  107. {dirsql-0.4.22 → dirsql-0.4.24}/docs/howto/search-by-meaning.md +0 -0
  108. {dirsql-0.4.22 → dirsql-0.4.24}/docs/howto/skip-files.md +0 -0
  109. {dirsql-0.4.22 → dirsql-0.4.24}/docs/howto/write-a-plugin.md +0 -0
  110. {dirsql-0.4.22 → dirsql-0.4.24}/docs/index.md +0 -0
  111. {dirsql-0.4.22 → dirsql-0.4.24}/docs/package.json +0 -0
  112. {dirsql-0.4.22 → dirsql-0.4.24}/docs/plugins.md +0 -0
  113. {dirsql-0.4.22 → dirsql-0.4.24}/docs/pnpm-lock.yaml +0 -0
  114. {dirsql-0.4.22 → dirsql-0.4.24}/docs/pnpm-workspace.yaml +0 -0
  115. {dirsql-0.4.22 → dirsql-0.4.24}/docs/reference/cli.md +0 -0
  116. {dirsql-0.4.22 → dirsql-0.4.24}/docs/reference/columns.md +0 -0
  117. {dirsql-0.4.22 → dirsql-0.4.24}/docs/reference/config.md +0 -0
  118. {dirsql-0.4.22 → dirsql-0.4.24}/docs/reference/hooks.md +0 -0
  119. {dirsql-0.4.22 → dirsql-0.4.24}/docs/reference/http-api.md +0 -0
  120. {dirsql-0.4.22 → dirsql-0.4.24}/docs/reference/sdk.md +0 -0
  121. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/CHANGELOG.md +0 -0
  122. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/MIGRATIONS.md +0 -0
  123. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/README.md +0 -0
  124. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  125. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
  126. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  127. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
  128. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  129. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  130. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  131. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
  132. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  133. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
  134. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
  135. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
  136. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
  137. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
  138. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
  139. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
  140. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
  141. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/changelog.d/README.md +0 -0
  142. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/conftest.py +0 -0
  143. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/.claude/CLAUDE.md +0 -0
  144. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  145. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  146. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/AGENTS.md +0 -0
  147. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/explanation.md +0 -0
  148. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/getting-started.md +0 -0
  149. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/howto/columns-from-paths.md +0 -0
  150. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/howto/define-tables.md +0 -0
  151. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/howto/embed.md +0 -0
  152. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/howto/load-extension.md +0 -0
  153. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
  154. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/howto/persist.md +0 -0
  155. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/howto/query-without-config.md +0 -0
  156. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/howto/react-to-changes.md +0 -0
  157. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/howto/search-by-meaning.md +0 -0
  158. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/howto/skip-files.md +0 -0
  159. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/howto/write-a-plugin.md +0 -0
  160. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/index.md +0 -0
  161. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/package.json +0 -0
  162. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/plugins.md +0 -0
  163. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/pnpm-lock.yaml +0 -0
  164. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/pnpm-workspace.yaml +0 -0
  165. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/reference/cli.md +0 -0
  166. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/reference/columns.md +0 -0
  167. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/reference/config.md +0 -0
  168. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/reference/hooks.md +0 -0
  169. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/reference/http-api.md +0 -0
  170. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/docs/reference/sdk.md +0 -0
  171. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
  172. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
  173. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
  174. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  175. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  176. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  177. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  178. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  179. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
  180. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  181. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
  182. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
  183. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/migrations.d/README.md +0 -0
  184. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/src/lib.rs +0 -0
  185. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/testing-conventions.toml +0 -0
  186. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/tests/__init__.py +0 -0
  187. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/tests/conftest.py +0 -0
  188. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/tests/e2e/__init__.py +0 -0
  189. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
  190. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
  191. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/tests/integration/__init__.py +0 -0
  192. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/tests/integration/binding/__init__.py +0 -0
  193. {dirsql-0.4.22 → dirsql-0.4.24}/packages/python/tests/integration/hermetic/__init__.py +0 -0
  194. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/CHANGELOG.md +0 -0
  195. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/MIGRATIONS.md +0 -0
  196. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/README.md +0 -0
  197. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/benches/db_bench.rs +0 -0
  198. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/benches/differ_bench.rs +0 -0
  199. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/benches/matcher_bench.rs +0 -0
  200. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/benches/scanner_bench.rs +0 -0
  201. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/explanation.md +0 -0
  202. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/getting-started.md +0 -0
  203. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/howto/columns-from-paths.md +0 -0
  204. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/howto/define-tables.md +0 -0
  205. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/howto/embed.md +0 -0
  206. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/howto/load-extension.md +0 -0
  207. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
  208. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/howto/persist.md +0 -0
  209. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/howto/query-without-config.md +0 -0
  210. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/howto/react-to-changes.md +0 -0
  211. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/howto/search-by-meaning.md +0 -0
  212. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/howto/skip-files.md +0 -0
  213. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/howto/write-a-plugin.md +0 -0
  214. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/index.md +0 -0
  215. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/plugins.md +0 -0
  216. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/reference/cli.md +0 -0
  217. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/reference/columns.md +0 -0
  218. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/reference/config.md +0 -0
  219. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/reference/hooks.md +0 -0
  220. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/reference/http-api.md +0 -0
  221. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/docs/reference/sdk.md +0 -0
  222. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/bin/dirsql.rs +0 -0
  223. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/cli/execute.rs +0 -0
  224. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/cli/init.rs +0 -0
  225. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/cli/mod.rs +0 -0
  226. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/cli/router.rs +0 -0
  227. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/cli/run.rs +0 -0
  228. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/cli/serialize.rs +0 -0
  229. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/cli/server.rs +0 -0
  230. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/command.rs +0 -0
  231. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/config.rs +0 -0
  232. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/default_config.toml +0 -0
  233. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/differ.rs +0 -0
  234. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/functions.rs +0 -0
  235. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/infer.rs +0 -0
  236. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/lib.rs +0 -0
  237. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/matcher.rs +0 -0
  238. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/parsed_cache.rs +0 -0
  239. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/parsed_vtab.rs +0 -0
  240. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/path_table.rs +0 -0
  241. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/persist.rs +0 -0
  242. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/scanner.rs +0 -0
  243. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/sql_literal.rs +0 -0
  244. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/vtab.rs +0 -0
  245. {dirsql-0.4.22 → dirsql-0.4.24}/packages/rust/src/watcher.rs +0 -0
  246. {dirsql-0.4.22 → dirsql-0.4.24}/pyproject.toml +0 -0
@@ -499,7 +499,7 @@ dependencies = [
499
499
 
500
500
  [[package]]
501
501
  name = "dirsql-py-ext"
502
- version = "0.4.22"
502
+ version = "0.4.24"
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.22
3
+ Version: 0.4.24
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
@@ -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' },
@@ -77,6 +77,9 @@ SQLite value mapping is under
77
77
 
78
78
  ## Going further
79
79
 
80
+ - Just want to read a field or two out of some JSON files? SQLite's JSON
81
+ operators work directly on a path-table's `content` column, with no config
82
+ and no command — [Query JSON file contents](./query-json.md).
80
83
  - The command re-runs on every startup and on every change to a matched
81
84
  file. If it is expensive, [keep the index across restarts](./persist.md).
82
85
  - Embedding `dirsql` in a program instead? The SDK's `on_file` callback
@@ -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.
@@ -61,6 +61,17 @@ SELECT * FROM '**/*.md';
61
61
  -- no such table: **/*.md; did you mean './**/*.md'?
62
62
  ```
63
63
 
64
+ **The quotes are required too.** A path is not a bare SQL identifier — `./` is
65
+ punctuation to SQLite's parser, so an unquoted path fails at parse time, before
66
+ dirsql ever sees a table name to resolve. Single or double quotes both work;
67
+ the error names the quoted form:
68
+
69
+ ```
70
+ SELECT * FROM ./;
71
+ -- near ".": syntax error in SELECT * FROM ./ at offset 14
72
+ -- hint: paths used as table names must be quoted; did you mean "./"?
73
+ ```
74
+
64
75
  ### Paths outside the index root
65
76
 
66
77
  Three other prefixes resolve, with their usual shell meanings:
@@ -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.22"
7
+ version = "0.4.24"
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
@@ -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' },
@@ -77,6 +77,9 @@ SQLite value mapping is under
77
77
 
78
78
  ## Going further
79
79
 
80
+ - Just want to read a field or two out of some JSON files? SQLite's JSON
81
+ operators work directly on a path-table's `content` column, with no config
82
+ and no command — [Query JSON file contents](./query-json.md).
80
83
  - The command re-runs on every startup and on every change to a matched
81
84
  file. If it is expensive, [keep the index across restarts](./persist.md).
82
85
  - Embedding `dirsql` in a program instead? The SDK's `on_file` callback
@@ -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.
@@ -61,6 +61,17 @@ SELECT * FROM '**/*.md';
61
61
  -- no such table: **/*.md; did you mean './**/*.md'?
62
62
  ```
63
63
 
64
+ **The quotes are required too.** A path is not a bare SQL identifier — `./` is
65
+ punctuation to SQLite's parser, so an unquoted path fails at parse time, before
66
+ dirsql ever sees a table name to resolve. Single or double quotes both work;
67
+ the error names the quoted form:
68
+
69
+ ```
70
+ SELECT * FROM ./;
71
+ -- near ".": syntax error in SELECT * FROM ./ at offset 14
72
+ -- hint: paths used as table names must be quoted; did you mean "./"?
73
+ ```
74
+
64
75
  ### Paths outside the index root
65
76
 
66
77
  Three other prefixes resolve, with their usual shell meanings:
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "uv run python -m pytest tests/e2e/ -x -q",
3
+ "ran_at": 1787248002,
4
+ "exit_code": 0,
5
+ "commit": "a4c7c1da17d99d040f01b9bab77cd12014b76320",
6
+ "branch": "claude/issue-951-0eease"
7
+ }
@@ -19,8 +19,14 @@ repository.workspace = true
19
19
  # `tests/` is the integration suite -- excluded so test files never ship in the
20
20
  # published `.crate` (enforced by the `packaging` gate in CI). Inline unit tests
21
21
  # stay (they are `#[cfg(test)]` modules inside `src/`, not separate files).
22
+ # The fragment dirs are repo inputs -- one file per change, assembled into
23
+ # nothing and read by no crate consumer. They need naming here because cargo
24
+ # ships whatever is not excluded; npm and maturin drop theirs structurally, via
25
+ # an allowlist and the wheel layout respectively.
22
26
  exclude = [
23
27
  "tests/",
28
+ "changelog.d/",
29
+ "migrations.d/",
24
30
  "docs/.vitepress",
25
31
  "docs/.claude",
26
32
  "docs/tests",
@@ -77,6 +77,9 @@ SQLite value mapping is under
77
77
 
78
78
  ## Going further
79
79
 
80
+ - Just want to read a field or two out of some JSON files? SQLite's JSON
81
+ operators work directly on a path-table's `content` column, with no config
82
+ and no command — [Query JSON file contents](./query-json.md).
80
83
  - The command re-runs on every startup and on every change to a matched
81
84
  file. If it is expensive, [keep the index across restarts](./persist.md).
82
85
  - Embedding `dirsql` in a program instead? The SDK's `on_file` callback