dirsql 0.4.63__tar.gz → 0.4.66__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.63 → dirsql-0.4.66}/Cargo.lock +2 -2
- {dirsql-0.4.63 → dirsql-0.4.66}/PKG-INFO +3 -3
- {dirsql-0.4.63/packages/python → dirsql-0.4.66}/README.md +2 -2
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/AGENTS.md +1 -1
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/getting-started.md +8 -7
- {dirsql-0.4.63/packages/python → dirsql-0.4.66}/docs/howto/define-tables.md +2 -2
- {dirsql-0.4.63/packages/rust → dirsql-0.4.66}/docs/howto/extract-from-contents.md +24 -14
- {dirsql-0.4.63/packages/rust → dirsql-0.4.66}/docs/howto/parse-files-into-columns.md +73 -6
- {dirsql-0.4.63/packages/rust → dirsql-0.4.66}/docs/howto/persist.md +7 -11
- {dirsql-0.4.63/packages/rust → dirsql-0.4.66}/docs/howto/query-without-config.md +2 -2
- {dirsql-0.4.63/packages/python → dirsql-0.4.66}/docs/howto/search-by-meaning.md +19 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/reference/cli.md +22 -21
- {dirsql-0.4.63/packages/rust → dirsql-0.4.66}/docs/reference/config.md +16 -6
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/reference/hooks.md +54 -17
- {dirsql-0.4.63/packages/python → dirsql-0.4.66}/docs/reference/path-tables.md +72 -33
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/reference/sdk.md +3 -2
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/Cargo.toml +1 -1
- {dirsql-0.4.63 → dirsql-0.4.66/packages/python}/README.md +2 -2
- dirsql-0.4.66/packages/python/changelog.d/2026-10-02-readme-docs-host.md +1 -0
- dirsql-0.4.66/packages/python/changelog.d/2026-10-03-one-glob-rule-for-config-globs.md +6 -0
- dirsql-0.4.66/packages/python/changelog.d/2026-10-03-path-table-directory-one-level.md +7 -0
- dirsql-0.4.66/packages/python/changelog.d/2026-10-05-path-table-symlinks.md +7 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/AGENTS.md +1 -1
- {dirsql-0.4.63/packages/rust → dirsql-0.4.66/packages/python}/docs/getting-started.md +8 -7
- {dirsql-0.4.63 → dirsql-0.4.66/packages/python}/docs/howto/define-tables.md +2 -2
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/howto/extract-from-contents.md +24 -14
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/howto/parse-files-into-columns.md +73 -6
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/howto/persist.md +7 -11
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/howto/query-without-config.md +2 -2
- {dirsql-0.4.63 → dirsql-0.4.66/packages/python}/docs/howto/search-by-meaning.md +19 -0
- {dirsql-0.4.63/packages/rust → dirsql-0.4.66/packages/python}/docs/reference/cli.md +22 -21
- {dirsql-0.4.63 → dirsql-0.4.66/packages/python}/docs/reference/config.md +16 -6
- {dirsql-0.4.63/packages/rust → dirsql-0.4.66/packages/python}/docs/reference/hooks.md +54 -17
- {dirsql-0.4.63/packages/rust → dirsql-0.4.66/packages/python}/docs/reference/path-tables.md +72 -33
- {dirsql-0.4.63/packages/rust → dirsql-0.4.66/packages/python}/docs/reference/sdk.md +3 -2
- dirsql-0.4.66/packages/python/e2e-attestations/claude-1199-glob-prefix.json +7 -0
- dirsql-0.4.66/packages/python/e2e-attestations/claude-1216-on-file-cleanup.json +7 -0
- dirsql-0.4.66/packages/python/e2e-attestations/claude-1223-config-glob-rule.json +7 -0
- dirsql-0.4.66/packages/python/e2e-attestations/claude-1223-dir-one-level.json +7 -0
- dirsql-0.4.66/packages/python/e2e-attestations/claude-1238-parallel-walk.json +7 -0
- dirsql-0.4.66/packages/python/e2e-attestations/claude-1241-content-prefetch.json +7 -0
- dirsql-0.4.66/packages/python/e2e-attestations/claude-1243-ingest-perf.json +7 -0
- dirsql-0.4.66/packages/python/e2e-attestations/claude-1256-symlinks.json +7 -0
- dirsql-0.4.66/packages/python/migrations.d/2026-10-02-readme-docs-host.md +26 -0
- dirsql-0.4.66/packages/python/migrations.d/2026-10-03-one-glob-rule-for-config-globs.md +67 -0
- dirsql-0.4.66/packages/python/migrations.d/2026-10-03-path-table-directory-one-level.md +42 -0
- dirsql-0.4.66/packages/python/migrations.d/2026-10-05-path-table-symlinks.md +36 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/migrations.d/README.md +5 -5
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/Cargo.toml +1 -1
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/README.md +2 -2
- {dirsql-0.4.63/packages/python → dirsql-0.4.66/packages/rust}/docs/getting-started.md +8 -7
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/howto/define-tables.md +2 -2
- {dirsql-0.4.63 → dirsql-0.4.66/packages/rust}/docs/howto/extract-from-contents.md +24 -14
- {dirsql-0.4.63 → dirsql-0.4.66/packages/rust}/docs/howto/parse-files-into-columns.md +73 -6
- {dirsql-0.4.63 → dirsql-0.4.66/packages/rust}/docs/howto/persist.md +7 -11
- {dirsql-0.4.63 → dirsql-0.4.66/packages/rust}/docs/howto/query-without-config.md +2 -2
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/howto/search-by-meaning.md +19 -0
- {dirsql-0.4.63/packages/python → dirsql-0.4.66/packages/rust}/docs/reference/cli.md +22 -21
- {dirsql-0.4.63/packages/python → dirsql-0.4.66/packages/rust}/docs/reference/config.md +16 -6
- {dirsql-0.4.63/packages/python → dirsql-0.4.66/packages/rust}/docs/reference/hooks.md +54 -17
- {dirsql-0.4.63 → dirsql-0.4.66/packages/rust}/docs/reference/path-tables.md +72 -33
- {dirsql-0.4.63/packages/python → dirsql-0.4.66/packages/rust}/docs/reference/sdk.md +3 -2
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/cli/run.rs +7 -56
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/command.rs +14 -14
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/config.rs +34 -37
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/db.rs +606 -163
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/default_config.toml +2 -2
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/lib.rs +87 -60
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/matcher.rs +124 -4
- dirsql-0.4.66/packages/rust/src/parsed_vtab.rs +442 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/path_table.rs +144 -87
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/persist.rs +35 -39
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/scanner.rs +321 -308
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/vtab.rs +247 -33
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/vtab_scaffold.rs +459 -86
- dirsql-0.4.63/packages/rust/src/parsed_cache.rs +0 -454
- dirsql-0.4.63/packages/rust/src/parsed_vtab.rs +0 -930
- {dirsql-0.4.63 → dirsql-0.4.66}/Cargo.toml +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/__init__.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/_async.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/cli/discover_plugins/__init__.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/cli/main.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/cli/resolve_config_extensions.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/plan_entry_path.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/py.typed +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/read_config.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/resolve_configs_extension_specs.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/resolve_extension.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/dirsql/resolve_package.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/explanation.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/howto/embed.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/howto/query-json.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/index.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/package.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/plugins.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/reference/columns.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/docs/reference/http-api.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/CHANGELOG.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/MIGRATIONS.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-08-20-curtaincall-dev-dependency.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-09-04-config-paths-from-argv-module.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-09-05-config-extension-loader-split.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-09-05-resolve-config-extensions-split.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-09-05-resolve-extension-split.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-09-09-launcher-config-path-scan.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-09-17-extension-resolution-via-core.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-09-18-export-scan-failure.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-09-18-flatten-row-event-in-core.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-09-18-programmatic-extension-plan.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/2026-09-24-query-rows-in-projection-order.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/changelog.d/README.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/conftest.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/explanation.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/howto/embed.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/howto/query-json.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/index.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/package.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/plugins.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/reference/columns.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/docs/reference/http-api.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/cc-keen-knuth-f11gyq.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1056-py-ofpf9.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1066-p1-resolve-extension.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1078-argv-config-paths-core.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1079-p2-resolve-config-extensions.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1080-share-vtab-scaffolding.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1081-indicatif-progress.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1096-watch-moved-dir.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1109-watch-moved-out.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1119-ext-plan.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1120-py-ext.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1122-ext-cleanup.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1130-codec-crates.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1131-flatten-row-event.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1139-sse-flatten.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1140-scan-failure-export.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1148-clippy-all-targets.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1164-sigint-fatal.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1170-projection-order.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1172-on-file-path.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1173-py-projection-order.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1184-win-rel-paths.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1185-win-abs-table-names.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1186-win-test-harness.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1196-join-index.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1201-single-walk.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1204-embed-batch.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1207-win-argv-quote.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1208-win-nonverbatim-paths.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1215-on-file-batch.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-1226-stale-docs.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-epic-953-slice2-reedline.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-epic-953-slice3-format.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-epic-953-stacked-prs-x59wm3.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-issue-986-red-test-e7sjrb.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-tackle-1034-cachesplit.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-tackle-1042-py12.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-tackle-956-xzen74.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6-worker-calls.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/e2e-attestations/claude-tackle-975-n8mc2h.json +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/migrations.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/migrations.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/migrations.d/2026-09-24-query-rows-in-projection-order.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/src/lib.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/testing-conventions.toml +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/tests/e2e/speed_of_light.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/tests/integration/binding/__init__.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/python/tests/integration/hermetic/__init__.py +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/CHANGELOG.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/MIGRATIONS.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/explanation.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/howto/embed.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/howto/query-json.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/index.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/plugins.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/reference/columns.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/docs/reference/http-api.md +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/cli/execute.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/cli/repl.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/cli/table.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/extension_resolution.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/functions.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/infer.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/launcher.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/on_file.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/progress.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/row_event_flat.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/sql_literal.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.4.63 → dirsql-0.4.66}/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.66"
|
|
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.66"
|
|
604
604
|
dependencies = [
|
|
605
605
|
"dirsql",
|
|
606
606
|
"pyo3",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dirsql
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.66
|
|
4
4
|
Requires-Dist: bin-shim>=0.1
|
|
5
5
|
Summary: Ephemeral SQL index over a local directory
|
|
6
6
|
Keywords: sql,filesystem,directory,sqlite,index
|
|
@@ -13,7 +13,7 @@ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
|
13
13
|
|
|
14
14
|
Ephemeral SQL index over a local directory. `dirsql` watches a filesystem, ingests structured files into an in-memory SQLite database, and exposes a SQL query interface -- the filesystem is always the source of truth.
|
|
15
15
|
|
|
16
|
-
[Documentation](https://
|
|
16
|
+
[Documentation](https://dirsql.dev/?lang=python)
|
|
17
17
|
|
|
18
18
|
Also available as [`dirsql` on crates.io](https://crates.io/crates/dirsql) and [`dirsql` on npm](https://www.npmjs.com/package/dirsql).
|
|
19
19
|
|
|
@@ -135,7 +135,7 @@ Each event has `.action` (`"insert"`, `"update"`, `"delete"`, or `"error"`), `.t
|
|
|
135
135
|
|
|
136
136
|
## CLI
|
|
137
137
|
|
|
138
|
-
`pip install dirsql` also installs a `dirsql` console script. `dirsql "<sql>"` (or `uvx dirsql "<sql>"`) runs one query and prints the rows as JSON — the default. `dirsql server` starts an HTTP server exposing the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. See the [CLI reference](https://
|
|
138
|
+
`pip install dirsql` also installs a `dirsql` console script. `dirsql "<sql>"` (or `uvx dirsql "<sql>"`) runs one query and prints the rows as JSON — the default. `dirsql server` starts an HTTP server exposing the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. See the [CLI reference](https://dirsql.dev/reference/cli).
|
|
139
139
|
|
|
140
140
|
## License
|
|
141
141
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Ephemeral SQL index over a local directory. `dirsql` watches a filesystem, ingests structured files into an in-memory SQLite database, and exposes a SQL query interface -- the filesystem is always the source of truth.
|
|
4
4
|
|
|
5
|
-
[Documentation](https://
|
|
5
|
+
[Documentation](https://dirsql.dev/?lang=python)
|
|
6
6
|
|
|
7
7
|
Also available as [`dirsql` on crates.io](https://crates.io/crates/dirsql) and [`dirsql` on npm](https://www.npmjs.com/package/dirsql).
|
|
8
8
|
|
|
@@ -124,7 +124,7 @@ Each event has `.action` (`"insert"`, `"update"`, `"delete"`, or `"error"`), `.t
|
|
|
124
124
|
|
|
125
125
|
## CLI
|
|
126
126
|
|
|
127
|
-
`pip install dirsql` also installs a `dirsql` console script. `dirsql "<sql>"` (or `uvx dirsql "<sql>"`) runs one query and prints the rows as JSON — the default. `dirsql server` starts an HTTP server exposing the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. See the [CLI reference](https://
|
|
127
|
+
`pip install dirsql` also installs a `dirsql` console script. `dirsql "<sql>"` (or `uvx dirsql "<sql>"`) runs one query and prints the rows as JSON — the default. `dirsql server` starts an HTTP server exposing the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. See the [CLI reference](https://dirsql.dev/reference/cli).
|
|
128
128
|
|
|
129
129
|
## License
|
|
130
130
|
|
|
@@ -57,7 +57,7 @@ migrated -- a page survives only if a slot wants its content):
|
|
|
57
57
|
`dirsql` in an application.
|
|
58
58
|
- **Reference** (`reference/`) -- CLI flags and defaults; the complete
|
|
59
59
|
`.dirsql.toml` schema; the command hook contract (placeholders, stdout
|
|
60
|
-
protocol,
|
|
60
|
+
protocol, failure semantics); the columns model (named tables get their
|
|
61
61
|
hook's output; path-tables get stat columns); the
|
|
62
62
|
HTTP API; the SDK page (`reference/sdk.md`, one page with
|
|
63
63
|
Python/TypeScript/Rust code-groups -- the sole SDK home).
|
|
@@ -68,11 +68,11 @@ this directory anyway — from inside `my-notes`, run one command:
|
|
|
68
68
|
::: code-group
|
|
69
69
|
|
|
70
70
|
```bash [npm]
|
|
71
|
-
npx dirsql "SELECT COUNT(*) AS files FROM '
|
|
71
|
+
npx dirsql "SELECT COUNT(*) AS files FROM './**'"
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
```bash [PyPI]
|
|
75
|
-
uvx dirsql "SELECT COUNT(*) AS files FROM '
|
|
75
|
+
uvx dirsql "SELECT COUNT(*) AS files FROM './**'"
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
:::
|
|
@@ -91,10 +91,11 @@ files
|
|
|
91
91
|
Three files, three rows. That one command scanned the directory, handed
|
|
92
92
|
SQLite one row per file, ran your SQL, and printed the answer.
|
|
93
93
|
|
|
94
|
-
There is no named table here — you never declared one. `'
|
|
94
|
+
There is no named table here — you never declared one. `'./**'` is a
|
|
95
95
|
[path-table](./reference/path-tables.md): a quoted path written where a table
|
|
96
|
-
name goes. `'
|
|
97
|
-
in
|
|
96
|
+
name goes. `'./**'` means every file under the directory you ran the command
|
|
97
|
+
in, at any depth; `'./'` alone would list only the files directly inside it,
|
|
98
|
+
like `ls`. The path *is* the query.
|
|
98
99
|
|
|
99
100
|
## 3. Select some columns
|
|
100
101
|
|
|
@@ -105,11 +106,11 @@ pretty-print. Ask for two columns instead of a count:
|
|
|
105
106
|
::: code-group
|
|
106
107
|
|
|
107
108
|
```bash [npm]
|
|
108
|
-
npx dirsql query "SELECT path, size FROM '
|
|
109
|
+
npx dirsql query "SELECT path, size FROM './**' ORDER BY path" | jq
|
|
109
110
|
```
|
|
110
111
|
|
|
111
112
|
```bash [PyPI]
|
|
112
|
-
uvx dirsql query "SELECT path, size FROM '
|
|
113
|
+
uvx dirsql query "SELECT path, size FROM './**' ORDER BY path" | jq
|
|
113
114
|
```
|
|
114
115
|
|
|
115
116
|
:::
|
|
@@ -116,8 +116,8 @@ templates, with the trigger mistakes that fail silently, are in
|
|
|
116
116
|
|
|
117
117
|
## Going further
|
|
118
118
|
|
|
119
|
-
- The parser mechanics — placeholders, stdout protocol,
|
|
120
|
-
|
|
119
|
+
- The parser mechanics — placeholders, stdout protocol, failure semantics —
|
|
120
|
+
are the [`on-file` hook contract](../reference/hooks.md#on-file);
|
|
121
121
|
[Extract rows from file contents](./extract-from-contents.md) is the fuller
|
|
122
122
|
recipe.
|
|
123
123
|
- Your directory layout encodes data (authors, dates, IDs)? Split the path in
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Paths and stat metadata only get you so far — when the columns you want live
|
|
4
4
|
*inside* the files (JSON fields, frontmatter, log lines), add an
|
|
5
|
-
[`on-file`](../reference/config.md#table) command: it runs once
|
|
6
|
-
file
|
|
5
|
+
[`on-file`](../reference/config.md#table) command: it runs once for the
|
|
6
|
+
table, with every matched file as an argument, and the JSON array it prints
|
|
7
|
+
becomes the table's rows.
|
|
7
8
|
|
|
8
9
|
## 1. Point a command at the files
|
|
9
10
|
|
|
@@ -13,8 +14,8 @@ Suppose each book is a JSON file:
|
|
|
13
14
|
{"title": "Middlemarch", "author": "George Eliot", "year": 1871}
|
|
14
15
|
```
|
|
15
16
|
|
|
16
|
-
Any program that reads
|
|
17
|
-
stdout works. With [`jq`](https://jqlang.org/):
|
|
17
|
+
Any program that reads the files named by its arguments and prints a **JSON
|
|
18
|
+
array of row objects** on stdout works. With [`jq`](https://jqlang.org/):
|
|
18
19
|
|
|
19
20
|
```toml
|
|
20
21
|
[[table]]
|
|
@@ -27,8 +28,8 @@ on-file = "jq -c -n '[inputs | {title, author, year}]'"
|
|
|
27
28
|
The command runs once for the table, with every matched file's absolute path
|
|
28
29
|
appended as an argument, and prints one array for all of them — the
|
|
29
30
|
[command hook contract](../reference/hooks.md#on-file), which also covers
|
|
30
|
-
the argv splitting, working directory, stdout protocol
|
|
31
|
-
|
|
31
|
+
the argv splitting, working directory, and stdout protocol shared by every
|
|
32
|
+
hook.
|
|
32
33
|
|
|
33
34
|
## 2. Query the extracted columns
|
|
34
35
|
|
|
@@ -68,13 +69,21 @@ dirsql query "SELECT event, user FROM events" -c ./.dirsql.toml
|
|
|
68
69
|
[{"event":"login","user":"alice"},{"event":"logout","user":"alice"},{"event":"login","user":"bob"}]
|
|
69
70
|
```
|
|
70
71
|
|
|
71
|
-
## When
|
|
72
|
+
## When the command fails
|
|
72
73
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
The command runs once for the whole table, so its failure is the table's: a
|
|
75
|
+
non-zero exit, no output, or output that is not a JSON array of objects fails
|
|
76
|
+
the build, and `dirsql query` exits `1` with the command's stderr tail on
|
|
77
|
+
stderr and nothing on stdout.
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
dirsql query: failed to load config: table `books`: on-file command failed: command `jq -c -n '[inputs | {title, author, year}]'` failed (exit 5): jq: error (at /home/me/library/books/broken.json:1): Cannot index string with string "title"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
A file the command cannot parse is the command's to handle — skip it, or
|
|
84
|
+
emit a row with `NULL`s — because dirsql has no per-file view of the rows.
|
|
85
|
+
Details in [failure semantics](../reference/hooks.md#failure-semantics); the
|
|
86
|
+
JSON to SQLite value mapping is under
|
|
78
87
|
[`on-file` row mapping](../reference/config.md#on-file-row-mapping).
|
|
79
88
|
|
|
80
89
|
## Going further
|
|
@@ -82,8 +91,9 @@ SQLite value mapping is under
|
|
|
82
91
|
- Just want to read a field or two out of some JSON files? SQLite's JSON
|
|
83
92
|
operators work directly on a path-table's `content` column, with no config
|
|
84
93
|
and no command — [Query JSON file contents](./query-json.md).
|
|
85
|
-
- The command re-runs on every startup and
|
|
86
|
-
|
|
94
|
+
- The command re-runs on every startup and, over all of the table's files, on
|
|
95
|
+
every change under the table's glob. If it is expensive,
|
|
96
|
+
[keep the index across restarts](./persist.md).
|
|
87
97
|
- Embedding `dirsql` in a program instead? The SDK's `on_file` callback
|
|
88
98
|
fills the same role in-process — see
|
|
89
99
|
[Embed `dirsql` in your application](./embed.md).
|
|
@@ -66,12 +66,17 @@ dirsql query "SELECT title, author FROM './posts/*.md' ORDER BY title" \
|
|
|
66
66
|
Now the parser's output *is* the table. `--on-file` runs the command once,
|
|
67
67
|
with every matched file's absolute path appended as an argument, under the
|
|
68
68
|
shared [`on-file` hook contract](../reference/hooks.md#on-file) (argv
|
|
69
|
-
splitting
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
splitting and failure semantics come from there). It runs in the directory
|
|
70
|
+
you ran `dirsql` from, which is why `python3 extract.py` finds the script. The
|
|
71
|
+
stat columns are no longer reachable — a parser that wants the path emits it,
|
|
72
|
+
since it already has the path. See
|
|
72
73
|
[Parsing rows with `--on-file`](../reference/path-tables.md#parsing-rows-with-on-file)
|
|
73
74
|
for the full behavior.
|
|
74
75
|
|
|
76
|
+
One run, one process: on a thousand files the parser starts once, not a
|
|
77
|
+
thousand times, so a Python or Node parser costs its startup once per query.
|
|
78
|
+
That is the shape to write — loop over `sys.argv[1:]`, collect, print once.
|
|
79
|
+
|
|
75
80
|
`--on-file` applies to every path-table in the query and may be given at most
|
|
76
81
|
once. It is a `query`-only flag: there is no config file involved yet, so it is
|
|
77
82
|
the fastest way to see whether a parser produces the rows you expect.
|
|
@@ -114,12 +119,74 @@ gives every path-table one parser. In both spellings the table's columns are
|
|
|
114
119
|
exactly what the parser emits: `dirsql` merges no filesystem facts back on. A
|
|
115
120
|
row that needs the file's `path` emits it (the parser has the path).
|
|
116
121
|
|
|
122
|
+
## The two shapes
|
|
123
|
+
|
|
124
|
+
Every parser is one of two shapes. The array length is the row count either
|
|
125
|
+
way; what differs is how many files feed it.
|
|
126
|
+
|
|
127
|
+
**One file, many rows.** A lab notebook is a single Markdown file of dated
|
|
128
|
+
`## YYYY-MM-DD` sections, and the question is about the sections. Name the one
|
|
129
|
+
file as the path-table; the parser receives one path and prints one row per
|
|
130
|
+
section. `notebook.py`:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
import json, re, sys
|
|
134
|
+
|
|
135
|
+
rows = []
|
|
136
|
+
for path in sys.argv[1:]:
|
|
137
|
+
text = open(path, encoding="utf-8").read()
|
|
138
|
+
for date, body in re.findall(r"^## (\d{4}-\d\d-\d\d)\n(.*?)(?=^## |\Z)", text, re.S | re.M):
|
|
139
|
+
rows.append({"date": date, "words": len(body.split())})
|
|
140
|
+
print(json.dumps(rows))
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
dirsql query "SELECT date, words FROM './notebook.md' ORDER BY date DESC LIMIT 2" \
|
|
145
|
+
--on-file 'python3 notebook.py'
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
[{"date":"2026-09-23","words":10},{"date":"2026-09-22","words":3}]
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Many files, many rows.** A tree of JSONL session logs under
|
|
153
|
+
`projects/<name>/`, and the question is how many messages each project has per
|
|
154
|
+
role. The parser receives every log's path and prints one row per message,
|
|
155
|
+
carrying the project name it derived from the path, because dirsql will not
|
|
156
|
+
attach it. `messages.py`:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
import json, os, sys
|
|
160
|
+
|
|
161
|
+
rows = []
|
|
162
|
+
for path in sys.argv[1:]:
|
|
163
|
+
project = os.path.relpath(path, "projects").split(os.sep)[0]
|
|
164
|
+
for line in open(path, encoding="utf-8"):
|
|
165
|
+
entry = json.loads(line)
|
|
166
|
+
if entry["type"] in ("user", "assistant"):
|
|
167
|
+
rows.append({"project": project, "role": entry["type"], "text": entry["message"]["content"]})
|
|
168
|
+
print(json.dumps(rows))
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
dirsql query "SELECT project, role, count(*) AS n FROM './projects/**/*.jsonl' GROUP BY project, role ORDER BY project, role" \
|
|
173
|
+
--on-file 'python3 messages.py'
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
[{"project":"alpha","role":"assistant","n":2},{"project":"alpha","role":"user","n":1},{"project":"beta","role":"user","n":2}]
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The same two scripts work unchanged as a `[[table]]`'s `on-file` key. The
|
|
181
|
+
loop is the same in both shapes, so a parser written for one file already
|
|
182
|
+
handles a glob.
|
|
183
|
+
|
|
117
184
|
## Going further
|
|
118
185
|
|
|
119
|
-
- The full stat-vs-parsed behavior, failure
|
|
186
|
+
- The full stat-vs-parsed behavior, failure semantics, and skip rules:
|
|
120
187
|
[Parsing rows with `--on-file`](../reference/path-tables.md#parsing-rows-with-on-file).
|
|
121
188
|
- Starting from a declared table instead of a path-table?
|
|
122
189
|
[Extract rows from file contents](./extract-from-contents.md) covers the
|
|
123
190
|
config-first path.
|
|
124
|
-
-
|
|
125
|
-
|
|
191
|
+
- A very large table may reach the parser in several invocations; see
|
|
192
|
+
[Argument-list limits](../reference/hooks.md#argument-list-limits).
|
|
@@ -4,8 +4,8 @@ By default the database is ephemeral: rebuilt from your files on every
|
|
|
4
4
|
startup and discarded on exit. The [`--persist [PATH]`](../reference/cli.md#dirsql-server)
|
|
5
5
|
flag keeps the SQLite index on disk instead, so a restart only re-parses
|
|
6
6
|
files that actually changed — the difference between seconds and
|
|
7
|
-
milliseconds on large trees, and between re-running and skipping expensive
|
|
8
|
-
[`on-file`](./extract-from-contents.md)
|
|
7
|
+
milliseconds on large trees, and between re-running and skipping an expensive
|
|
8
|
+
declared-table [`on-file`](./extract-from-contents.md) command.
|
|
9
9
|
|
|
10
10
|
Whether and where to cache is a machine-local operational choice — it
|
|
11
11
|
belongs to the command you run, not to the shared `.dirsql.toml`. That is
|
|
@@ -58,15 +58,11 @@ exactly what a non-persistent startup does.
|
|
|
58
58
|
A run that changes nothing writes nothing: the cache file is read and left
|
|
59
59
|
exactly as it was.
|
|
60
60
|
|
|
61
|
-
This covers
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
them parses afresh rather than serving rows the current command never
|
|
67
|
-
produced. A *stat* path-table caches nothing, because there is nothing to
|
|
68
|
-
save: its columns are the metadata the scan already collected, and `content`
|
|
69
|
-
is read live by design.
|
|
61
|
+
This covers declared tables, which keep their indexed rows. A
|
|
62
|
+
[path-table](../reference/path-tables.md) is not cached: a *stat* path-table
|
|
63
|
+
has nothing to save, since its columns are the metadata the scan already
|
|
64
|
+
collected and `content` is read live by design, and a path-table parsed with
|
|
65
|
+
`--on-file` runs its parser on every start.
|
|
70
66
|
|
|
71
67
|
Persistence is a startup-time optimization, not a change in meaning: the
|
|
72
68
|
database remains a derived view of your files, and queries return the same
|
|
@@ -67,5 +67,5 @@ why indexes belong to only one of them, are in
|
|
|
67
67
|
- Paths outside the root resolve too — `'/var/log/*.log'`, `'../notes'`,
|
|
68
68
|
`'~/notes/*.md'` — reporting absolute paths
|
|
69
69
|
([path-tables reference](../reference/path-tables.md#paths-outside-the-index-root)).
|
|
70
|
-
- `node_modules/` and `.git/` are skipped by default so a bare `'
|
|
71
|
-
drown in machinery ([skip rules](../reference/path-tables.md#skip-rules)).
|
|
70
|
+
- `node_modules/` and `.git/` are skipped by default so a bare `'./**'` does
|
|
71
|
+
not drown in machinery ([skip rules](../reference/path-tables.md#skip-rules)).
|
|
@@ -120,6 +120,25 @@ ORDER BY vec_distance_cosine(emb, embed('local private models'))
|
|
|
120
120
|
LIMIT 10
|
|
121
121
|
```
|
|
122
122
|
|
|
123
|
+
A field that needs real parsing — frontmatter, a log line — comes out with a
|
|
124
|
+
[parser attached](../reference/path-tables.md#parsing-rows-with-on-file) by
|
|
125
|
+
`--on-file`; the plugin's `embed()` then works on the parser's columns, since a
|
|
126
|
+
discovered plugin and an inline parser compose. With `title.py` printing one
|
|
127
|
+
`{"path", "title"}` row per note from its frontmatter:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
uvx --with dirsql-plugin-embeddings dirsql "
|
|
131
|
+
SELECT title,
|
|
132
|
+
vec_distance_cosine(embed(title), embed('how do I cook pasta?')) AS distance
|
|
133
|
+
FROM './notes/*.md'
|
|
134
|
+
ORDER BY distance
|
|
135
|
+
LIMIT 3" --on-file 'python3 title.py'
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
[{"title":"Boiling spaghetti","distance":0.491},{"title":"Planting tomatoes","distance":0.836},{"title":"Feature branches","distance":1.064}]
|
|
140
|
+
```
|
|
141
|
+
|
|
123
142
|
The same projection works as an `on-file` hook feeding the indexed shape:
|
|
124
143
|
parse the field in the hook, store it as a column, and the trigger embeds it
|
|
125
144
|
once instead of on every query.
|
|
@@ -88,7 +88,7 @@ front.
|
|
|
88
88
|
### Output format
|
|
89
89
|
|
|
90
90
|
Rows go where they are useful: a **table** when stdout is a terminal, the
|
|
91
|
-
**JSON array** when it is piped or redirected. `SELECT * FROM '
|
|
91
|
+
**JSON array** when it is piped or redirected. `SELECT * FROM './**'` in a
|
|
92
92
|
5000-file tree should not put a 5000-element JSON array in front of a person,
|
|
93
93
|
and `dirsql "…" | jq` should not have to parse a table.
|
|
94
94
|
|
|
@@ -223,11 +223,7 @@ every statement, so it is reported once and exits `1` before the first prompt.
|
|
|
223
223
|
| Code | Meaning |
|
|
224
224
|
|---|---|
|
|
225
225
|
| `0` | Clean EOF (Ctrl-D, `exit`, `quit`, or the end of a piped script) — **including when statements failed**. Matches interactive `sqlite3`; use [`dirsql query`](#dirsql-query) when a script needs a statement's exit status. |
|
|
226
|
-
| `1` | The index could not be built (a bad `-c`, an unresolvable `--on-file`), or stdin could not be read. Nothing was executed. |
|
|
227
|
-
|
|
228
|
-
`23` (partial scan) is not produced here: skipped files are reported before the
|
|
229
|
-
first prompt, and a session's exit code describes the session rather than one
|
|
230
|
-
scan.
|
|
226
|
+
| `1` | The index could not be built (a bad `-c`, an unresolvable `--on-file`, a failed `on-file` command), or stdin could not be read. Nothing was executed. |
|
|
231
227
|
|
|
232
228
|
## `dirsql server`
|
|
233
229
|
|
|
@@ -283,7 +279,7 @@ curl -s localhost:7117/query -H 'content-type: application/json' \
|
|
|
283
279
|
```
|
|
284
280
|
|
|
285
281
|
Earlier versions served an implicit table named `files` here. It is gone; a
|
|
286
|
-
`SELECT ... FROM files` with no config now fails and points at `FROM '
|
|
282
|
+
`SELECT ... FROM files` with no config now fails and points at `FROM './**'`.
|
|
287
283
|
|
|
288
284
|
Passing a config with `-c` fully overrules this default. A `-c` naming a file
|
|
289
285
|
that does not exist is an error (not a fallback to the default); a config that
|
|
@@ -365,8 +361,9 @@ uses**, so behavior is identical to `POST /query` by construction:
|
|
|
365
361
|
#### `--on-file <command>`
|
|
366
362
|
|
|
367
363
|
Attach a parser to every [path-table](./path-tables.md#parsing-rows-with-on-file)
|
|
368
|
-
in the query
|
|
369
|
-
array of row objects
|
|
364
|
+
in the query: the command runs once per path-table, with every matched file's
|
|
365
|
+
path as a trailing argument, and the JSON array of row objects it prints
|
|
366
|
+
replaces the stat columns:
|
|
370
367
|
|
|
371
368
|
```sh
|
|
372
369
|
dirsql query "SELECT title, author FROM './posts/*.md'" \
|
|
@@ -375,17 +372,21 @@ dirsql query "SELECT title, author FROM './posts/*.md'" \
|
|
|
375
372
|
|
|
376
373
|
The command follows the [`on-file` hook contract](./hooks.md#on-file) — argv
|
|
377
374
|
splitting, the `{root}` placeholder, every matched path as a trailing
|
|
378
|
-
argument, the failure semantics
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
375
|
+
argument, and the failure semantics — with one difference from the config
|
|
376
|
+
key: there is no config file, so the command runs in the index root (the
|
|
377
|
+
directory `dirsql query` was run in). The parser's output is the whole
|
|
378
|
+
schema; the stat columns are not reachable on a parsed path-table.
|
|
379
|
+
`--on-file` may be given **at most once** (a repeat is an error pointing at
|
|
380
|
+
config files) and never touches config-declared tables. It is a `query`-only flag — server mode rejects it as an unknown
|
|
382
381
|
argument. The command string is copy-paste identical to a `[[table]]`
|
|
383
382
|
`on-file` key, so an inline parser graduates to a config file unchanged — see
|
|
384
383
|
[Parse your files into columns](../howto/parse-files-into-columns.md).
|
|
385
384
|
|
|
386
385
|
Errors print the same diagnostic the HTTP `{"error": …}` body carries —
|
|
387
|
-
config failures, SQL errors, rejected reads, hook failures
|
|
388
|
-
|
|
386
|
+
config failures, SQL errors, rejected reads, hook failures — to stderr, with
|
|
387
|
+
exit code `1`. A failed `on-file` command is a hook failure: nothing is
|
|
388
|
+
printed on stdout, and the diagnostic carries the command's exit status and
|
|
389
|
+
the tail of its stderr.
|
|
389
390
|
|
|
390
391
|
#### `--format {auto,table,json}`
|
|
391
392
|
|
|
@@ -398,13 +399,13 @@ takes, with the same `auto` default. A one-shot query is usually piped, so
|
|
|
398
399
|
| Code | Meaning |
|
|
399
400
|
|---|---|
|
|
400
401
|
| `0` | Query succeeded; rows printed on stdout. |
|
|
401
|
-
| `1` | Any failure: config, SQL, rejected read,
|
|
402
|
+
| `1` | Any failure: config, SQL, rejected read, or a failed `on-file` command. The diagnostic is on stderr. |
|
|
402
403
|
|
|
403
404
|
## `dirsql init`
|
|
404
405
|
|
|
405
406
|
Writes a starter `.dirsql.toml` as a scaffold to edit. It does **not**
|
|
406
|
-
duplicate the zero-config floor (`SELECT * FROM '
|
|
407
|
-
with no config); instead it shows the **escalation**: one named `[[table]]`
|
|
407
|
+
duplicate the zero-config floor (`SELECT * FROM './**'` already lists every
|
|
408
|
+
file with no config); instead it shows the **escalation**: one named `[[table]]`
|
|
408
409
|
with a glob, a schema, and a real `on-file` hook that pulls structured rows
|
|
409
410
|
out of your files.
|
|
410
411
|
|
|
@@ -467,9 +468,9 @@ fragment is a launcher error naming the package — never a silent skip.
|
|
|
467
468
|
## Progress reporting
|
|
468
469
|
|
|
469
470
|
Building the index over a large tree is not instant: the walk visits every
|
|
470
|
-
file, then each
|
|
471
|
-
table's `ddl` fires on insert. On a big corpus that is minutes.
|
|
472
|
-
the two phases on **stderr** while they run:
|
|
471
|
+
file, then each table runs its `on-file` command over all of its files, plus
|
|
472
|
+
whatever the table's `ddl` fires on insert. On a big corpus that is minutes.
|
|
473
|
+
dirsql reports the two phases on **stderr** while they run:
|
|
473
474
|
|
|
474
475
|
```
|
|
475
476
|
dirsql: scanning 128413 files
|
|
@@ -24,7 +24,7 @@ the config file's location. See [`--config`](./cli.md#flags).
|
|
|
24
24
|
|
|
25
25
|
| Key | Type | Default | Description |
|
|
26
26
|
|---|---|---|---|
|
|
27
|
-
| `ignore` | array of strings | `[]` | Glob patterns matched against root-relative paths. Matched files are skipped entirely — excluded from the initial scan and from watch events. |
|
|
27
|
+
| `ignore` | array of strings | `[]` | Glob patterns matched against root-relative paths, under the [one glob rule](#glob-rule): `*` matches one level, `**` any depth. Matched files are skipped entirely — excluded from the initial scan and from watch events. |
|
|
28
28
|
|
|
29
29
|
There is no timeout key. `on-file` hook runs are unbounded; to bound one, wrap
|
|
30
30
|
its command in `timeout(1)` (see [Command hooks](./hooks.md#bounding-a-hook)).
|
|
@@ -43,6 +43,16 @@ directory.
|
|
|
43
43
|
ignore = ["node_modules/**", ".git/**"]
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
+
### Glob rule
|
|
47
|
+
|
|
48
|
+
Every glob in dirsql — `ignore`, a `[[table]]`'s `glob`, and a
|
|
49
|
+
[path-table](./path-tables.md#writing-the-path) — reads as the shell does:
|
|
50
|
+
`*` and `?` match within one path segment and never cross `/`; `**` matches
|
|
51
|
+
any depth. So `ignore = ["*"]` hides only the files directly inside the root,
|
|
52
|
+
`ignore = ["build/*"]` hides `build/a.o` but not `build/sub/b.o`, and
|
|
53
|
+
`glob = "*.json"` selects only the top-level `.json` files; write
|
|
54
|
+
`**/*.json` to select them at every depth.
|
|
55
|
+
|
|
46
56
|
Persistence is not a config key. Keep the SQLite index on disk between runs
|
|
47
57
|
with the [`--persist [PATH]` CLI flag](./cli.md#dirsql-server) — a machine-local
|
|
48
58
|
operational choice that belongs to the runner, not to shareable config.
|
|
@@ -220,7 +230,7 @@ what its required `on-file` command emits — dirsql injects nothing (see
|
|
|
220
230
|
|---|---|---|
|
|
221
231
|
| `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
232
|
| `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
|
-
| `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). |
|
|
233
|
+
| `glob` | yes | Glob pattern matched against root-relative paths, under the [one glob rule](#glob-rule): `*` matches one level, `**` any depth. 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
234
|
| `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
235
|
| `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
236
|
|
|
@@ -320,9 +330,9 @@ integral number → `INTEGER`, any other number → `REAL`; a string → `TEXT`;
|
|
|
320
330
|
nested array or object → its JSON text as `TEXT`.
|
|
321
331
|
|
|
322
332
|
A row's columns are exactly the keys the command emits, narrowed to the DDL;
|
|
323
|
-
dirsql merges nothing else in. Output that is not a JSON array of objects
|
|
324
|
-
|
|
325
|
-
|
|
333
|
+
dirsql merges nothing else in. Output that is not a JSON array of objects fails
|
|
334
|
+
the table, and a failed table fails the build (see
|
|
335
|
+
[failure semantics](./hooks.md#failure-semantics)).
|
|
326
336
|
|
|
327
337
|
## Composing multiple configs
|
|
328
338
|
|
|
@@ -386,7 +396,7 @@ SDKs raise/reject) when:
|
|
|
386
396
|
- A `[[table]]` entry omits `on-file` (or it is empty/whitespace). The error
|
|
387
397
|
names the offending glob and points at the fix:
|
|
388
398
|
|
|
389
|
-
> `[[table]] '**/*.md' has no on-file hook, so every row would be all-NULL. Add an `on-file` hook that emits the columns, or, for stat columns with no code, query the path directly: `FROM '
|
|
399
|
+
> `[[table]] '**/*.md' has no on-file hook, so every row would be all-NULL. Add an `on-file` hook that emits the columns, or, for stat columns with no code, query the path directly: `FROM './**'``
|
|
390
400
|
|
|
391
401
|
- A `[[dirsql.extension]]` entry omits `path`, or `path` is empty.
|
|
392
402
|
- A `[[dirsql.function]]` entry omits `name`, `command`, or `args` (or
|
|
@@ -37,10 +37,13 @@ The available placeholders are listed under the
|
|
|
37
37
|
|
|
38
38
|
### Working directory and environment
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
the command resolve predictably regardless of where
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
A command named by a `[[table]]` runs in the **config file's directory**, so
|
|
41
|
+
relative paths in the command resolve predictably regardless of where
|
|
42
|
+
`dirsql` was launched. A command named by the `--on-file` flag has no config
|
|
43
|
+
file: it runs in the **index root**, the directory `dirsql query` was run in,
|
|
44
|
+
which is also the directory a `./` path-table is relative to. In both forms
|
|
45
|
+
`{root}` is the index root. The command inherits `dirsql`'s environment, so
|
|
46
|
+
tools like `uvx --with …` / `npx …` resolve their dependencies as usual.
|
|
44
47
|
|
|
45
48
|
### stdout protocol
|
|
46
49
|
|
|
@@ -69,8 +72,8 @@ on-file = "timeout 30 my-extractor"
|
|
|
69
72
|
```
|
|
70
73
|
|
|
71
74
|
When the wrapper kills an overrunning command, the run exits non-zero and
|
|
72
|
-
the ordinary [failure semantics](#failure-semantics) apply — the
|
|
73
|
-
|
|
75
|
+
the ordinary [failure semantics](#failure-semantics) apply — the table's
|
|
76
|
+
command failed, so the build fails.
|
|
74
77
|
|
|
75
78
|
::: warning Windows
|
|
76
79
|
Windows's built-in `timeout` command is a *sleep*, not a bound — it cannot
|
|
@@ -94,20 +97,39 @@ A hook run fails when the command:
|
|
|
94
97
|
- exits zero but prints no non-empty stdout line,
|
|
95
98
|
- or prints output that does not parse as a JSON array of row objects.
|
|
96
99
|
|
|
97
|
-
What a failure *means*:
|
|
98
|
-
|
|
99
|
-
The
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
`strict` counts as the same kind of failure.
|
|
100
|
+
What a failure *means*: the command ran once for the whole table, so its
|
|
101
|
+
failure is the table's, and a table that cannot be filled fails the build.
|
|
102
|
+
The error names the table and carries the command's exit status and stderr
|
|
103
|
+
tail; the CLI prints it and exits `1`. A row the table rejects under `strict`
|
|
104
|
+
counts as the same kind of failure.
|
|
103
105
|
|
|
104
106
|
## `on-file` contract
|
|
105
107
|
|
|
106
|
-
Runs once per file matched by the table's `glob
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
Runs **once per table**, with every file matched by the table's `glob`
|
|
109
|
+
appended to the command as a trailing argument, and prints **one JSON array
|
|
110
|
+
of row objects** for the whole table. That is the whole contract. The command
|
|
111
|
+
reads the files itself; see [`[[table]]`](./config.md#table) for the
|
|
109
112
|
row-mapping rules.
|
|
110
113
|
|
|
114
|
+
One process over all the files is the shape to write: a loop over the
|
|
115
|
+
arguments that collects rows and prints them once at the end. Parsing is the
|
|
116
|
+
command's cost, not dirsql's — dirsql spawns the command, waits, and reads
|
|
117
|
+
its stdout. A table over no matched files spawns nothing.
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
import json, sys
|
|
121
|
+
|
|
122
|
+
rows = []
|
|
123
|
+
for path in sys.argv[1:]:
|
|
124
|
+
rows.extend(parse(path))
|
|
125
|
+
print(json.dumps(rows))
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
There is no row-to-file attribution: dirsql does not know which file a row
|
|
129
|
+
came from, and a row that needs the path carries it as a column the command
|
|
130
|
+
emitted. In watch mode a change to any file under the table's glob re-runs
|
|
131
|
+
the command over all of the table's files and replaces the table's rows.
|
|
132
|
+
|
|
111
133
|
The same command is attachable two ways, over the same contract: the
|
|
112
134
|
`on-file` config key on a `[[table]]`, and the
|
|
113
135
|
[`--on-file <command>`](./cli.md#on-file-command) flag on `dirsql query`,
|
|
@@ -126,5 +148,20 @@ the path or stat metadata emits it (it has the paths).
|
|
|
126
148
|
The matched files' **absolute** paths are not placeholders: they are appended
|
|
127
149
|
to the command as trailing arguments, after everything written in the
|
|
128
150
|
command, so `on-file = "extract.py"` receives them as `sys.argv[1:]` — one run
|
|
129
|
-
per table, self-sufficient from any working directory. A
|
|
130
|
-
|
|
151
|
+
per table, self-sufficient from any working directory. A tool that needs a
|
|
152
|
+
path anywhere other than last gets a wrapper script. A command that spells
|
|
153
|
+
`{path}` is rejected at startup:
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
on-file command `python3 extract.py {path}` uses `{path}`, but an on-file command now runs once per table with every matched path appended as trailing arguments and prints one JSON array of row objects. Remove `{path}` and read the paths from the command's arguments.
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Argument-list limits
|
|
160
|
+
|
|
161
|
+
Every platform caps the bytes one process may receive as arguments. When a
|
|
162
|
+
table's paths outgrow that cap, dirsql splits them into the fewest
|
|
163
|
+
consecutive runs that fit, runs the command once per run, and concatenates
|
|
164
|
+
the arrays it prints, in order. The command cannot tell: each run is an
|
|
165
|
+
ordinary invocation with a subset of the paths. A command must therefore not
|
|
166
|
+
assume one invocation sees every path — a count, a cross-file join, or a
|
|
167
|
+
dedupe over `sys.argv[1:]` is per run, not per table. Do that work in SQL.
|