dirsql 0.4.125__tar.gz → 0.4.127__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.125 → dirsql-0.4.127}/Cargo.lock +2 -2
- {dirsql-0.4.125 → dirsql-0.4.127}/PKG-INFO +1 -1
- {dirsql-0.4.125/packages/rust → dirsql-0.4.127}/docs/reference/sdk.md +4 -5
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/Cargo.toml +1 -1
- {dirsql-0.4.125 → dirsql-0.4.127/packages/python}/docs/reference/sdk.md +4 -5
- dirsql-0.4.127/packages/python/e2e-attestations/bot-1562-hook-savepoint-1102.json +7 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/Cargo.toml +1 -1
- {dirsql-0.4.125/packages/python → dirsql-0.4.127/packages/rust}/docs/reference/sdk.md +4 -5
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/command.rs +71 -21
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/foreign_key.rs +61 -10
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/lib.rs +152 -51
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/on_file.rs +59 -21
- {dirsql-0.4.125 → dirsql-0.4.127}/Cargo.toml +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/README.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/__init__.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/_async.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/cli/discover_plugins/__init__.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/cli/main.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/cli/resolve_config_extensions.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/plan_entry_path.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/py.typed +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/read_config.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/resolve_configs_extension_specs.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/resolve_extension.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/dirsql/resolve_package.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/AGENTS.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/context/.gitattributes +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/context/recipes.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/context/troubleshooting.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/context/usage.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/explanation.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/getting-started.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/agent-skill.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/embed.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/persist.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/query-json.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/index.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/package.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/plugins.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/reference/cli.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/reference/columns.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/reference/config.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/reference/glob.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/reference/hooks.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/reference/http-api.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/speed.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/docs/speed.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/CHANGELOG.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/MIGRATIONS.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/README.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-20-curtaincall-dev-dependency.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-04-config-paths-from-argv-module.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-05-config-extension-loader-split.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-05-resolve-config-extensions-split.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-05-resolve-extension-split.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-09-launcher-config-path-scan.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-17-extension-resolution-via-core.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-18-export-scan-failure.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-18-flatten-row-event-in-core.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-18-programmatic-extension-plan.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-24-query-rows-in-projection-order.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-02-readme-docs-host.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-03-one-glob-rule-for-config-globs.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-03-path-table-directory-one-level.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-04-path-table-dotfiles-hidden.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-05-brace-groups-follow-bash.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-05-cli-context.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-05-gitignore-requires-repo.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-05-path-table-node-modules-named.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-05-path-table-symlinks.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-05-path-table-trailing-slash.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-05-unbalanced-brackets-literal.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-config-braces.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-config-directory.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-config-dotnames.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-config-gitignore.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-config-globs-anchor-at-the-config.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-config-links.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-one-glob-compiler.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-plugin-no-default-records.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-watch-broadcast.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-zero-match-config-table-warning.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-bracket-slash-literal.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-dotdot-and-double-slashes.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-dotdot-as-written.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-glob-walks-node-modules.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-literal-gitignore.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-on-file-ndjson.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-parallel-hooks.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-persist-cache-outside-root.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-posix-classes-unicode.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-spread-few-large-files.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-08-small-walks-stay-on-one-thread.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-08-watch-requires-named-table.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-11-02-watch-dirs-created-mid-registration.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/2026-11-02-watch-live-on-return.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/changelog.d/README.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/conftest.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/context/.gitattributes +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/context/recipes.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/context/troubleshooting.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/context/usage.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/explanation.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/getting-started.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/agent-skill.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/embed.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/persist.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/query-json.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/index.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/package.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/plugins.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/reference/cli.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/reference/columns.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/reference/config.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/reference/glob.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/reference/hooks.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/reference/http-api.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/speed.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/docs/speed.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1334-listing-exemptions.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1397-watch-broadcast.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1398-inotify-error.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1399-server-cors.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1401-watch-scope.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1406-watch-no-tables-1008.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1407-child-place-depth.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1414-stat-speed.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1415-server-speed.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1416-watch-speed-1008.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1418-node-modules.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1419-dotdot-slashes.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1420-bracket-slash.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1421-posix-unicode.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1422-literal-gitignore.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1426-walk-spawn-threshold-1008.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1428-ndjson-hooks.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1429-parallel-hooks.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1430-dotdot-as-written.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1431-persist-cache-dir.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1437-test-cache-isolation.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1440-fix-main-build.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1448-wildcard-ignored-prefix.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1451-named-dir-never-hidden.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1454-split-few-files.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1457-incremental-refresh-1008.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1459-rescan-on-overflow-1008.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1461-chunked-read-1016.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1461-row-footprint-1008.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1461-step3-1020.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1461-wide-read-1015.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1462-paired-speed-harness-1008.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1464-fastest-native-1008.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1469-ci-speed-sanity-1009.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1470-perf-suite-1009.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1470-speed-page-1011.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1474-vtab-speed-1014.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1475-rowpath-1016.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1477-onelevel-speed-1015.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1477-onelevel-speed-1016.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1478-perdir-walk-1020.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1480-matcher-speed-1015.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1481-gitrepo-speed-1015.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1483-fm-speed-1015.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1484-jsonl-speed-1015.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1487-frontend-query-1011.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1488-frontend-metadata-1011.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1489-frontend-browse-1013.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1503-bench-watch-1011.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1504-bench-names-1011.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1514-watch-rerun-inline-1015.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1524-path-eq-1016.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1526-main-red-1016.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1532-gitignore-fastest-bar-1016.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1534-fm-native-1016.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1534-fm-native-1102.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1538-onfile-order-1019.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1540-update-in-place-1019.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1541-defer-fk-1019.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1544-perfile-update-1020.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1552-watch-gap-1102.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1557-watch-rename-1102.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1562-watch-speed-1102.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-fix-main-place-depth-20261007.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-issue-1486-frontend-20261009.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-gap-childpath-1011.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-parse-overlap-1011.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-parse-paths-1009.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-parse-pragmas-1011.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-sql-valueref-1013.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-walk-components-1011.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-walk-rowpath-1011.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-walk-rows-1013.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-walk-sched-1009.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/cc-keen-knuth-f11gyq.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1056-py-ofpf9.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1066-p1-resolve-extension.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1078-argv-config-paths-core.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1079-p2-resolve-config-extensions.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1080-share-vtab-scaffolding.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1081-indicatif-progress.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1096-watch-moved-dir.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1109-watch-moved-out.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1119-ext-plan.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1120-py-ext.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1122-ext-cleanup.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1130-codec-crates.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1131-flatten-row-event.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1139-sse-flatten.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1140-scan-failure-export.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1148-clippy-all-targets.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1164-sigint-fatal.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1170-projection-order.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1172-on-file-path.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1173-py-projection-order.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1184-win-rel-paths.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1185-win-abs-table-names.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1186-win-test-harness.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1196-join-index.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1199-glob-prefix.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1201-single-walk.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1204-embed-batch.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1207-win-argv-quote.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1208-win-nonverbatim-paths.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1215-on-file-batch.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1216-on-file-cleanup.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1223-config-glob-rule.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1223-dir-one-level.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1225-plugin-no-default.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1226-stale-docs.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1232-anchor-plumbing.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1232-config-anchor.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1232-multi-watch.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1232-zero-match.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1238-parallel-walk.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1241-content-prefetch.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1243-ingest-perf.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1249-dotfiles.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1256-symlinks.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1257-trailing-slash.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1258-config-braces.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1258-config-directory.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1258-config-dotnames.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1258-config-gitignore.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1258-config-links.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1258-one-pattern.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1262-brace-literal.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1264-context.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1267-posix-classes.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1268-unbalanced-brackets.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1269-utf8-chars.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1271-node-modules-named.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1272-ancestor-gitignore.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1273-walk-prune.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1285-ingest-fast.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1286-nested-repo.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1305-glob-speed.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1308-glob-speed.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1310-glob-speed.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1311-glob-speed.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1312-glob-speed.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1318-lazy-stat.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1320-walk-speed.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1322-walk-readdir.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1325-parallel-walk.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1326-stream-rows.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1330-python-dirsql-patch.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1330-python-extensions-patch.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1330-scanner-effects.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1330-scanner-gitignore.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1330-vtab-prefetch-flag.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1330-vtab-read.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1351-dot-dirs.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-epic-953-slice2-reedline.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-epic-953-slice3-format.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-epic-953-stacked-prs-x59wm3.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-issue-986-red-test-e7sjrb.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-tackle-1034-cachesplit.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-tackle-1042-py12.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-tackle-956-xzen74.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6-worker-calls.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-tackle-975-n8mc2h.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-09-24-query-rows-in-projection-order.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-02-readme-docs-host.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-03-one-glob-rule-for-config-globs.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-03-path-table-directory-one-level.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-04-path-table-dotfiles-hidden.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-05-brace-groups-follow-bash.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-05-cli-context.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-05-gitignore-requires-repo.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-05-path-table-node-modules-named.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-05-path-table-symlinks.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-05-path-table-trailing-slash.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-05-unbalanced-brackets-literal.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-config-braces.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-config-directory.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-config-dotnames.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-config-gitignore.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-config-globs-anchor-at-the-config.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-config-links.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-one-glob-compiler.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-plugin-no-default-records.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-watch-broadcast.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-zero-match-config-table-warning.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-bracket-slash-literal.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-dotdot-and-double-slashes.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-dotdot-as-written.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-glob-walks-node-modules.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-literal-gitignore.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-on-file-ndjson.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-parallel-hooks.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-persist-cache-outside-root.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-posix-classes-unicode.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-spread-few-large-files.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-08-small-walks-stay-on-one-thread.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-08-watch-requires-named-table.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-11-02-watch-dirs-created-mid-registration.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/2026-11-02-watch-live-on-return.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/migrations.d/README.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/src/lib.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/testing-conventions.toml +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/tests/e2e/bench_report.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/tests/e2e/bench_suite.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/tests/e2e/speed_of_light.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/tests/integration/binding/__init__.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/python/tests/integration/hermetic/__init__.py +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/CHANGELOG.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/MIGRATIONS.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/README.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/context/.gitattributes +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/context/recipes.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/context/troubleshooting.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/context/usage.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/explanation.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/getting-started.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/agent-skill.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/embed.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/persist.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/query-json.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/index.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/plugins.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/reference/cli.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/reference/columns.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/reference/config.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/reference/glob.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/reference/hooks.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/reference/http-api.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/speed.json +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/docs/speed.md +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/brace.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/cli/context.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/cli/execute.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/cli/frontend.html +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/cli/frontend.js +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/cli/repl.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/cli/run.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/cli/table.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/config.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/db.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/default_config.toml +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/extension_resolution.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/functions.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/gitignore_frame.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/infer.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/launcher.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/listing.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/parsed_vtab.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/path_table.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/per_thread.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/posix_class.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/progress.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/row_event_flat.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/row_stream.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/sql_literal.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/tree_walk.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/vtab.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/vtab_scaffold.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.4.125 → dirsql-0.4.127}/pyproject.toml +0 -0
|
@@ -573,7 +573,7 @@ dependencies = [
|
|
|
573
573
|
|
|
574
574
|
[[package]]
|
|
575
575
|
name = "dirsql"
|
|
576
|
-
version = "0.4.
|
|
576
|
+
version = "0.4.127"
|
|
577
577
|
dependencies = [
|
|
578
578
|
"assert_cmd",
|
|
579
579
|
"axum",
|
|
@@ -625,7 +625,7 @@ dependencies = [
|
|
|
625
625
|
|
|
626
626
|
[[package]]
|
|
627
627
|
name = "dirsql-py-ext"
|
|
628
|
-
version = "0.4.
|
|
628
|
+
version = "0.4.127"
|
|
629
629
|
dependencies = [
|
|
630
630
|
"dirsql",
|
|
631
631
|
"pyo3",
|
|
@@ -300,11 +300,10 @@ Returns a stream of [`RowEvent`](#rowevent)s reflecting filesystem changes
|
|
|
300
300
|
under the root. The stream never terminates on its own; stop consuming it
|
|
301
301
|
to stop.
|
|
302
302
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
while the initial scan is still running may be missed.
|
|
307
|
-
starts on first iteration.
|
|
303
|
+
The watcher is live once both `watch()` and [`ready`](#ready) have returned,
|
|
304
|
+
in either order (a Rust `DirSQL` is ready when `build()` returns); a file
|
|
305
|
+
written after that point produces an event and reaches the index. A write
|
|
306
|
+
made while the initial scan is still running may be missed.
|
|
308
307
|
|
|
309
308
|
An instance with no named tables cannot be watched: path-tables emit no
|
|
310
309
|
watch events, so `watch()` (and the polling primitives) raise an error naming
|
|
@@ -4,7 +4,7 @@ name = "dirsql-py-ext"
|
|
|
4
4
|
# pypi/maturin handler can rewrite it via `write-version` before
|
|
5
5
|
# `maturin build`. `pyproject.toml` declares `dynamic = ["version"]`
|
|
6
6
|
# and maturin reads this field. Mirrors `packages/rust/Cargo.toml`.
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.127"
|
|
8
8
|
# abi3 note: the `abi3-py310` pyo3 feature (below) builds ONE stable-ABI
|
|
9
9
|
# `cp310-abi3` wheel per platform that loads on every CPython >= 3.10
|
|
10
10
|
# (matching `pyproject.toml`'s `requires-python = ">=3.10"`), instead of
|
|
@@ -300,11 +300,10 @@ Returns a stream of [`RowEvent`](#rowevent)s reflecting filesystem changes
|
|
|
300
300
|
under the root. The stream never terminates on its own; stop consuming it
|
|
301
301
|
to stop.
|
|
302
302
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
while the initial scan is still running may be missed.
|
|
307
|
-
starts on first iteration.
|
|
303
|
+
The watcher is live once both `watch()` and [`ready`](#ready) have returned,
|
|
304
|
+
in either order (a Rust `DirSQL` is ready when `build()` returns); a file
|
|
305
|
+
written after that point produces an event and reaches the index. A write
|
|
306
|
+
made while the initial scan is still running may be missed.
|
|
308
307
|
|
|
309
308
|
An instance with no named tables cannot be watched: path-tables emit no
|
|
310
309
|
watch events, so `watch()` (and the polling primitives) raise an error naming
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"command": "uv run python -m pytest tests/e2e/on_file_query_test.py tests/e2e/query_contract_test.py tests/e2e/declared_table_name_test.py tests/e2e/fanout_test.py tests/e2e/use_case_dossier_test.py tests/e2e/use_case_join_test.py tests/e2e/use_case_notebook_test.py tests/e2e/use_case_transcripts_test.py tests/e2e/watch_speed_test.py -q",
|
|
3
|
+
"ran_at": 1793671776,
|
|
4
|
+
"exit_code": 0,
|
|
5
|
+
"commit": "92277f18890c83a5a800db7c2dec4d6f0e4bb8fb",
|
|
6
|
+
"branch": "bot/1562-hook-savepoint-1102"
|
|
7
|
+
}
|
|
@@ -6,7 +6,7 @@ description = "Ephemeral SQL index over a local directory"
|
|
|
6
6
|
# version stays for the binding crates (publish = false). The literal
|
|
7
7
|
# intentionally lags the published version: putitoutthere rewrites it to
|
|
8
8
|
# the planned release version at build time and never commits it back.
|
|
9
|
-
version = "0.4.
|
|
9
|
+
version = "0.4.127"
|
|
10
10
|
edition.workspace = true
|
|
11
11
|
# Literal `license` (not `license.workspace = true`) because
|
|
12
12
|
# putitoutthere's preflight check reads `[package].license` directly
|
|
@@ -300,11 +300,10 @@ Returns a stream of [`RowEvent`](#rowevent)s reflecting filesystem changes
|
|
|
300
300
|
under the root. The stream never terminates on its own; stop consuming it
|
|
301
301
|
to stop.
|
|
302
302
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
while the initial scan is still running may be missed.
|
|
307
|
-
starts on first iteration.
|
|
303
|
+
The watcher is live once both `watch()` and [`ready`](#ready) have returned,
|
|
304
|
+
in either order (a Rust `DirSQL` is ready when `build()` returns); a file
|
|
305
|
+
written after that point produces an event and reaches the index. A write
|
|
306
|
+
made while the initial scan is still running may be missed.
|
|
308
307
|
|
|
309
308
|
An instance with no named tables cannot be watched: path-tables emit no
|
|
310
309
|
watch events, so `watch()` (and the polling primitives) raise an error naming
|
|
@@ -286,12 +286,14 @@ const READ_BYTES: usize = 262_144;
|
|
|
286
286
|
/// Run an already-built `argv` and hand its stdout to `on_block` as it
|
|
287
287
|
/// arrives, in blocks that each hold whole lines (the last block may lack its
|
|
288
288
|
/// trailing newline). The child runs with stdin closed. A non-zero exit is an
|
|
289
|
-
/// error after every block has been delivered.
|
|
289
|
+
/// error after every block has been delivered. `on_eof` runs once stdout has
|
|
290
|
+
/// closed, before the child's exit is known.
|
|
290
291
|
pub(crate) fn run_argv_blocks(
|
|
291
292
|
command: &str,
|
|
292
293
|
argv: &[String],
|
|
293
294
|
cwd: &Path,
|
|
294
295
|
on_block: &mut dyn FnMut(&str),
|
|
296
|
+
on_eof: &mut dyn FnMut(),
|
|
295
297
|
) -> Result<(), CommandError> {
|
|
296
298
|
let mut cmd = Command::new(&argv[0]);
|
|
297
299
|
push_args(&mut cmd, &argv[1..]);
|
|
@@ -310,10 +312,29 @@ pub(crate) fn run_argv_blocks(
|
|
|
310
312
|
buf
|
|
311
313
|
});
|
|
312
314
|
let mut stdout_pipe = child.stdout.take().expect("stdout piped");
|
|
315
|
+
let status =
|
|
316
|
+
drain_then_reap(&mut stdout_pipe, on_block, on_eof, || child.wait()).map_err(|source| {
|
|
317
|
+
CommandError::Io {
|
|
318
|
+
command: command.to_string(),
|
|
319
|
+
source,
|
|
320
|
+
}
|
|
321
|
+
})?;
|
|
322
|
+
let stderr = stderr_thread.join().unwrap_or_default();
|
|
323
|
+
check_exit(command, status, &stderr)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/// Hand `stdout` to `on_block` in blocks of whole lines until it closes, run
|
|
327
|
+
/// `on_eof`, then `reap` the child, so work on the output overlaps its exit.
|
|
328
|
+
fn drain_then_reap<T>(
|
|
329
|
+
stdout: &mut dyn Read,
|
|
330
|
+
on_block: &mut dyn FnMut(&str),
|
|
331
|
+
on_eof: &mut dyn FnMut(),
|
|
332
|
+
reap: impl FnOnce() -> T,
|
|
333
|
+
) -> T {
|
|
313
334
|
let mut pending: Vec<u8> = Vec::new();
|
|
314
335
|
let mut buf = vec![0u8; READ_BYTES];
|
|
315
336
|
loop {
|
|
316
|
-
let n = match
|
|
337
|
+
let n = match stdout.read(&mut buf) {
|
|
317
338
|
Ok(0) | Err(_) => break,
|
|
318
339
|
Ok(n) => n,
|
|
319
340
|
};
|
|
@@ -326,13 +347,8 @@ pub(crate) fn run_argv_blocks(
|
|
|
326
347
|
if !pending.is_empty() {
|
|
327
348
|
on_block(&String::from_utf8_lossy(&pending));
|
|
328
349
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
command: command.to_string(),
|
|
332
|
-
source,
|
|
333
|
-
})?;
|
|
334
|
-
let stderr = stderr_thread.join().unwrap_or_default();
|
|
335
|
-
check_exit(command, status, &stderr)
|
|
350
|
+
on_eof();
|
|
351
|
+
reap()
|
|
336
352
|
}
|
|
337
353
|
|
|
338
354
|
// One fn with cfg blocks rather than two cfg'd fns: cargo-mutants mutates
|
|
@@ -809,10 +825,16 @@ mod tests {
|
|
|
809
825
|
];
|
|
810
826
|
let mut seen = String::new();
|
|
811
827
|
let mut blocks = 0;
|
|
812
|
-
run_argv_blocks(
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
828
|
+
run_argv_blocks(
|
|
829
|
+
"t",
|
|
830
|
+
&argv,
|
|
831
|
+
&cwd(),
|
|
832
|
+
&mut |block| {
|
|
833
|
+
seen.push_str(block);
|
|
834
|
+
blocks += 1;
|
|
835
|
+
},
|
|
836
|
+
&mut || {},
|
|
837
|
+
)
|
|
816
838
|
.unwrap();
|
|
817
839
|
assert_eq!(seen, "a\nb\nc");
|
|
818
840
|
assert!(blocks >= 1);
|
|
@@ -827,11 +849,17 @@ mod tests {
|
|
|
827
849
|
];
|
|
828
850
|
let mut lines = 0;
|
|
829
851
|
let mut blocks = 0;
|
|
830
|
-
run_argv_blocks(
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
852
|
+
run_argv_blocks(
|
|
853
|
+
"t",
|
|
854
|
+
&argv,
|
|
855
|
+
&cwd(),
|
|
856
|
+
&mut |block| {
|
|
857
|
+
blocks += 1;
|
|
858
|
+
assert!(block.ends_with('\n'), "block cut mid-line");
|
|
859
|
+
lines += block.lines().count();
|
|
860
|
+
},
|
|
861
|
+
&mut || {},
|
|
862
|
+
)
|
|
835
863
|
.unwrap();
|
|
836
864
|
assert_eq!(lines, 100_000);
|
|
837
865
|
assert!(blocks > 1, "2.7 MB arrives in more than one read");
|
|
@@ -845,8 +873,14 @@ mod tests {
|
|
|
845
873
|
"echo partial; echo oops >&2; exit 3".to_string(),
|
|
846
874
|
];
|
|
847
875
|
let mut seen = String::new();
|
|
848
|
-
let err =
|
|
849
|
-
|
|
876
|
+
let err = run_argv_blocks(
|
|
877
|
+
"t",
|
|
878
|
+
&argv,
|
|
879
|
+
&cwd(),
|
|
880
|
+
&mut |block| seen.push_str(block),
|
|
881
|
+
&mut || {},
|
|
882
|
+
)
|
|
883
|
+
.unwrap_err();
|
|
850
884
|
assert_eq!(seen, "partial\n");
|
|
851
885
|
match err {
|
|
852
886
|
CommandError::NonZeroExit {
|
|
@@ -859,10 +893,26 @@ mod tests {
|
|
|
859
893
|
}
|
|
860
894
|
}
|
|
861
895
|
|
|
896
|
+
#[test]
|
|
897
|
+
fn drain_then_reap_ends_the_output_before_reaping_the_child() {
|
|
898
|
+
let order = std::cell::RefCell::new(Vec::new());
|
|
899
|
+
let reaped = drain_then_reap(
|
|
900
|
+
&mut &b"a\nb"[..],
|
|
901
|
+
&mut |block| order.borrow_mut().push(block.to_string()),
|
|
902
|
+
&mut || order.borrow_mut().push("eof".to_string()),
|
|
903
|
+
|| {
|
|
904
|
+
order.borrow_mut().push("reap".to_string());
|
|
905
|
+
7
|
|
906
|
+
},
|
|
907
|
+
);
|
|
908
|
+
assert_eq!(reaped, 7);
|
|
909
|
+
assert_eq!(*order.borrow(), vec!["a\n", "b", "eof", "reap"]);
|
|
910
|
+
}
|
|
911
|
+
|
|
862
912
|
#[test]
|
|
863
913
|
fn run_argv_blocks_names_a_missing_program() {
|
|
864
914
|
let argv = vec!["definitely-not-a-real-binary-xyzzy".to_string()];
|
|
865
|
-
let err = run_argv_blocks("t", &argv, &cwd(), &mut |_| {}).unwrap_err();
|
|
915
|
+
let err = run_argv_blocks("t", &argv, &cwd(), &mut |_| {}, &mut || {}).unwrap_err();
|
|
866
916
|
assert!(
|
|
867
917
|
matches!(err, CommandError::NotOnPath { .. }),
|
|
868
918
|
"got: {err:?}"
|
|
@@ -54,18 +54,32 @@ pub(crate) fn commit(conn: &Connection) -> Result<(), DbError> {
|
|
|
54
54
|
pub(crate) fn atomically<T, E: From<rusqlite::Error>>(
|
|
55
55
|
conn: &Connection,
|
|
56
56
|
unit: impl FnOnce() -> Result<T, E>,
|
|
57
|
+
) -> Result<T, E> {
|
|
58
|
+
let value = stage(conn, unit)?;
|
|
59
|
+
keep(conn)?;
|
|
60
|
+
Ok(value)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// Apply `unit` but hold it open, for [`keep`] or [`discard`] to settle. A
|
|
64
|
+
/// unit that fails is discarded here and leaves nothing open.
|
|
65
|
+
pub(crate) fn stage<T, E: From<rusqlite::Error>>(
|
|
66
|
+
conn: &Connection,
|
|
67
|
+
unit: impl FnOnce() -> Result<T, E>,
|
|
57
68
|
) -> Result<T, E> {
|
|
58
69
|
conn.execute_batch("SAVEPOINT dirsql_unit")?;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
unit().inspect_err(|_| {
|
|
71
|
+
let _ = discard(conn);
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// Keep the unit [`stage`] left open.
|
|
76
|
+
pub(crate) fn keep(conn: &Connection) -> rusqlite::Result<()> {
|
|
77
|
+
conn.execute_batch("RELEASE dirsql_unit")
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/// Drop the unit [`stage`] left open, as if it had never run.
|
|
81
|
+
pub(crate) fn discard(conn: &Connection) -> rusqlite::Result<()> {
|
|
82
|
+
conn.execute_batch("ROLLBACK TO dirsql_unit; RELEASE dirsql_unit")
|
|
69
83
|
}
|
|
70
84
|
|
|
71
85
|
/// The rows violating a foreign key right now, or `None` when there are none.
|
|
@@ -402,4 +416,41 @@ mod tests {
|
|
|
402
416
|
commit(&conn).unwrap();
|
|
403
417
|
assert_eq!(count(&conn, "parent"), 1);
|
|
404
418
|
}
|
|
419
|
+
#[test]
|
|
420
|
+
fn a_staged_unit_is_visible_until_discarded() {
|
|
421
|
+
let conn = family(CHILD);
|
|
422
|
+
let out: rusqlite::Result<i32> = stage(&conn, || {
|
|
423
|
+
conn.execute_batch("INSERT INTO parent VALUES (1, 'a')")?;
|
|
424
|
+
Ok(7)
|
|
425
|
+
});
|
|
426
|
+
assert_eq!(out.unwrap(), 7);
|
|
427
|
+
assert_eq!(count(&conn, "parent"), 1);
|
|
428
|
+
discard(&conn).unwrap();
|
|
429
|
+
assert_eq!(count(&conn, "parent"), 0);
|
|
430
|
+
assert!(conn.is_autocommit());
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
#[test]
|
|
434
|
+
fn a_staged_unit_kept_stays() {
|
|
435
|
+
let conn = family(CHILD);
|
|
436
|
+
let out: rusqlite::Result<()> = stage(&conn, || {
|
|
437
|
+
conn.execute_batch("INSERT INTO parent VALUES (1, 'a')")
|
|
438
|
+
});
|
|
439
|
+
out.unwrap();
|
|
440
|
+
keep(&conn).unwrap();
|
|
441
|
+
assert!(conn.is_autocommit());
|
|
442
|
+
assert_eq!(count(&conn, "parent"), 1);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
#[test]
|
|
446
|
+
fn a_staged_unit_that_fails_leaves_nothing_open() {
|
|
447
|
+
let conn = family(CHILD);
|
|
448
|
+
let out: rusqlite::Result<()> = stage(&conn, || {
|
|
449
|
+
conn.execute_batch("INSERT INTO parent VALUES (1, 'a')")?;
|
|
450
|
+
conn.execute_batch("INSERT INTO nowhere VALUES (1)")
|
|
451
|
+
});
|
|
452
|
+
assert!(out.is_err());
|
|
453
|
+
assert!(conn.is_autocommit());
|
|
454
|
+
assert_eq!(count(&conn, "parent"), 0);
|
|
455
|
+
}
|
|
405
456
|
}
|
|
@@ -108,7 +108,10 @@ type OnFileFn = dyn Fn(&str) -> std::result::Result<Vec<Row>, BoxError> + Send +
|
|
|
108
108
|
type RowSink<'a> = dyn FnMut(Vec<infer::JsonRow>) + Send + 'a;
|
|
109
109
|
/// The paths a per-table hook runs over, yielded as the scan finds them.
|
|
110
110
|
type PathFeed<'a> = dyn Iterator<Item = PathBuf> + Send + 'a;
|
|
111
|
-
|
|
111
|
+
/// What a per-table hook may call once its last chunk is out, before it knows
|
|
112
|
+
/// whether it succeeded, so its rows can be staged while it finishes.
|
|
113
|
+
type OutputEnd<'a> = dyn FnMut() + 'a;
|
|
114
|
+
type OnFilesFn = dyn Fn(&mut PathFeed<'_>, &mut RowSink<'_>, &mut OutputEnd<'_>) -> std::result::Result<(), BoxError>
|
|
112
115
|
+ Send
|
|
113
116
|
+ Sync
|
|
114
117
|
+ 'static;
|
|
@@ -378,11 +381,16 @@ impl Table {
|
|
|
378
381
|
+ Sync
|
|
379
382
|
+ 'static,
|
|
380
383
|
{
|
|
381
|
-
Self::per_table_streaming(
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
384
|
+
Self::per_table_streaming(
|
|
385
|
+
name,
|
|
386
|
+
ddl,
|
|
387
|
+
glob,
|
|
388
|
+
move |feed, sink: &mut RowSink<'_>, _: &mut OutputEnd<'_>| {
|
|
389
|
+
let paths: Vec<PathBuf> = feed.collect();
|
|
390
|
+
sink(on_files(&paths)?);
|
|
391
|
+
Ok(())
|
|
392
|
+
},
|
|
393
|
+
)
|
|
386
394
|
}
|
|
387
395
|
|
|
388
396
|
/// [`per_table`](Self::per_table) for a hook that hands its rows over in
|
|
@@ -394,7 +402,11 @@ impl Table {
|
|
|
394
402
|
on_files: F,
|
|
395
403
|
) -> Self
|
|
396
404
|
where
|
|
397
|
-
F: Fn(
|
|
405
|
+
F: Fn(
|
|
406
|
+
&mut PathFeed<'_>,
|
|
407
|
+
&mut RowSink<'_>,
|
|
408
|
+
&mut OutputEnd<'_>,
|
|
409
|
+
) -> std::result::Result<(), BoxError>
|
|
398
410
|
+ Send
|
|
399
411
|
+ Sync
|
|
400
412
|
+ 'static,
|
|
@@ -1031,27 +1043,31 @@ impl DirSQL {
|
|
|
1031
1043
|
.unwrap_or_default(),
|
|
1032
1044
|
Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
|
|
1033
1045
|
};
|
|
1034
|
-
let raw_rows = match collect_table_rows(hook.as_ref(), &abs_paths) {
|
|
1035
|
-
Ok(rows) => rows,
|
|
1036
|
-
Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
|
|
1037
|
-
};
|
|
1038
1046
|
let strict = *self.inner.strict_map.get(table).unwrap_or(&false);
|
|
1039
|
-
|
|
1040
|
-
let
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
|
|
1047
|
+
let rows = Mutex::new(Vec::new());
|
|
1048
|
+
let take_rows = || std::mem::take(&mut *rows.lock().expect("hook rows lock"));
|
|
1049
|
+
let mut staged = None;
|
|
1050
|
+
let produced = hook(
|
|
1051
|
+
&mut abs_paths.into_iter(),
|
|
1052
|
+
&mut |chunk| rows.lock().expect("hook rows lock").extend(chunk),
|
|
1053
|
+
&mut || staged = Some(self.stage_table_rows(table, take_rows(), strict)),
|
|
1054
|
+
);
|
|
1055
|
+
let staged = match (produced, staged) {
|
|
1056
|
+
(Err(e), staged) => {
|
|
1057
|
+
if let Some(Ok(staged)) = staged {
|
|
1058
|
+
let _ = foreign_key::discard(staged.db.conn());
|
|
1059
|
+
}
|
|
1060
|
+
return vec![error_event(Some(table), trigger, e.to_string())];
|
|
1054
1061
|
}
|
|
1062
|
+
(Ok(()), Some(staged)) => staged,
|
|
1063
|
+
(Ok(()), None) => self.stage_table_rows(table, take_rows(), strict),
|
|
1064
|
+
};
|
|
1065
|
+
let changes = match staged {
|
|
1066
|
+
Ok(Staged { db, changes }) => match foreign_key::keep(db.conn()) {
|
|
1067
|
+
Ok(()) => changes,
|
|
1068
|
+
Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
|
|
1069
|
+
},
|
|
1070
|
+
Err(message) => return vec![error_event(Some(table), trigger, message)],
|
|
1055
1071
|
};
|
|
1056
1072
|
|
|
1057
1073
|
if changes.keyed {
|
|
@@ -1067,6 +1083,23 @@ impl DirSQL {
|
|
|
1067
1083
|
}
|
|
1068
1084
|
}
|
|
1069
1085
|
|
|
1086
|
+
/// Shape a per-table hook's rows and write them as `table`'s, held open
|
|
1087
|
+
/// under the database lock until the hook's exit keeps or discards them.
|
|
1088
|
+
fn stage_table_rows(
|
|
1089
|
+
&self,
|
|
1090
|
+
table: &str,
|
|
1091
|
+
raw_rows: Vec<infer::JsonRow>,
|
|
1092
|
+
strict: bool,
|
|
1093
|
+
) -> std::result::Result<Staged<'_>, String> {
|
|
1094
|
+
let db = self.inner.db.lock().map_err(|e| e.to_string())?;
|
|
1095
|
+
let rows = shape_rows(&db, table, raw_rows, strict)?;
|
|
1096
|
+
let changes = foreign_key::stage(db.conn(), || {
|
|
1097
|
+
db.reconcile_batch_rows(table, BATCH_OWNER, &rows)
|
|
1098
|
+
})
|
|
1099
|
+
.map_err(|e| e.to_string())?;
|
|
1100
|
+
Ok(Staged { db, changes })
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1070
1103
|
/// Record in the table's file set whether `abs_path` is, now, one of the
|
|
1071
1104
|
/// files its per-table hook runs over. The set stays in walk order
|
|
1072
1105
|
/// (component-wise byte order), so the hook sees the same argument list a
|
|
@@ -2567,16 +2600,6 @@ fn shape_rows(
|
|
|
2567
2600
|
.map_err(|e| e.to_string())
|
|
2568
2601
|
}
|
|
2569
2602
|
|
|
2570
|
-
/// Every row a per-table hook produces over `paths`, gathered into one list.
|
|
2571
|
-
fn collect_table_rows(
|
|
2572
|
-
hook: &OnFilesFn,
|
|
2573
|
-
paths: &[PathBuf],
|
|
2574
|
-
) -> std::result::Result<Vec<infer::JsonRow>, BoxError> {
|
|
2575
|
-
let mut rows = Vec::new();
|
|
2576
|
-
hook(&mut paths.iter().cloned(), &mut |chunk| rows.extend(chunk))?;
|
|
2577
|
-
Ok(rows)
|
|
2578
|
-
}
|
|
2579
|
-
|
|
2580
2603
|
/// Replace a per-table hook's rows under [`BATCH_OWNER`], storing each chunk
|
|
2581
2604
|
/// the hook emits while the hook, on its own thread, goes on producing the
|
|
2582
2605
|
/// next. Chunks are shaped on a thread of their own, in order, so shaping one
|
|
@@ -2660,6 +2683,12 @@ fn refill_table_rows(
|
|
|
2660
2683
|
Ok(outcome)
|
|
2661
2684
|
}
|
|
2662
2685
|
|
|
2686
|
+
/// A per-table hook's rows written but not yet kept.
|
|
2687
|
+
struct Staged<'a> {
|
|
2688
|
+
db: std::sync::MutexGuard<'a, Db>,
|
|
2689
|
+
changes: db::RowChanges,
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2663
2692
|
/// A per-table hook running on its own thread, its rows arriving as chunks.
|
|
2664
2693
|
struct Production {
|
|
2665
2694
|
chunks: std::sync::mpsc::Receiver<Vec<infer::JsonRow>>,
|
|
@@ -2689,9 +2718,13 @@ fn start_hook(
|
|
|
2689
2718
|
if paths.peek().is_none() {
|
|
2690
2719
|
return Ok(());
|
|
2691
2720
|
}
|
|
2692
|
-
hook(
|
|
2693
|
-
|
|
2694
|
-
|
|
2721
|
+
hook(
|
|
2722
|
+
&mut paths,
|
|
2723
|
+
&mut |chunk| {
|
|
2724
|
+
let _ = sender.send(chunk);
|
|
2725
|
+
},
|
|
2726
|
+
&mut || {},
|
|
2727
|
+
)
|
|
2695
2728
|
.map_err(|e| e.to_string())
|
|
2696
2729
|
});
|
|
2697
2730
|
Production { chunks, handle }
|
|
@@ -2964,8 +2997,8 @@ fn build_tables_from_config(cfg: &config::Config, config_dir: &Path) -> Result<V
|
|
|
2964
2997
|
table_cfg.name.clone(),
|
|
2965
2998
|
table_cfg.ddl.clone(),
|
|
2966
2999
|
glob,
|
|
2967
|
-
move |paths: &mut PathFeed<'_>, sink: &mut RowSink<'_>| {
|
|
2968
|
-
run_on_files(&command, paths, &hook_cwd, &hook_root, sink)
|
|
3000
|
+
move |paths: &mut PathFeed<'_>, sink: &mut RowSink<'_>, end: &mut OutputEnd<'_>| {
|
|
3001
|
+
run_on_files(&command, paths, &hook_cwd, &hook_root, sink, end)
|
|
2969
3002
|
},
|
|
2970
3003
|
)
|
|
2971
3004
|
.anchored(anchor)
|
|
@@ -2992,9 +3025,10 @@ fn run_on_files(
|
|
|
2992
3025
|
config_dir: &Path,
|
|
2993
3026
|
root: &Path,
|
|
2994
3027
|
sink: &mut RowSink<'_>,
|
|
3028
|
+
end: &mut OutputEnd<'_>,
|
|
2995
3029
|
) -> std::result::Result<(), BoxError> {
|
|
2996
3030
|
Ok(on_file::run_streaming(
|
|
2997
|
-
command, config_dir, root, paths, sink,
|
|
3031
|
+
command, config_dir, root, paths, sink, end,
|
|
2998
3032
|
)?)
|
|
2999
3033
|
}
|
|
3000
3034
|
|
|
@@ -3478,7 +3512,7 @@ mod internal_tests {
|
|
|
3478
3512
|
"items",
|
|
3479
3513
|
"CREATE TABLE items (name TEXT)",
|
|
3480
3514
|
"**/*.txt",
|
|
3481
|
-
move |paths: &mut PathFeed<'_>, _: &mut RowSink<'_>| {
|
|
3515
|
+
move |paths: &mut PathFeed<'_>, _: &mut RowSink<'_>, _: &mut OutputEnd<'_>| {
|
|
3482
3516
|
for path in paths {
|
|
3483
3517
|
let _ = got.lock().unwrap().send(path);
|
|
3484
3518
|
}
|
|
@@ -4794,7 +4828,7 @@ mod internal_tests {
|
|
|
4794
4828
|
chunks: Vec<Vec<infer::JsonRow>>,
|
|
4795
4829
|
outcome: std::result::Result<(), String>,
|
|
4796
4830
|
) -> Production {
|
|
4797
|
-
let hook: Arc<OnFilesFn> = Arc::new(move |_paths, sink| {
|
|
4831
|
+
let hook: Arc<OnFilesFn> = Arc::new(move |_paths, sink, _end| {
|
|
4798
4832
|
for chunk in chunks.clone() {
|
|
4799
4833
|
sink(chunk);
|
|
4800
4834
|
}
|
|
@@ -5399,12 +5433,14 @@ mod internal_tests {
|
|
|
5399
5433
|
let Hook::PerTable(on_files) = &tables[0].hook else {
|
|
5400
5434
|
panic!("a configured on-file command runs once per table");
|
|
5401
5435
|
};
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
)
|
|
5436
|
+
let mut rows = Vec::new();
|
|
5437
|
+
on_files(
|
|
5438
|
+
&mut std::iter::once(dir.path().join("f.a")),
|
|
5439
|
+
&mut |chunk| rows.extend(chunk),
|
|
5440
|
+
&mut || {},
|
|
5441
|
+
)
|
|
5442
|
+
.unwrap();
|
|
5443
|
+
assert_eq!(rows.len(), 1);
|
|
5408
5444
|
assert!(tables[1].strict, "on-file table preserves strict flag");
|
|
5409
5445
|
}
|
|
5410
5446
|
|
|
@@ -5574,6 +5610,7 @@ mod internal_tests {
|
|
|
5574
5610
|
config_dir,
|
|
5575
5611
|
root,
|
|
5576
5612
|
&mut |chunk| rows.extend(chunk),
|
|
5613
|
+
&mut || {},
|
|
5577
5614
|
)?;
|
|
5578
5615
|
Ok(rows)
|
|
5579
5616
|
}
|
|
@@ -5605,6 +5642,7 @@ mod internal_tests {
|
|
|
5605
5642
|
dir.path(),
|
|
5606
5643
|
dir.path(),
|
|
5607
5644
|
&mut |chunk| chunks.push(chunk),
|
|
5645
|
+
&mut || {},
|
|
5608
5646
|
)
|
|
5609
5647
|
.expect("a well-formed payload parses");
|
|
5610
5648
|
assert!(chunks.len() > 1, "{} invocation(s)", chunks.len());
|
|
@@ -5991,7 +6029,7 @@ mod internal_tests {
|
|
|
5991
6029
|
"items",
|
|
5992
6030
|
"CREATE TABLE items (name TEXT)",
|
|
5993
6031
|
"*.txt",
|
|
5994
|
-
move |_: &mut PathFeed<'_>, sink: &mut RowSink<'_>| hook(sink),
|
|
6032
|
+
move |_: &mut PathFeed<'_>, sink: &mut RowSink<'_>, _: &mut OutputEnd<'_>| hook(sink),
|
|
5995
6033
|
)
|
|
5996
6034
|
}
|
|
5997
6035
|
|
|
@@ -6421,6 +6459,69 @@ mod internal_tests {
|
|
|
6421
6459
|
);
|
|
6422
6460
|
}
|
|
6423
6461
|
|
|
6462
|
+
/// A per-table hook that answers `answer`'s name, ends its output, and
|
|
6463
|
+
/// then fails when `answer` says so.
|
|
6464
|
+
fn ending_per_table(answer: Arc<Mutex<(String, bool)>>) -> Table {
|
|
6465
|
+
Table::per_table_streaming(
|
|
6466
|
+
"items",
|
|
6467
|
+
"CREATE TABLE items (name TEXT)",
|
|
6468
|
+
"**/*.txt",
|
|
6469
|
+
move |_: &mut PathFeed<'_>, sink: &mut RowSink<'_>, end: &mut OutputEnd<'_>| {
|
|
6470
|
+
let (name, fails) = answer.lock().unwrap().clone();
|
|
6471
|
+
sink(vec![name_json_row(&name)]);
|
|
6472
|
+
end();
|
|
6473
|
+
if fails {
|
|
6474
|
+
return Err("exited 1".into());
|
|
6475
|
+
}
|
|
6476
|
+
Ok(())
|
|
6477
|
+
},
|
|
6478
|
+
)
|
|
6479
|
+
}
|
|
6480
|
+
|
|
6481
|
+
fn ending_hook_db(answer: &Arc<Mutex<(String, bool)>>) -> (TempDir, DirSQL, PathBuf) {
|
|
6482
|
+
let dir = TempDir::new().unwrap();
|
|
6483
|
+
let root = dir.path().to_path_buf();
|
|
6484
|
+
let a = root.join("a.txt");
|
|
6485
|
+
let fake = Arc::new(
|
|
6486
|
+
FakeFs::default().with_subtree(root.clone(), vec![(a.clone(), "items".into())]),
|
|
6487
|
+
);
|
|
6488
|
+
let items = ending_per_table(Arc::clone(answer));
|
|
6489
|
+
let db =
|
|
6490
|
+
DirSQL::with_ignore_and_fs(&root, vec![items], Vec::<String>::new(), fake).unwrap();
|
|
6491
|
+
db.apply_file_events(vec![FileEvent::Created(a.clone())]);
|
|
6492
|
+
(dir, db, a)
|
|
6493
|
+
}
|
|
6494
|
+
|
|
6495
|
+
#[test]
|
|
6496
|
+
fn a_per_table_hook_that_fails_after_ending_its_output_writes_nothing() {
|
|
6497
|
+
let answer = Arc::new(Mutex::new(("old".to_string(), false)));
|
|
6498
|
+
let (_dir, db, a) = ending_hook_db(&answer);
|
|
6499
|
+
*answer.lock().unwrap() = ("new".to_string(), true);
|
|
6500
|
+
|
|
6501
|
+
let events = db.apply_file_events(vec![FileEvent::Modified(a)]);
|
|
6502
|
+
|
|
6503
|
+
assert!(
|
|
6504
|
+
matches!(&events[..], [RowEvent::Error { error, .. }] if error.contains("exited 1")),
|
|
6505
|
+
"{events:?}"
|
|
6506
|
+
);
|
|
6507
|
+
assert_eq!(row_names(&db), vec!["old"]);
|
|
6508
|
+
}
|
|
6509
|
+
|
|
6510
|
+
#[test]
|
|
6511
|
+
fn a_per_table_hook_that_succeeds_after_ending_its_output_keeps_its_rows() {
|
|
6512
|
+
let answer = Arc::new(Mutex::new(("old".to_string(), false)));
|
|
6513
|
+
let (_dir, db, a) = ending_hook_db(&answer);
|
|
6514
|
+
*answer.lock().unwrap() = ("new".to_string(), false);
|
|
6515
|
+
|
|
6516
|
+
let events = db.apply_file_events(vec![FileEvent::Modified(a)]);
|
|
6517
|
+
|
|
6518
|
+
assert!(
|
|
6519
|
+
matches!(&events[..], [RowEvent::Update { .. }]),
|
|
6520
|
+
"{events:?}"
|
|
6521
|
+
);
|
|
6522
|
+
assert_eq!(row_names(&db), vec!["new"]);
|
|
6523
|
+
}
|
|
6524
|
+
|
|
6424
6525
|
#[test]
|
|
6425
6526
|
fn apply_file_events_writes_only_the_rows_a_per_table_refresh_changed() {
|
|
6426
6527
|
let dir = TempDir::new().unwrap();
|