dirsql 0.4.19__tar.gz → 0.4.20__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 (244) hide show
  1. {dirsql-0.4.19 → dirsql-0.4.20}/Cargo.lock +1 -1
  2. {dirsql-0.4.19 → dirsql-0.4.20}/PKG-INFO +1 -1
  3. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/Cargo.toml +1 -1
  4. dirsql-0.4.20/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +7 -0
  5. dirsql-0.4.20/packages/rust/changelog.d/2026-08-12-unquote-inverts-quote-literal.md +3 -0
  6. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/db.rs +1 -19
  7. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/lib.rs +2 -0
  8. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/parsed_vtab.rs +1 -42
  9. dirsql-0.4.20/packages/rust/src/sql_literal.rs +127 -0
  10. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/vtab.rs +1 -42
  11. {dirsql-0.4.19 → dirsql-0.4.20}/Cargo.toml +0 -0
  12. {dirsql-0.4.19 → dirsql-0.4.20}/README.md +0 -0
  13. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/__init__.py +0 -0
  14. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/_async.py +0 -0
  15. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/_dirsql.pyi +0 -0
  16. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/cli/__init__.py +0 -0
  17. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/cli/discover_plugins/__init__.py +0 -0
  18. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
  19. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
  20. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
  21. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
  22. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
  23. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/cli/main.py +0 -0
  24. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/cli/resolve_config_extensions.py +0 -0
  25. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/py.typed +0 -0
  26. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/resolve_config_extensions.py +0 -0
  27. {dirsql-0.4.19 → dirsql-0.4.20}/dirsql/resolve_extension.py +0 -0
  28. {dirsql-0.4.19 → dirsql-0.4.20}/docs/.claude/CLAUDE.md +0 -0
  29. {dirsql-0.4.19 → dirsql-0.4.20}/docs/.vitepress/config.ts +0 -0
  30. {dirsql-0.4.19 → dirsql-0.4.20}/docs/.vitepress/theme/index.ts +0 -0
  31. {dirsql-0.4.19 → dirsql-0.4.20}/docs/.vitepress/theme/lang.ts +0 -0
  32. {dirsql-0.4.19 → dirsql-0.4.20}/docs/AGENTS.md +0 -0
  33. {dirsql-0.4.19 → dirsql-0.4.20}/docs/explanation.md +0 -0
  34. {dirsql-0.4.19 → dirsql-0.4.20}/docs/getting-started.md +0 -0
  35. {dirsql-0.4.19 → dirsql-0.4.20}/docs/howto/columns-from-paths.md +0 -0
  36. {dirsql-0.4.19 → dirsql-0.4.20}/docs/howto/define-tables.md +0 -0
  37. {dirsql-0.4.19 → dirsql-0.4.20}/docs/howto/embed.md +0 -0
  38. {dirsql-0.4.19 → dirsql-0.4.20}/docs/howto/extract-from-contents.md +0 -0
  39. {dirsql-0.4.19 → dirsql-0.4.20}/docs/howto/load-extension.md +0 -0
  40. {dirsql-0.4.19 → dirsql-0.4.20}/docs/howto/parse-files-into-columns.md +0 -0
  41. {dirsql-0.4.19 → dirsql-0.4.20}/docs/howto/persist.md +0 -0
  42. {dirsql-0.4.19 → dirsql-0.4.20}/docs/howto/query-without-config.md +0 -0
  43. {dirsql-0.4.19 → dirsql-0.4.20}/docs/howto/react-to-changes.md +0 -0
  44. {dirsql-0.4.19 → dirsql-0.4.20}/docs/howto/search-by-meaning.md +0 -0
  45. {dirsql-0.4.19 → dirsql-0.4.20}/docs/howto/skip-files.md +0 -0
  46. {dirsql-0.4.19 → dirsql-0.4.20}/docs/howto/write-a-plugin.md +0 -0
  47. {dirsql-0.4.19 → dirsql-0.4.20}/docs/index.md +0 -0
  48. {dirsql-0.4.19 → dirsql-0.4.20}/docs/migrations.md +0 -0
  49. {dirsql-0.4.19 → dirsql-0.4.20}/docs/package.json +0 -0
  50. {dirsql-0.4.19 → dirsql-0.4.20}/docs/plugins.md +0 -0
  51. {dirsql-0.4.19 → dirsql-0.4.20}/docs/pnpm-lock.yaml +0 -0
  52. {dirsql-0.4.19 → dirsql-0.4.20}/docs/pnpm-workspace.yaml +0 -0
  53. {dirsql-0.4.19 → dirsql-0.4.20}/docs/reference/cli.md +0 -0
  54. {dirsql-0.4.19 → dirsql-0.4.20}/docs/reference/columns.md +0 -0
  55. {dirsql-0.4.19 → dirsql-0.4.20}/docs/reference/config.md +0 -0
  56. {dirsql-0.4.19 → dirsql-0.4.20}/docs/reference/hooks.md +0 -0
  57. {dirsql-0.4.19 → dirsql-0.4.20}/docs/reference/http-api.md +0 -0
  58. {dirsql-0.4.19 → dirsql-0.4.20}/docs/reference/path-tables.md +0 -0
  59. {dirsql-0.4.19 → dirsql-0.4.20}/docs/reference/sdk.md +0 -0
  60. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/CHANGELOG.md +0 -0
  61. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/MIGRATIONS.md +0 -0
  62. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/README.md +0 -0
  63. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  64. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
  65. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  66. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
  67. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  68. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  69. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  70. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
  71. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  72. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
  73. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
  74. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
  75. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
  76. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
  77. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
  78. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
  79. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
  80. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/changelog.d/README.md +0 -0
  81. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/conftest.py +0 -0
  82. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/.claude/CLAUDE.md +0 -0
  83. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/.vitepress/config.ts +0 -0
  84. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  85. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  86. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/AGENTS.md +0 -0
  87. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/explanation.md +0 -0
  88. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/getting-started.md +0 -0
  89. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/howto/columns-from-paths.md +0 -0
  90. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/howto/define-tables.md +0 -0
  91. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/howto/embed.md +0 -0
  92. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/howto/extract-from-contents.md +0 -0
  93. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/howto/load-extension.md +0 -0
  94. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
  95. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/howto/persist.md +0 -0
  96. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/howto/query-without-config.md +0 -0
  97. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/howto/react-to-changes.md +0 -0
  98. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/howto/search-by-meaning.md +0 -0
  99. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/howto/skip-files.md +0 -0
  100. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/howto/write-a-plugin.md +0 -0
  101. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/index.md +0 -0
  102. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/migrations.md +0 -0
  103. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/package.json +0 -0
  104. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/plugins.md +0 -0
  105. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/pnpm-lock.yaml +0 -0
  106. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/pnpm-workspace.yaml +0 -0
  107. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/reference/cli.md +0 -0
  108. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/reference/columns.md +0 -0
  109. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/reference/config.md +0 -0
  110. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/reference/hooks.md +0 -0
  111. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/reference/http-api.md +0 -0
  112. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/reference/path-tables.md +0 -0
  113. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/docs/reference/sdk.md +0 -0
  114. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
  115. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
  116. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  117. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  118. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  119. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  120. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  121. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
  122. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  123. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
  124. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
  125. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/migrations.d/README.md +0 -0
  126. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/src/lib.rs +0 -0
  127. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/tests/__init__.py +0 -0
  128. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/tests/conftest.py +0 -0
  129. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/tests/e2e/__init__.py +0 -0
  130. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
  131. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
  132. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/tests/integration/__init__.py +0 -0
  133. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/tests/integration/binding/__init__.py +0 -0
  134. {dirsql-0.4.19 → dirsql-0.4.20}/packages/python/tests/integration/hermetic/__init__.py +0 -0
  135. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/CHANGELOG.md +0 -0
  136. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/Cargo.toml +0 -0
  137. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/MIGRATIONS.md +0 -0
  138. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/README.md +0 -0
  139. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/benches/db_bench.rs +0 -0
  140. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/benches/differ_bench.rs +0 -0
  141. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/benches/matcher_bench.rs +0 -0
  142. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/benches/scanner_bench.rs +0 -0
  143. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-13-batch-ingest-transaction.md +0 -0
  144. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-13-chained-pre-post-query-hooks.md +0 -0
  145. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  146. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-13-fan-out-file-table-matching.md +0 -0
  147. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-13-persist-wal.md +0 -0
  148. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  149. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-13-repeatable-builder-config.md +0 -0
  150. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-13-repeatable-cli-config.md +0 -0
  151. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  152. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-13-subcommand-local-config-flags.md +0 -0
  153. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-19-path-table-query-fallback.md +0 -0
  154. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-19-path-table-vtab.md +0 -0
  155. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  156. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-20-path-table-glob-semantics.md +0 -0
  157. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-20-schema-inference.md +0 -0
  158. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-21-on-file-flag.md +0 -0
  159. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  160. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-23-init-escalation-example.md +0 -0
  161. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-23-query-default-cli.md +0 -0
  162. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
  163. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  164. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-07-29-on-file-failures-accumulate.md +0 -0
  165. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-08-02-drop-regex.md +0 -0
  166. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-08-02-per-file-scan-failures.md +0 -0
  167. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-08-02-release-profile.md +0 -0
  168. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-08-03-gitignore-by-default.md +0 -0
  169. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-08-03-nested-default-ignores.md +0 -0
  170. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-08-04-cast-lints.md +0 -0
  171. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-08-04-cli-run-shim.md +0 -0
  172. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-08-04-configless-extension.md +0 -0
  173. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-08-10-dirsql-function.md +0 -0
  174. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-08-10-remove-query-hooks.md +0 -0
  175. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-08-11-oneshot-query-no-timeout.md +0 -0
  176. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-08-11-persist-parsed-path-tables.md +0 -0
  177. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/2026-08-11-retire-hook-timeout.md +0 -0
  178. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/changelog.d/README.md +0 -0
  179. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/explanation.md +0 -0
  180. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/getting-started.md +0 -0
  181. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/howto/columns-from-paths.md +0 -0
  182. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/howto/define-tables.md +0 -0
  183. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/howto/embed.md +0 -0
  184. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/howto/extract-from-contents.md +0 -0
  185. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/howto/load-extension.md +0 -0
  186. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
  187. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/howto/persist.md +0 -0
  188. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/howto/query-without-config.md +0 -0
  189. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/howto/react-to-changes.md +0 -0
  190. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/howto/search-by-meaning.md +0 -0
  191. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/howto/skip-files.md +0 -0
  192. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/howto/write-a-plugin.md +0 -0
  193. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/index.md +0 -0
  194. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/migrations.md +0 -0
  195. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/plugins.md +0 -0
  196. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/reference/cli.md +0 -0
  197. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/reference/columns.md +0 -0
  198. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/reference/config.md +0 -0
  199. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/reference/hooks.md +0 -0
  200. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/reference/http-api.md +0 -0
  201. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/reference/path-tables.md +0 -0
  202. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/docs/reference/sdk.md +0 -0
  203. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  204. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-07-13-fan-out-file-table-matching.md +0 -0
  205. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-07-13-persist-wal.md +0 -0
  206. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  207. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  208. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-07-13-subcommand-local-config-flags.md +0 -0
  209. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  210. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-07-20-path-table-glob-semantics.md +0 -0
  211. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  212. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-07-23-init-escalation-example.md +0 -0
  213. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-07-23-query-default-cli.md +0 -0
  214. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
  215. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  216. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-08-02-per-file-scan-failures.md +0 -0
  217. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-08-03-gitignore-by-default.md +0 -0
  218. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-08-03-nested-default-ignores.md +0 -0
  219. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-08-10-remove-query-hooks.md +0 -0
  220. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-08-11-oneshot-query-no-timeout.md +0 -0
  221. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-08-11-persist-parsed-path-tables.md +0 -0
  222. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/2026-08-11-retire-hook-timeout.md +0 -0
  223. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/migrations.d/README.md +0 -0
  224. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/bin/dirsql.rs +0 -0
  225. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/cli/execute.rs +0 -0
  226. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/cli/init.rs +0 -0
  227. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/cli/mod.rs +0 -0
  228. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/cli/router.rs +0 -0
  229. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/cli/run.rs +0 -0
  230. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/cli/serialize.rs +0 -0
  231. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/cli/server.rs +0 -0
  232. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/command.rs +0 -0
  233. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/config.rs +0 -0
  234. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/default_config.toml +0 -0
  235. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/differ.rs +0 -0
  236. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/functions.rs +0 -0
  237. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/infer.rs +0 -0
  238. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/matcher.rs +0 -0
  239. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/parsed_cache.rs +0 -0
  240. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/path_table.rs +0 -0
  241. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/persist.rs +0 -0
  242. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/scanner.rs +0 -0
  243. {dirsql-0.4.19 → dirsql-0.4.20}/packages/rust/src/watcher.rs +0 -0
  244. {dirsql-0.4.19 → dirsql-0.4.20}/pyproject.toml +0 -0
@@ -499,7 +499,7 @@ dependencies = [
499
499
 
500
500
  [[package]]
501
501
  name = "dirsql-py-ext"
502
- version = "0.4.19"
502
+ version = "0.4.20"
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.19
3
+ Version: 0.4.20
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
@@ -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.19"
7
+ version = "0.4.20"
8
8
  # abi3 note: the `abi3-py310` pyo3 feature (below) builds ONE stable-ABI
9
9
  # `cp310-abi3` wheel per platform that loads on every CPython >= 3.10
10
10
  # (matching `pyproject.toml`'s `requires-python = ">=3.10"`), instead of
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "uv run python -m pytest tests/e2e/ -x -q",
3
+ "ran_at": 1786553201,
4
+ "exit_code": 0,
5
+ "commit": "859a062ab1c795d43af357130dc1587ef9e77db0",
6
+ "branch": "claude/827-unquote-doubled-quotes"
7
+ }
@@ -0,0 +1,3 @@
1
+ **Fixed**
2
+
3
+ - **A path-table argument containing a single quote now reaches the module as written.** `dirsql --on-file "sh -c 'jq . \"$1\"' sh {path}"` — `sh -c '…'` being the documented way to ask for a shell — arrived at the parser as `sh -c ''…''` and ran a different script. Minting a path-table writes its arguments as SQL literals, where an embedded quote is escaped by doubling; the modules stripped the surrounding quotes without undoing the doubling. The same corruption applied to any glob or ignore pattern carrying a quote. `quote_literal`, `quote_identifier` and `unquote` now live together in one module with a round-trip property test, so the encoder and decoder cannot drift apart again. (#827)
@@ -6,6 +6,7 @@ use thiserror::Error;
6
6
  use crate::parsed_vtab;
7
7
  use crate::path_table::{self, PathTable, Resolution};
8
8
  use crate::scanner;
9
+ use crate::sql_literal::{quote_identifier, quote_literal};
9
10
  use crate::vtab;
10
11
 
11
12
  /// The user's home directory, if the platform reports one. Injected here so
@@ -94,15 +95,6 @@ fn no_home_path_table(name: &str) -> String {
94
95
  }
95
96
 
96
97
  /// Wrap `s` as a SQL string literal.
97
- fn quote_literal(s: &str) -> String {
98
- format!("'{}'", s.replace('\'', "''"))
99
- }
100
-
101
- /// Wrap `s` as a double-quoted SQL identifier.
102
- fn quote_identifier(s: &str) -> String {
103
- format!("\"{}\"", s.replace('"', "\"\""))
104
- }
105
-
106
98
  /// The DDL that mints a path-table.
107
99
  ///
108
100
  /// It lands in `temp`, which is per-connection and never written to the
@@ -2174,16 +2166,6 @@ mod tests {
2174
2166
  );
2175
2167
  }
2176
2168
 
2177
- #[test]
2178
- fn quote_literal_doubles_embedded_quotes() {
2179
- assert_eq!(quote_literal("it's"), "'it''s'");
2180
- }
2181
-
2182
- #[test]
2183
- fn quote_identifier_doubles_embedded_quotes() {
2184
- assert_eq!(quote_identifier("a\"b"), "\"a\"\"b\"");
2185
- }
2186
-
2187
2169
  fn docs_path_table() -> PathTable {
2188
2170
  PathTable {
2189
2171
  root: PathBuf::from("/root"),
@@ -32,6 +32,8 @@ pub mod persist;
32
32
  #[doc(hidden)]
33
33
  pub mod scanner;
34
34
  #[doc(hidden)]
35
+ pub mod sql_literal;
36
+ #[doc(hidden)]
35
37
  pub mod vtab;
36
38
  #[doc(hidden)]
37
39
  pub mod watcher;
@@ -39,6 +39,7 @@ use crate::parsed_cache::{self, CachedParse, Entry, RowCache, SqliteRowCache};
39
39
  use crate::path_table;
40
40
  use crate::persist::{FileStat, hash_file, now_ns};
41
41
  use crate::scanner::{self, scan_glob};
42
+ use crate::sql_literal::unquote;
42
43
 
43
44
  /// SQL module name a parsed path-table is created with.
44
45
  pub const MODULE_NAME: &str = "dirsql_parsed";
@@ -49,18 +50,6 @@ pub fn load_module(conn: &Connection) -> Result<()> {
49
50
  conn.create_module(MODULE_NAME, read_only_module::<ParsedTab>(), aux)
50
51
  }
51
52
 
52
- /// Strip one layer of SQL string quoting from a `CREATE VIRTUAL TABLE`
53
- /// argument. SQLite hands module arguments through verbatim, quotes included.
54
- fn unquote(arg: &str) -> &str {
55
- let trimmed = arg.trim();
56
- for quote in ['\'', '"'] {
57
- if trimmed.len() >= 2 && trimmed.starts_with(quote) && trimmed.ends_with(quote) {
58
- return &trimmed[1..trimmed.len() - 1];
59
- }
60
- }
61
- trimmed
62
- }
63
-
64
53
  /// Number of module arguments that are not ignore patterns.
65
54
  const FIXED_ARGS: usize = 5;
66
55
 
@@ -485,36 +474,6 @@ mod tests {
485
474
  assert_eq!(MODULE_NAME, "dirsql_parsed");
486
475
  }
487
476
 
488
- #[test]
489
- fn unquote_strips_single_quotes() {
490
- assert_eq!(unquote("'./docs'"), "./docs");
491
- }
492
-
493
- #[test]
494
- fn unquote_strips_double_quotes() {
495
- assert_eq!(unquote("\"./docs\""), "./docs");
496
- }
497
-
498
- #[test]
499
- fn unquote_trims_surrounding_whitespace() {
500
- assert_eq!(unquote(" './docs' "), "./docs");
501
- }
502
-
503
- #[test]
504
- fn unquote_leaves_unquoted_arguments_alone() {
505
- assert_eq!(unquote("./docs"), "./docs");
506
- }
507
-
508
- #[test]
509
- fn unquote_leaves_a_lone_quote_alone() {
510
- assert_eq!(unquote("'"), "'");
511
- }
512
-
513
- #[test]
514
- fn unquote_leaves_mismatched_quotes_alone() {
515
- assert_eq!(unquote("'./docs\""), "'./docs\"");
516
- }
517
-
518
477
  /// The three fixed arguments SQLite prepends before the module's own.
519
478
  fn args_with<'a>(user: &[&'a [u8]]) -> Vec<&'a [u8]> {
520
479
  let mut all: Vec<&'a [u8]> = vec![
@@ -0,0 +1,127 @@
1
+ //! The one encoding a path-table's arguments travel through.
2
+ //!
3
+ //! `dirsql` mints a path-table by writing a `CREATE VIRTUAL TABLE` statement
4
+ //! whose module arguments are SQL literals ([`quote_literal`]), and SQLite
5
+ //! hands those arguments to the module verbatim, quotes included, for
6
+ //! [`unquote`] to decode. The two are inverses, and they live together so they
7
+ //! stay that way: a value that survives one but not the other reaches the
8
+ //! module as something the user never wrote.
9
+
10
+ use std::borrow::Cow;
11
+
12
+ /// Wrap `s` as a single-quoted SQL string literal.
13
+ pub fn quote_literal(s: &str) -> String {
14
+ format!("'{}'", s.replace('\'', "''"))
15
+ }
16
+
17
+ /// Wrap `s` as a double-quoted SQL identifier.
18
+ pub fn quote_identifier(s: &str) -> String {
19
+ format!("\"{}\"", s.replace('"', "\"\""))
20
+ }
21
+
22
+ /// Decode one quoted `CREATE VIRTUAL TABLE` argument: strip the surrounding
23
+ /// quotes and collapse the doubling that escaped them. Borrowed when there is
24
+ /// nothing to collapse, which is the ordinary case.
25
+ pub fn unquote(arg: &str) -> Cow<'_, str> {
26
+ let trimmed = arg.trim();
27
+ for quote in ['\'', '"'] {
28
+ if trimmed.len() >= 2 && trimmed.starts_with(quote) && trimmed.ends_with(quote) {
29
+ let inner = &trimmed[1..trimmed.len() - 1];
30
+ let doubled = [quote, quote].iter().collect::<String>();
31
+ return if inner.contains(&doubled) {
32
+ Cow::Owned(inner.replace(&doubled, &quote.to_string()))
33
+ } else {
34
+ Cow::Borrowed(inner)
35
+ };
36
+ }
37
+ }
38
+ Cow::Borrowed(trimmed)
39
+ }
40
+
41
+ #[cfg(test)]
42
+ mod tests {
43
+ use super::*;
44
+
45
+ #[test]
46
+ fn quote_literal_doubles_embedded_quotes() {
47
+ assert_eq!(quote_literal("it's"), "'it''s'");
48
+ }
49
+
50
+ #[test]
51
+ fn quote_identifier_doubles_embedded_quotes() {
52
+ assert_eq!(quote_identifier("a\"b"), "\"a\"\"b\"");
53
+ }
54
+
55
+ #[test]
56
+ fn unquote_strips_single_quotes() {
57
+ assert_eq!(unquote("'./docs'"), "./docs");
58
+ }
59
+
60
+ #[test]
61
+ fn unquote_strips_double_quotes() {
62
+ assert_eq!(unquote("\"./docs\""), "./docs");
63
+ }
64
+
65
+ #[test]
66
+ fn unquote_trims_surrounding_whitespace() {
67
+ assert_eq!(unquote(" './docs' "), "./docs");
68
+ }
69
+
70
+ #[test]
71
+ fn unquote_leaves_unquoted_arguments_alone() {
72
+ assert_eq!(unquote("./docs"), "./docs");
73
+ }
74
+
75
+ #[test]
76
+ fn unquote_leaves_a_lone_quote_alone() {
77
+ assert_eq!(unquote("'"), "'");
78
+ }
79
+
80
+ #[test]
81
+ fn unquote_leaves_mismatched_quotes_alone() {
82
+ assert_eq!(unquote("'./docs\""), "'./docs\"");
83
+ }
84
+
85
+ #[test]
86
+ fn unquote_collapses_the_doubling_that_escaped_a_quote() {
87
+ assert_eq!(unquote("'sh -c ''echo hi'''"), "sh -c 'echo hi'");
88
+ }
89
+
90
+ #[test]
91
+ fn unquote_collapses_only_the_quote_character_it_stripped() {
92
+ // A double-quote inside a single-quoted literal was never doubled, so
93
+ // collapsing it would corrupt the value in the other direction.
94
+ assert_eq!(unquote("'say \"\"hi\"\"'"), "say \"\"hi\"\"");
95
+ }
96
+
97
+ #[test]
98
+ fn unquote_borrows_when_there_is_nothing_to_collapse() {
99
+ assert!(matches!(unquote("'plain'"), Cow::Borrowed("plain")));
100
+ }
101
+
102
+ #[test]
103
+ fn unquote_inverts_quote_literal() {
104
+ for value in [
105
+ "plain",
106
+ "it's",
107
+ "sh -c 'echo hi'",
108
+ "''",
109
+ "a''b",
110
+ "say \"hi\"",
111
+ "",
112
+ ] {
113
+ assert_eq!(
114
+ unquote(&quote_literal(value)),
115
+ value,
116
+ "round trip must be lossless for {value:?}"
117
+ );
118
+ }
119
+ }
120
+
121
+ #[test]
122
+ fn unquote_inverts_quote_identifier() {
123
+ for value in ["plain", "a\"b", "./docs/*.md"] {
124
+ assert_eq!(unquote(&quote_identifier(value)), value);
125
+ }
126
+ }
127
+ }
@@ -13,6 +13,7 @@ use crate::compute_stat_virtuals;
13
13
  use crate::matcher::TableMatcher;
14
14
  use crate::path_table;
15
15
  use crate::scanner::{self, scan_glob};
16
+ use crate::sql_literal::unquote;
16
17
  use crate::{Row, Value};
17
18
 
18
19
  /// SQL module name a path-table is created with:
@@ -58,18 +59,6 @@ fn compile_glob(pattern: &str) -> Result<GlobSet> {
58
59
  scanner::compile_glob(pattern).map_err(|e| Error::ModuleError(e.to_string()))
59
60
  }
60
61
 
61
- /// Strip one layer of SQL string quoting from a `CREATE VIRTUAL TABLE`
62
- /// argument. SQLite hands module arguments through verbatim, quotes included.
63
- fn unquote(arg: &str) -> &str {
64
- let trimmed = arg.trim();
65
- for quote in ['\'', '"'] {
66
- if trimmed.len() >= 2 && trimmed.starts_with(quote) && trimmed.ends_with(quote) {
67
- return &trimmed[1..trimmed.len() - 1];
68
- }
69
- }
70
- trimmed
71
- }
72
-
73
62
  /// Read `path` as text, yielding `None` when it is unreadable or not valid
74
63
  /// UTF-8. A file that cannot be read is a NULL cell, never a failed row: the
75
64
  /// filesystem is allowed to be messy and a query over it should still return.
@@ -376,36 +365,6 @@ mod tests {
376
365
  assert_eq!(MODULE_NAME, "dirsql_path");
377
366
  }
378
367
 
379
- #[test]
380
- fn unquote_strips_single_quotes() {
381
- assert_eq!(unquote("'./docs'"), "./docs");
382
- }
383
-
384
- #[test]
385
- fn unquote_strips_double_quotes() {
386
- assert_eq!(unquote("\"./docs\""), "./docs");
387
- }
388
-
389
- #[test]
390
- fn unquote_trims_surrounding_whitespace() {
391
- assert_eq!(unquote(" './docs' "), "./docs");
392
- }
393
-
394
- #[test]
395
- fn unquote_leaves_unquoted_arguments_alone() {
396
- assert_eq!(unquote("./docs"), "./docs");
397
- }
398
-
399
- #[test]
400
- fn unquote_leaves_a_lone_quote_alone() {
401
- assert_eq!(unquote("'"), "'");
402
- }
403
-
404
- #[test]
405
- fn unquote_leaves_mismatched_quotes_alone() {
406
- assert_eq!(unquote("'./docs\""), "'./docs\"");
407
- }
408
-
409
368
  #[test]
410
369
  fn compile_glob_accepts_a_valid_pattern() {
411
370
  assert!(compile_glob("**/*.md").is_ok());
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes