dirsql 0.4.61__tar.gz → 0.4.63__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.
- {dirsql-0.4.61 → dirsql-0.4.63}/Cargo.lock +2 -2
- {dirsql-0.4.61 → dirsql-0.4.63}/PKG-INFO +1 -1
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/getting-started.md +25 -13
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/howto/columns-from-paths.md +14 -11
- {dirsql-0.4.61/packages/python → dirsql-0.4.63}/docs/howto/define-tables.md +12 -9
- {dirsql-0.4.61/packages/rust → dirsql-0.4.63}/docs/howto/extract-from-contents.md +5 -5
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/howto/parse-files-into-columns.md +22 -19
- {dirsql-0.4.61/packages/rust → dirsql-0.4.63}/docs/howto/react-to-changes.md +1 -1
- {dirsql-0.4.61/packages/rust → dirsql-0.4.63}/docs/howto/search-indexes.md +2 -2
- {dirsql-0.4.61/packages/rust → dirsql-0.4.63}/docs/howto/skip-files.md +1 -1
- {dirsql-0.4.61/packages/rust → dirsql-0.4.63}/docs/howto/write-a-plugin.md +26 -23
- {dirsql-0.4.61/packages/rust → dirsql-0.4.63}/docs/plugins.md +7 -6
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/reference/cli.md +13 -10
- {dirsql-0.4.61/packages/python → dirsql-0.4.63}/docs/reference/columns.md +4 -4
- {dirsql-0.4.61/packages/rust → dirsql-0.4.63}/docs/reference/config.md +7 -7
- {dirsql-0.4.61/packages/rust → dirsql-0.4.63}/docs/reference/hooks.md +10 -5
- {dirsql-0.4.61/packages/python → dirsql-0.4.63}/docs/reference/path-tables.md +6 -6
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/reference/sdk.md +7 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/Cargo.toml +1 -1
- {dirsql-0.4.61/packages/rust → dirsql-0.4.63/packages/python}/docs/getting-started.md +25 -13
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/howto/columns-from-paths.md +14 -11
- {dirsql-0.4.61 → dirsql-0.4.63/packages/python}/docs/howto/define-tables.md +12 -9
- {dirsql-0.4.61 → dirsql-0.4.63/packages/python}/docs/howto/extract-from-contents.md +5 -5
- {dirsql-0.4.61/packages/rust → dirsql-0.4.63/packages/python}/docs/howto/parse-files-into-columns.md +22 -19
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/howto/react-to-changes.md +1 -1
- {dirsql-0.4.61 → dirsql-0.4.63/packages/python}/docs/howto/search-indexes.md +2 -2
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/howto/skip-files.md +1 -1
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/howto/write-a-plugin.md +26 -23
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/plugins.md +7 -6
- {dirsql-0.4.61/packages/rust → dirsql-0.4.63/packages/python}/docs/reference/cli.md +13 -10
- {dirsql-0.4.61 → dirsql-0.4.63/packages/python}/docs/reference/columns.md +4 -4
- {dirsql-0.4.61 → dirsql-0.4.63/packages/python}/docs/reference/config.md +7 -7
- {dirsql-0.4.61 → dirsql-0.4.63/packages/python}/docs/reference/hooks.md +10 -5
- {dirsql-0.4.61/packages/rust → dirsql-0.4.63/packages/python}/docs/reference/path-tables.md +6 -6
- {dirsql-0.4.61/packages/rust → dirsql-0.4.63/packages/python}/docs/reference/sdk.md +7 -0
- dirsql-0.4.63/packages/python/e2e-attestations/claude-1196-join-index.json +7 -0
- dirsql-0.4.63/packages/python/e2e-attestations/claude-1215-on-file-batch.json +7 -0
- dirsql-0.4.63/packages/python/e2e-attestations/claude-1226-stale-docs.json +7 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +1 -1
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/Cargo.toml +1 -1
- {dirsql-0.4.61/packages/python → dirsql-0.4.63/packages/rust}/docs/getting-started.md +25 -13
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/docs/howto/columns-from-paths.md +14 -11
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/docs/howto/define-tables.md +12 -9
- {dirsql-0.4.61/packages/python → dirsql-0.4.63/packages/rust}/docs/howto/extract-from-contents.md +5 -5
- {dirsql-0.4.61/packages/python → dirsql-0.4.63/packages/rust}/docs/howto/parse-files-into-columns.md +22 -19
- {dirsql-0.4.61 → dirsql-0.4.63/packages/rust}/docs/howto/react-to-changes.md +1 -1
- {dirsql-0.4.61/packages/python → dirsql-0.4.63/packages/rust}/docs/howto/search-indexes.md +2 -2
- {dirsql-0.4.61 → dirsql-0.4.63/packages/rust}/docs/howto/skip-files.md +1 -1
- {dirsql-0.4.61 → dirsql-0.4.63/packages/rust}/docs/howto/write-a-plugin.md +26 -23
- {dirsql-0.4.61 → dirsql-0.4.63/packages/rust}/docs/plugins.md +7 -6
- {dirsql-0.4.61/packages/python → dirsql-0.4.63/packages/rust}/docs/reference/cli.md +13 -10
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/docs/reference/columns.md +4 -4
- {dirsql-0.4.61/packages/python → dirsql-0.4.63/packages/rust}/docs/reference/config.md +7 -7
- {dirsql-0.4.61/packages/python → dirsql-0.4.63/packages/rust}/docs/reference/hooks.md +10 -5
- {dirsql-0.4.61 → dirsql-0.4.63/packages/rust}/docs/reference/path-tables.md +6 -6
- {dirsql-0.4.61/packages/python → dirsql-0.4.63/packages/rust}/docs/reference/sdk.md +7 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/cli/run.rs +16 -12
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/command.rs +11 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/config.rs +2 -2
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/db.rs +169 -20
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/default_config.toml +7 -6
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/differ.rs +190 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/infer.rs +11 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/lib.rs +772 -251
- dirsql-0.4.63/packages/rust/src/on_file.rs +236 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/parsed_vtab.rs +185 -268
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/vtab.rs +38 -0
- dirsql-0.4.63/packages/rust/src/vtab_scaffold.rs +1138 -0
- dirsql-0.4.61/packages/rust/src/vtab_scaffold.rs +0 -562
- {dirsql-0.4.61 → dirsql-0.4.63}/Cargo.toml +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/README.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/__init__.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/_async.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/cli/discover_plugins/__init__.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/cli/main.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/cli/resolve_config_extensions.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/plan_entry_path.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/py.typed +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/read_config.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/resolve_configs_extension_specs.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/resolve_extension.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/dirsql/resolve_package.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/AGENTS.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/explanation.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/howto/embed.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/howto/persist.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/howto/query-json.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/index.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/package.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/docs/reference/http-api.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/CHANGELOG.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/MIGRATIONS.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/README.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-08-20-curtaincall-dev-dependency.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-09-04-config-paths-from-argv-module.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-09-05-config-extension-loader-split.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-09-05-resolve-config-extensions-split.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-09-05-resolve-extension-split.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-09-09-launcher-config-path-scan.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-09-17-extension-resolution-via-core.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-09-18-export-scan-failure.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-09-18-flatten-row-event-in-core.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-09-18-programmatic-extension-plan.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/2026-09-24-query-rows-in-projection-order.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/changelog.d/README.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/conftest.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/explanation.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/howto/embed.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/howto/persist.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/howto/query-json.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/index.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/package.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/docs/reference/http-api.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/cc-keen-knuth-f11gyq.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1056-py-ofpf9.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1066-p1-resolve-extension.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1078-argv-config-paths-core.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1079-p2-resolve-config-extensions.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1080-share-vtab-scaffolding.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1081-indicatif-progress.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1096-watch-moved-dir.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1109-watch-moved-out.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1119-ext-plan.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1120-py-ext.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1122-ext-cleanup.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1130-codec-crates.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1131-flatten-row-event.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1139-sse-flatten.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1140-scan-failure-export.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1148-clippy-all-targets.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1164-sigint-fatal.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1170-projection-order.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1172-on-file-path.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1173-py-projection-order.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1184-win-rel-paths.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1185-win-abs-table-names.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1186-win-test-harness.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1201-single-walk.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1204-embed-batch.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1207-win-argv-quote.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-1208-win-nonverbatim-paths.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-epic-953-slice2-reedline.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-epic-953-slice3-format.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-epic-953-stacked-prs-x59wm3.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-issue-986-red-test-e7sjrb.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-tackle-1034-cachesplit.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-tackle-1042-py12.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-tackle-956-xzen74.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6-worker-calls.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/e2e-attestations/claude-tackle-975-n8mc2h.json +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/migrations.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/migrations.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/migrations.d/2026-09-24-query-rows-in-projection-order.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/migrations.d/README.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/src/lib.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/testing-conventions.toml +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/tests/e2e/speed_of_light.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/tests/integration/binding/__init__.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/python/tests/integration/hermetic/__init__.py +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/CHANGELOG.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/MIGRATIONS.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/README.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/docs/explanation.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/docs/howto/embed.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/docs/howto/persist.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/docs/howto/query-json.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/docs/index.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/docs/reference/http-api.md +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/cli/execute.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/cli/repl.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/cli/table.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/extension_resolution.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/functions.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/launcher.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/parsed_cache.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/path_table.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/progress.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/row_event_flat.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/sql_literal.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.4.61 → dirsql-0.4.63}/pyproject.toml +0 -0
|
@@ -552,7 +552,7 @@ checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
|
|
|
552
552
|
|
|
553
553
|
[[package]]
|
|
554
554
|
name = "dirsql"
|
|
555
|
-
version = "0.4.
|
|
555
|
+
version = "0.4.63"
|
|
556
556
|
dependencies = [
|
|
557
557
|
"assert_cmd",
|
|
558
558
|
"axum",
|
|
@@ -600,7 +600,7 @@ dependencies = [
|
|
|
600
600
|
|
|
601
601
|
[[package]]
|
|
602
602
|
name = "dirsql-py-ext"
|
|
603
|
-
version = "0.4.
|
|
603
|
+
version = "0.4.63"
|
|
604
604
|
dependencies = [
|
|
605
605
|
"dirsql",
|
|
606
606
|
"pyo3",
|
|
@@ -81,11 +81,15 @@ The first run downloads the package (`npx` asks for confirmation — answer
|
|
|
81
81
|
`y`; `uvx` prints download progress), then prints the result:
|
|
82
82
|
|
|
83
83
|
```
|
|
84
|
-
|
|
84
|
+
files
|
|
85
|
+
-----
|
|
86
|
+
3
|
|
87
|
+
|
|
88
|
+
1 row
|
|
85
89
|
```
|
|
86
90
|
|
|
87
91
|
Three files, three rows. That one command scanned the directory, handed
|
|
88
|
-
SQLite one row per file, ran your SQL, and printed the answer
|
|
92
|
+
SQLite one row per file, ran your SQL, and printed the answer.
|
|
89
93
|
|
|
90
94
|
There is no named table here — you never declared one. `'./'` is a
|
|
91
95
|
[path-table](./reference/path-tables.md): a quoted path written where a table
|
|
@@ -94,8 +98,9 @@ in. The path *is* the query.
|
|
|
94
98
|
|
|
95
99
|
## 3. Select some columns
|
|
96
100
|
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
At a terminal `dirsql` prints a table; when its output is piped, it prints a
|
|
102
|
+
JSON array of row objects instead. From here on we pipe it through `jq` to
|
|
103
|
+
pretty-print. Ask for two columns instead of a count:
|
|
99
104
|
|
|
100
105
|
::: code-group
|
|
101
106
|
|
|
@@ -151,11 +156,17 @@ folder name), and prints them as a JSON row:
|
|
|
151
156
|
```bash
|
|
152
157
|
cat > note.sh <<'EOF'
|
|
153
158
|
#!/usr/bin/env sh
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
"$(
|
|
159
|
+
printf '['
|
|
160
|
+
sep=''
|
|
161
|
+
for f; do
|
|
162
|
+
title=$(sed -n 's/^# //p' "$f" | head -n1)
|
|
163
|
+
author=$(basename "$(dirname "$f")")
|
|
164
|
+
printf '%s{"title":%s,"author":%s}' "$sep" \
|
|
165
|
+
"$(jq -Rn --arg t "$title" '$t')" \
|
|
166
|
+
"$(jq -Rn --arg a "$author" '$a')"
|
|
167
|
+
sep=','
|
|
168
|
+
done
|
|
169
|
+
printf ']'
|
|
159
170
|
EOF
|
|
160
171
|
```
|
|
161
172
|
|
|
@@ -167,7 +178,7 @@ cat > .dirsql.toml <<'EOF'
|
|
|
167
178
|
name = "notes"
|
|
168
179
|
ddl = "CREATE TABLE notes (title TEXT, author TEXT)"
|
|
169
180
|
glob = "notes/**/*.md"
|
|
170
|
-
on-file = "sh note.sh
|
|
181
|
+
on-file = "sh note.sh"
|
|
171
182
|
EOF
|
|
172
183
|
```
|
|
173
184
|
|
|
@@ -176,9 +187,10 @@ Three keys define the table:
|
|
|
176
187
|
- `glob` selects which files feed the table — every `.md` at any depth under
|
|
177
188
|
`notes/`, relative to the directory the config sits in.
|
|
178
189
|
- `ddl` is ordinary `CREATE TABLE` SQL naming the columns you want to keep.
|
|
179
|
-
- `on-file` is the command run once
|
|
180
|
-
path
|
|
181
|
-
exactly what it emits — `title` from the heading, `author`
|
|
190
|
+
- `on-file` is the command run once for the table, with every matched file's
|
|
191
|
+
path appended as an argument; the JSON array it prints is the table's rows.
|
|
192
|
+
The columns are exactly what it emits — `title` from the heading, `author`
|
|
193
|
+
from the folder.
|
|
182
194
|
|
|
183
195
|
## 5. Query the table
|
|
184
196
|
|
|
@@ -15,18 +15,21 @@ photos/2024/11/hike.jpg
|
|
|
15
15
|
photos/2025/01/snow.jpg
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
Write a small parser, `pathcols.py`, that turns
|
|
19
|
-
receives the
|
|
20
|
-
row objects:
|
|
18
|
+
Write a small parser, `pathcols.py`, that turns each path into a row. It
|
|
19
|
+
receives the matched files' absolute paths as its arguments and prints one
|
|
20
|
+
JSON array of row objects:
|
|
21
21
|
|
|
22
22
|
```python
|
|
23
23
|
#!/usr/bin/env python3
|
|
24
24
|
import json, os, sys
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
rows = []
|
|
27
|
+
for path in sys.argv[1:]:
|
|
28
|
+
parts = path.split(os.sep)
|
|
29
|
+
# .../photos/<year>/<month>/<file>
|
|
30
|
+
rows.append({"year": parts[-3], "month": parts[-2],
|
|
31
|
+
"basename": os.path.basename(path)})
|
|
32
|
+
print(json.dumps(rows))
|
|
30
33
|
```
|
|
31
34
|
|
|
32
35
|
Point a table at it in `.dirsql.toml`:
|
|
@@ -36,12 +39,12 @@ Point a table at it in `.dirsql.toml`:
|
|
|
36
39
|
name = "photos"
|
|
37
40
|
ddl = "CREATE TABLE photos (year TEXT, month TEXT, basename TEXT)"
|
|
38
41
|
glob = "photos/*/*/*.jpg"
|
|
39
|
-
on-file = "python3 pathcols.py
|
|
42
|
+
on-file = "python3 pathcols.py"
|
|
40
43
|
```
|
|
41
44
|
|
|
42
|
-
The hook emits every column the table has — dirsql injects nothing.
|
|
43
|
-
|
|
44
|
-
[command hook contract](../reference/hooks.md#on-file). A column appears only
|
|
45
|
+
The hook emits every column the table has — dirsql injects nothing. The
|
|
46
|
+
matched files' absolute paths arrive as the command's trailing arguments, per
|
|
47
|
+
the [command hook contract](../reference/hooks.md#on-file). A column appears only
|
|
45
48
|
because the DDL declares it *and* the hook emits it.
|
|
46
49
|
|
|
47
50
|
## 2. Query the derived columns
|
|
@@ -10,16 +10,19 @@ persist across restarts, instead of repeating an ad-hoc
|
|
|
10
10
|
Suppose your blog posts live under `posts/`, one markdown file each. A named
|
|
11
11
|
table needs three keys: a `glob` that selects the files, a `ddl` that names
|
|
12
12
|
the columns, and an [`on-file`](../reference/config.md#table) hook that emits
|
|
13
|
-
|
|
14
|
-
reads
|
|
13
|
+
the table's rows. Put a small parser next to the config — `extract.py`, which
|
|
14
|
+
reads each post's title line and prints one JSON array of row objects:
|
|
15
15
|
|
|
16
16
|
```python
|
|
17
17
|
#!/usr/bin/env python3
|
|
18
18
|
import json, os, sys
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
rows = []
|
|
21
|
+
for path in sys.argv[1:]:
|
|
22
|
+
text = open(path, encoding="utf-8").read()
|
|
23
|
+
title = next((l[2:].strip() for l in text.splitlines() if l.startswith("# ")), None)
|
|
24
|
+
rows.append({"title": title, "slug": os.path.basename(path)[:-3]})
|
|
25
|
+
print(json.dumps(rows))
|
|
23
26
|
```
|
|
24
27
|
|
|
25
28
|
Then declare the table in `.dirsql.toml`:
|
|
@@ -29,15 +32,15 @@ Then declare the table in `.dirsql.toml`:
|
|
|
29
32
|
name = "posts"
|
|
30
33
|
ddl = "CREATE TABLE posts (title TEXT, slug TEXT)"
|
|
31
34
|
glob = "posts/**/*.md"
|
|
32
|
-
on-file = "python3 extract.py
|
|
35
|
+
on-file = "python3 extract.py"
|
|
33
36
|
```
|
|
34
37
|
|
|
35
38
|
- `glob` selects the files: every `.md` under `posts/`, at any depth, relative
|
|
36
39
|
to the directory containing the config.
|
|
37
40
|
- `ddl` is a plain SQLite `CREATE TABLE` naming the columns you want to keep.
|
|
38
41
|
- `on-file` is **required** — it is where the table's rows come from. dirsql
|
|
39
|
-
injects nothing; the hook emits every column, reading the
|
|
40
|
-
|
|
42
|
+
injects nothing; the hook emits every column, reading the files (their
|
|
43
|
+
paths are its arguments) and deriving whatever it needs. A `[[table]]` with no `on-file` is
|
|
41
44
|
a [config error](../reference/config.md#parse-errors). For plain stat
|
|
42
45
|
columns with no code, query the path directly with a path-table instead.
|
|
43
46
|
|
|
@@ -75,7 +78,7 @@ two triggers:
|
|
|
75
78
|
[[table]]
|
|
76
79
|
name = "posts"
|
|
77
80
|
glob = "posts/**/*.md"
|
|
78
|
-
on-file = "python3 extract.py
|
|
81
|
+
on-file = "python3 extract.py"
|
|
79
82
|
ddl = '''
|
|
80
83
|
CREATE TABLE posts (title TEXT, slug TEXT, body TEXT);
|
|
81
84
|
CREATE INDEX posts_slug ON posts(slug);
|
|
@@ -21,11 +21,11 @@ stdout works. With [`jq`](https://jqlang.org/):
|
|
|
21
21
|
name = "books"
|
|
22
22
|
ddl = "CREATE TABLE books (title TEXT, author TEXT, year INTEGER)"
|
|
23
23
|
glob = "books/*.json"
|
|
24
|
-
on-file = "jq -c '[{title, author, year}]'
|
|
24
|
+
on-file = "jq -c -n '[inputs | {title, author, year}]'"
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
The command runs once for the table, with every matched file's absolute path
|
|
28
|
+
appended as an argument, and prints one array for all of them — the
|
|
29
29
|
[command hook contract](../reference/hooks.md#on-file), which also covers
|
|
30
30
|
the argv splitting, working directory, stdout protocol, and timeout shared
|
|
31
31
|
by every hook.
|
|
@@ -45,7 +45,7 @@ dirsql query "SELECT title, author, year FROM books ORDER BY year" -c ./.dirsql.
|
|
|
45
45
|
|
|
46
46
|
The table's columns are exactly what the command emits, narrowed to the DDL —
|
|
47
47
|
`dirsql` adds nothing. To include the file's `path`, have the command emit it
|
|
48
|
-
(it has
|
|
48
|
+
(it has the path); dirsql will not merge it in for you.
|
|
49
49
|
|
|
50
50
|
## Multiple rows per file
|
|
51
51
|
|
|
@@ -57,7 +57,7 @@ row per line, slurp it:
|
|
|
57
57
|
name = "events"
|
|
58
58
|
ddl = "CREATE TABLE events (event TEXT, user TEXT)"
|
|
59
59
|
glob = "logs/*.jsonl"
|
|
60
|
-
on-file = "jq -c -s '.'
|
|
60
|
+
on-file = "jq -c -s '.'"
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
```bash
|
|
@@ -32,40 +32,43 @@ To get them, you need a parser.
|
|
|
32
32
|
|
|
33
33
|
## 2. Attach a parser with `--on-file`
|
|
34
34
|
|
|
35
|
-
Any program that reads
|
|
36
|
-
stdout is a parser. Here is a small one,
|
|
37
|
-
frontmatter:
|
|
35
|
+
Any program that reads the files named by its arguments and prints a **JSON
|
|
36
|
+
array of row objects** on stdout is a parser. Here is a small one,
|
|
37
|
+
`extract.py`, that reads each post's frontmatter:
|
|
38
38
|
|
|
39
39
|
```python
|
|
40
40
|
#!/usr/bin/env python3
|
|
41
41
|
import json, re, sys
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
)
|
|
49
|
-
|
|
43
|
+
rows = []
|
|
44
|
+
for path in sys.argv[1:]:
|
|
45
|
+
text = open(path, encoding="utf-8").read()
|
|
46
|
+
m = re.match(r"^---\n(.*?)\n---", text, re.DOTALL)
|
|
47
|
+
fields = dict(
|
|
48
|
+
(k.strip(), v.strip())
|
|
49
|
+
for k, _, v in (line.partition(":") for line in (m.group(1).splitlines() if m else []))
|
|
50
|
+
)
|
|
51
|
+
rows.append({"title": fields.get("title"), "author": fields.get("author")})
|
|
52
|
+
print(json.dumps(rows))
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
Point the path-table at it with `--on-file`:
|
|
53
56
|
|
|
54
57
|
```bash
|
|
55
58
|
dirsql query "SELECT title, author FROM './posts/*.md' ORDER BY title" \
|
|
56
|
-
--on-file 'python3 extract.py
|
|
59
|
+
--on-file 'python3 extract.py'
|
|
57
60
|
```
|
|
58
61
|
|
|
59
62
|
```json
|
|
60
63
|
[{"author":"Ada Lovelace","title":"Hello World"},{"author":"Alan Turing","title":"On Recursion"}]
|
|
61
64
|
```
|
|
62
65
|
|
|
63
|
-
Now the parser's output *is* the table. `--on-file` runs the command once
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
splitting, timeout, and
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
Now the parser's output *is* the table. `--on-file` runs the command once,
|
|
67
|
+
with every matched file's absolute path appended as an argument, under the
|
|
68
|
+
shared [`on-file` hook contract](../reference/hooks.md#on-file) (argv
|
|
69
|
+
splitting, timeout, and failure semantics all come from there). The stat
|
|
70
|
+
columns are no longer reachable — a parser that wants the path emits it, since
|
|
71
|
+
it already has the path. See
|
|
69
72
|
[Parsing rows with `--on-file`](../reference/path-tables.md#parsing-rows-with-on-file)
|
|
70
73
|
for the full behavior.
|
|
71
74
|
|
|
@@ -87,7 +90,7 @@ command in verbatim:
|
|
|
87
90
|
name = "posts"
|
|
88
91
|
ddl = "CREATE TABLE posts (title TEXT, author TEXT)"
|
|
89
92
|
glob = "posts/*.md"
|
|
90
|
-
on-file = "python3 extract.py
|
|
93
|
+
on-file = "python3 extract.py"
|
|
91
94
|
```
|
|
92
95
|
|
|
93
96
|
The `on-file` value is byte-for-byte the string you passed to `--on-file`. The
|
|
@@ -109,7 +112,7 @@ indexed on build, kept fresh by the watcher, survives restarts with
|
|
|
109
112
|
[many tables](./define-tables.md) — each with its own `on-file` — where the flag
|
|
110
113
|
gives every path-table one parser. In both spellings the table's columns are
|
|
111
114
|
exactly what the parser emits: `dirsql` merges no filesystem facts back on. A
|
|
112
|
-
row that needs the file's `path` emits it (the parser has
|
|
115
|
+
row that needs the file's `path` emits it (the parser has the path).
|
|
113
116
|
|
|
114
117
|
## Going further
|
|
115
118
|
|
|
@@ -17,7 +17,7 @@ prints each file's basename:
|
|
|
17
17
|
name = "files"
|
|
18
18
|
ddl = "CREATE TABLE files (basename TEXT)"
|
|
19
19
|
glob = "**/*"
|
|
20
|
-
on-file = '''sh -c 'printf "[{\"basename\":\"%s\"}
|
|
20
|
+
on-file = '''sh -c 'printf "["; sep=""; for p; do printf "%s{\"basename\":\"%s\"}" "$sep" "${p##*/}"; sep=","; done; printf "]"' sh'''
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## 1. Open the stream
|
|
@@ -31,7 +31,7 @@ external-content index beside the row table and let the two triggers feed it:
|
|
|
31
31
|
[[table]]
|
|
32
32
|
name = "notes"
|
|
33
33
|
glob = "notes/**/*.md"
|
|
34
|
-
on-file = "python3 extract.py
|
|
34
|
+
on-file = "python3 extract.py"
|
|
35
35
|
ddl = '''
|
|
36
36
|
CREATE TABLE notes (slug TEXT, title TEXT, body TEXT);
|
|
37
37
|
|
|
@@ -150,7 +150,7 @@ inserted vector for the "embedding" column. Expected 8 dimensions but received 4
|
|
|
150
150
|
[[table]]
|
|
151
151
|
name = "notes"
|
|
152
152
|
glob = "notes/**/*.md"
|
|
153
|
-
on-file = "python3 extract.py
|
|
153
|
+
on-file = "python3 extract.py"
|
|
154
154
|
ddl = '''
|
|
155
155
|
CREATE TABLE notes (slug TEXT, title TEXT, body TEXT);
|
|
156
156
|
|
|
@@ -25,7 +25,7 @@ ignore = ["notes/drafts/**", "**/*.tmp"]
|
|
|
25
25
|
name = "notes"
|
|
26
26
|
ddl = "CREATE TABLE notes (basename TEXT)"
|
|
27
27
|
glob = "notes/**/*"
|
|
28
|
-
on-file = '''sh -c 'printf "[{\"basename\":\"%s\"}
|
|
28
|
+
on-file = '''sh -c 'printf "["; sep=""; for p; do printf "%s{\"basename\":\"%s\"}" "$sep" "${p##*/}"; sep=","; done; printf "]"' sh'''
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
Patterns match against root-relative paths, the same way table globs do. An
|
|
@@ -60,11 +60,12 @@ its `embed()` SQL function),
|
|
|
60
60
|
and [`ignore`](../reference/config.md#dirsql-keys).
|
|
61
61
|
|
|
62
62
|
There are **no plugin-specific keys and no plugin-specific restrictions**. The
|
|
63
|
-
config schema is content-only: the index
|
|
64
|
-
[runner-owned
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
config schema is content-only: the index root and persistence are
|
|
64
|
+
[runner-owned](../reference/config.md#dirsql-keys) — the root is the directory
|
|
65
|
+
`dirsql` is run from (or an SDK's explicit `root`), persistence is the
|
|
66
|
+
`--persist [PATH]` flag — decided by whoever runs `dirsql`, never by a config
|
|
67
|
+
file, so a plugin has nothing to say about them. Whatever you can put in your
|
|
68
|
+
own `.dirsql.toml`, a plugin can put in its fragment, and vice-versa.
|
|
68
69
|
|
|
69
70
|
## Hook commands
|
|
70
71
|
|
|
@@ -72,11 +73,11 @@ Both hook command styles from the [hook contract](../reference/hooks.md) work
|
|
|
72
73
|
in a plugin fragment:
|
|
73
74
|
|
|
74
75
|
- **Console scripts** — a `bin`-style entry point your package installs on
|
|
75
|
-
`PATH` (`embed-file {
|
|
76
|
+
`PATH` (`embed-file {root}`). Recommended for published plugins: the command
|
|
76
77
|
is bound to your package's interpreter and dependencies, and it is
|
|
77
78
|
language-neutral (the fragment names a command, not a Python file).
|
|
78
79
|
- **Relative scripts** — a path resolved against the fragment's own directory
|
|
79
|
-
(`uv run python embed.py {
|
|
80
|
+
(`uv run python embed.py {root}`). Convenient while developing the plugin
|
|
80
81
|
in-tree.
|
|
81
82
|
|
|
82
83
|
Two facts from the [execution contract](../reference/hooks.md#execution-contract)
|
|
@@ -84,12 +85,12 @@ matter most for a published plugin:
|
|
|
84
85
|
|
|
85
86
|
- **A hook runs in its declaring config's directory.** For a plugin that is
|
|
86
87
|
the installed fragment's directory — inside **site-packages**. That is a
|
|
87
|
-
read-only, shared location: **run from it, never write to it.**
|
|
88
|
-
absolute
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
read-only, shared location: **run from it, never write to it.** Read the
|
|
89
|
+
matched files from the absolute paths the hook appends as arguments, and use
|
|
90
|
+
[`{root}`](../reference/hooks.md#on-file) to reach the user's project
|
|
91
|
+
directory. Write any cache to `{root}` or a real cache dir,
|
|
91
92
|
never next to the fragment.
|
|
92
|
-
-
|
|
93
|
+
- **The paths are absolute and `{root}` is the index root**, so a command is
|
|
93
94
|
self-sufficient from any working directory — it works whether the plugin
|
|
94
95
|
lives in the project or in site-packages.
|
|
95
96
|
|
|
@@ -111,28 +112,30 @@ entrypoint = "sqlite3_vec_init"
|
|
|
111
112
|
name = "notes"
|
|
112
113
|
ddl = "CREATE TABLE notes (path TEXT, text TEXT, embedding TEXT)"
|
|
113
114
|
glob = "notes/*.md"
|
|
114
|
-
on-file = "uv run --with model2vec python embed.py {
|
|
115
|
+
on-file = "uv run --with model2vec python embed.py {root}"
|
|
115
116
|
```
|
|
116
117
|
|
|
117
|
-
`embed.py` turns
|
|
118
|
-
dirsql injects no columns, so the script emits the path itself,
|
|
119
|
-
`{
|
|
118
|
+
`embed.py` turns each file into one row carrying its path, text, and
|
|
119
|
+
embedding. dirsql injects no columns, so the script emits the path itself,
|
|
120
|
+
from the `{root}` the hook passes in and the paths it appends:
|
|
120
121
|
|
|
121
122
|
```python
|
|
122
|
-
"""Embed
|
|
123
|
+
"""Embed each file's text; print one dirsql row array on stdout."""
|
|
123
124
|
import json
|
|
124
125
|
import os
|
|
125
126
|
import sys
|
|
126
127
|
|
|
127
128
|
from model2vec import StaticModel
|
|
128
129
|
|
|
129
|
-
|
|
130
|
-
|
|
130
|
+
root, paths = sys.argv[1], sys.argv[2:]
|
|
131
|
+
texts = [open(path, encoding="utf-8").read() for path in paths]
|
|
131
132
|
model = StaticModel.from_pretrained("minishlab/potion-base-8M")
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
rows = [
|
|
134
|
+
{"path": os.path.relpath(path, root), "text": text,
|
|
135
|
+
"embedding": json.dumps([round(float(x), 6) for x in vector])}
|
|
136
|
+
for path, text, vector in zip(paths, texts, model.encode(texts))
|
|
137
|
+
]
|
|
138
|
+
print(json.dumps(rows))
|
|
136
139
|
```
|
|
137
140
|
|
|
138
141
|
The relative `embed.py` above resolves against the fragment directory, which
|
|
@@ -93,9 +93,10 @@ scope.
|
|
|
93
93
|
### Vector cache
|
|
94
94
|
|
|
95
95
|
Computed vectors are cached at `~/.cache/dirsql/embeddings/` (respecting
|
|
96
|
-
`XDG_CACHE_HOME`)
|
|
97
|
-
|
|
98
|
-
vectors — and re-running a query over
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
`XDG_CACHE_HOME`): one SQLite database per model identifier, each row keyed
|
|
97
|
+
on the SHA-256 of the value bytes. Changing the value or the model recomputes
|
|
98
|
+
— switching models never serves stale vectors — and re-running a query over
|
|
99
|
+
unchanged files is cache hits all the way, a whole batch answered by one
|
|
100
|
+
query. There is no eviction: the directory is **safe to wipe at any time**;
|
|
101
|
+
the only cost is re-embedding. The cache never lives inside a queried tree —
|
|
102
|
+
the worker writes nothing into the directories you query.
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# CLI
|
|
2
2
|
|
|
3
|
-
Query is the default: `dirsql "<sql>"` runs one query and prints
|
|
3
|
+
Query is the default: `dirsql "<sql>"` runs one query and prints the rows —
|
|
4
|
+
a table at a terminal, a JSON array when piped (see
|
|
5
|
+
[Output format](#output-format)).
|
|
4
6
|
The `dirsql` binary has these modes:
|
|
5
7
|
|
|
6
8
|
| Invocation | Behavior |
|
|
7
9
|
|---|---|
|
|
8
|
-
| `dirsql "<sql>"` | Run one query over the directory and print the rows
|
|
10
|
+
| `dirsql "<sql>"` | Run one query over the directory and print the rows. The default; identical to `dirsql query "<sql>"`. |
|
|
9
11
|
| `dirsql query "<sql>"` | Explicit synonym for the default one-shot query. |
|
|
10
12
|
| `dirsql server` | Start a long-lived HTTP server exposing a SQL view of a directory. See [HTTP API](./http-api.md). |
|
|
11
13
|
| `dirsql init` | Generate a `.dirsql.toml`. |
|
|
@@ -53,7 +55,7 @@ pipeline, same flags, same output. See that section for config discovery,
|
|
|
53
55
|
|
|
54
56
|
```bash
|
|
55
57
|
dirsql
|
|
56
|
-
# dirsql
|
|
58
|
+
# dirsql <version> — this directory is a database.
|
|
57
59
|
#
|
|
58
60
|
# SELECT basename, size FROM './' ORDER BY size DESC LIMIT 5;
|
|
59
61
|
# SELECT path FROM './**/*.md' WHERE content LIKE '%TODO%';
|
|
@@ -331,9 +333,10 @@ is a hard error — `error: the subcommand 'query' cannot be used with
|
|
|
331
333
|
for the server they follow the subcommand: `dirsql server -c <cfg>`.)
|
|
332
334
|
:::
|
|
333
335
|
|
|
334
|
-
The subcommand builds the index, runs the SQL, prints the result rows
|
|
335
|
-
JSON array
|
|
336
|
-
|
|
336
|
+
The subcommand builds the index, runs the SQL, prints the result rows on
|
|
337
|
+
stdout — a table at a terminal, otherwise a JSON array byte-identical to the
|
|
338
|
+
[`POST /query`](./http-api.md) response body (see
|
|
339
|
+
[Output format](#output-format)) — and exits `0`.
|
|
337
340
|
|
|
338
341
|
`dirsql query` is a thin adapter over the **same query pipeline the server
|
|
339
342
|
uses**, so behavior is identical to `POST /query` by construction:
|
|
@@ -367,12 +370,12 @@ array of row objects) instead of the stat columns:
|
|
|
367
370
|
|
|
368
371
|
```sh
|
|
369
372
|
dirsql query "SELECT title, author FROM './posts/*.md'" \
|
|
370
|
-
--on-file 'extract.py
|
|
373
|
+
--on-file 'extract.py'
|
|
371
374
|
```
|
|
372
375
|
|
|
373
376
|
The command follows the [`on-file` hook contract](./hooks.md#on-file) — argv
|
|
374
|
-
splitting, `{
|
|
375
|
-
timeout. The parser's output is the whole schema; the stat columns are not
|
|
377
|
+
splitting, the `{root}` placeholder, every matched path as a trailing
|
|
378
|
+
argument, the failure semantics, and the timeout. The parser's output is the whole schema; the stat columns are not
|
|
376
379
|
reachable on a parsed path-table. `--on-file` may be given **at most once** (a
|
|
377
380
|
repeat is an error pointing at config files) and never touches config-declared
|
|
378
381
|
tables. It is a `query`-only flag — server mode rejects it as an unknown
|
|
@@ -413,7 +416,7 @@ The output does **not** auto-load. Once you've tweaked it, pass it explicitly
|
|
|
413
416
|
to run against it:
|
|
414
417
|
|
|
415
418
|
```bash
|
|
416
|
-
dirsql "SELECT * FROM
|
|
419
|
+
dirsql "SELECT * FROM records" -c ./.dirsql.toml
|
|
417
420
|
```
|
|
418
421
|
|
|
419
422
|
### Flags
|
|
@@ -12,8 +12,8 @@ A named [`[[table]]`](./config.md#table) — or an SDK
|
|
|
12
12
|
[`on-file` hook](./hooks.md#on-file) emits, narrowed to the columns the DDL
|
|
13
13
|
declares. dirsql adds nothing on top: no `path`, no `size`, no value derived
|
|
14
14
|
from the filename. A hook that wants any of those computes them itself. The
|
|
15
|
-
hook receives
|
|
16
|
-
|
|
15
|
+
hook receives every matched file's path as an argument (an SDK `on_file`
|
|
16
|
+
callback receives one path) and may stat or read the files however it likes.
|
|
17
17
|
|
|
18
18
|
The hook is **required**. A `[[table]]` with no `on-file` is a
|
|
19
19
|
[config-load error](./config.md#parse-errors): with nothing supplying columns,
|
|
@@ -58,12 +58,12 @@ ORDER BY mtime DESC;
|
|
|
58
58
|
[Attaching a parser](./path-tables.md#parsing-rows-with-on-file) to a
|
|
59
59
|
path-table with `--on-file` **replaces** these stat columns with the parser's
|
|
60
60
|
own output — the two modes stay cleanly separate, exactly as for a named
|
|
61
|
-
table. A parser that wants the path emits it; it has
|
|
61
|
+
table. A parser that wants the path emits it; it has the paths.
|
|
62
62
|
|
|
63
63
|
## Deriving columns from the path
|
|
64
64
|
|
|
65
65
|
To turn path segments (an author, a year, a thread id) into columns, a hook
|
|
66
|
-
splits
|
|
66
|
+
splits the path and emits the pieces — the same as any other column it
|
|
67
67
|
produces. dirsql does not do this for you: a `{name}` segment in a glob is
|
|
68
68
|
rewritten to `*` and matches a single path segment, but captures no value.
|
|
69
69
|
[Derive columns from file paths](../howto/columns-from-paths.md) walks a
|
|
@@ -221,12 +221,12 @@ what its required `on-file` command emits — dirsql injects nothing (see
|
|
|
221
221
|
| `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. |
|
|
222
222
|
| `ddl` | yes | A SQL batch, run verbatim — any number of statements. It must create a table called `name`; that table holds the file rows, and only the columns it declares are kept (keys the `on-file` command emits that are not declared are dropped). The rest of the batch is yours: indexes, virtual tables, triggers. See [Batch `ddl`](#batch-ddl). |
|
|
223
223
|
| `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). |
|
|
224
|
-
| `on-file` | **yes** | A command run once per matched file; its stdout (
|
|
224
|
+
| `on-file` | **yes** | A command run once per table, with every matched file's absolute path appended as a trailing argument; its stdout (one JSON array of row objects) is the table'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). |
|
|
225
225
|
| `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`. |
|
|
226
226
|
|
|
227
227
|
`on-file` is required because a table's rows come from nowhere else. dirsql
|
|
228
228
|
does not read file contents or merge filesystem facts on your behalf: the
|
|
229
|
-
command reads the
|
|
229
|
+
command reads the files (it receives their paths as arguments) and prints the rows, and those
|
|
230
230
|
rows — filtered to the DDL — are the table. For plain stat columns with no
|
|
231
231
|
command, query the path directly with a [path-table](./path-tables.md)
|
|
232
232
|
instead of declaring a table.
|
|
@@ -236,13 +236,13 @@ instead of declaring a table.
|
|
|
236
236
|
name = "comments"
|
|
237
237
|
ddl = "CREATE TABLE comments (path TEXT, author TEXT, body TEXT)"
|
|
238
238
|
glob = "_comments/*/*.jsonl"
|
|
239
|
-
on-file = "jq -c -s '.'
|
|
239
|
+
on-file = "jq -c -s '.'"
|
|
240
240
|
|
|
241
241
|
[[table]]
|
|
242
242
|
name = "papers"
|
|
243
243
|
ddl = "CREATE TABLE papers (paper_id TEXT, title TEXT)"
|
|
244
244
|
glob = "**/meta.json"
|
|
245
|
-
on-file = "uv run python extract_papers.py
|
|
245
|
+
on-file = "uv run python extract_papers.py"
|
|
246
246
|
strict = true
|
|
247
247
|
```
|
|
248
248
|
|
|
@@ -255,7 +255,7 @@ statement:
|
|
|
255
255
|
[[table]]
|
|
256
256
|
name = "messages"
|
|
257
257
|
glob = "sessions/*/messages/*.json"
|
|
258
|
-
on-file = "jq -c
|
|
258
|
+
on-file = "jq -c -s add"
|
|
259
259
|
ddl = '''
|
|
260
260
|
CREATE TABLE messages (session TEXT, idx INT, role TEXT, text TEXT);
|
|
261
261
|
CREATE INDEX messages_session ON messages(session);
|
|
@@ -419,11 +419,11 @@ timeout = "600s"
|
|
|
419
419
|
name = "comments"
|
|
420
420
|
ddl = "CREATE TABLE comments (author TEXT, body TEXT)"
|
|
421
421
|
glob = "_comments/*/*.jsonl"
|
|
422
|
-
on-file = "jq -c -s '.'
|
|
422
|
+
on-file = "jq -c -s '.'"
|
|
423
423
|
|
|
424
424
|
[[table]]
|
|
425
425
|
name = "documents"
|
|
426
426
|
ddl = "CREATE TABLE documents (title TEXT, summary TEXT)"
|
|
427
427
|
glob = "**/index.md"
|
|
428
|
-
on-file = "uv run python extract_doc.py
|
|
428
|
+
on-file = "uv run python extract_doc.py"
|
|
429
429
|
```
|