dirsql 0.4.104__tar.gz → 0.4.105__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.104 → dirsql-0.4.105}/Cargo.lock +2 -2
- {dirsql-0.4.104 → dirsql-0.4.105}/PKG-INFO +1 -1
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/Cargo.toml +1 -1
- dirsql-0.4.105/packages/python/e2e-attestations/bot-1457-incremental-refresh-1008.json +7 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/Cargo.toml +1 -1
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/db.rs +251 -12
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/lib.rs +191 -30
- {dirsql-0.4.104 → dirsql-0.4.105}/Cargo.toml +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/README.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/__init__.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/_async.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/cli/discover_plugins/__init__.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/cli/main.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/cli/resolve_config_extensions.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/plan_entry_path.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/py.typed +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/read_config.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/resolve_configs_extension_specs.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/resolve_extension.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/dirsql/resolve_package.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/AGENTS.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/context/.gitattributes +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/context/recipes.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/context/troubleshooting.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/context/usage.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/explanation.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/getting-started.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/agent-skill.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/embed.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/persist.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/query-json.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/index.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/package.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/plugins.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/reference/cli.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/reference/columns.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/reference/config.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/reference/glob.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/reference/hooks.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/reference/http-api.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/docs/reference/sdk.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/CHANGELOG.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/MIGRATIONS.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/README.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-08-20-curtaincall-dev-dependency.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-09-04-config-paths-from-argv-module.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-09-05-config-extension-loader-split.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-09-05-resolve-config-extensions-split.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-09-05-resolve-extension-split.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-09-09-launcher-config-path-scan.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-09-17-extension-resolution-via-core.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-09-18-export-scan-failure.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-09-18-flatten-row-event-in-core.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-09-18-programmatic-extension-plan.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-09-24-query-rows-in-projection-order.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-02-readme-docs-host.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-03-one-glob-rule-for-config-globs.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-03-path-table-directory-one-level.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-04-path-table-dotfiles-hidden.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-05-brace-groups-follow-bash.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-05-cli-context.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-05-gitignore-requires-repo.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-05-path-table-node-modules-named.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-05-path-table-symlinks.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-05-path-table-trailing-slash.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-05-unbalanced-brackets-literal.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-06-config-braces.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-06-config-directory.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-06-config-dotnames.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-06-config-gitignore.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-06-config-globs-anchor-at-the-config.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-06-config-links.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-06-one-glob-compiler.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-06-plugin-no-default-records.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-06-watch-broadcast.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-06-zero-match-config-table-warning.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-07-bracket-slash-literal.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-07-dotdot-and-double-slashes.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-07-dotdot-as-written.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-07-glob-walks-node-modules.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-07-literal-gitignore.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-07-on-file-ndjson.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-07-parallel-hooks.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-07-persist-cache-outside-root.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-07-posix-classes-unicode.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-07-spread-few-large-files.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/2026-10-08-small-walks-stay-on-one-thread.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/changelog.d/README.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/conftest.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/context/.gitattributes +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/context/recipes.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/context/troubleshooting.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/context/usage.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/explanation.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/getting-started.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/agent-skill.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/embed.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/persist.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/query-json.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/index.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/package.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/plugins.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/reference/cli.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/reference/columns.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/reference/config.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/reference/glob.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/reference/hooks.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/reference/http-api.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/docs/reference/sdk.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1334-listing-exemptions.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1397-watch-broadcast.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1398-inotify-error.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1399-server-cors.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1401-watch-scope.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1407-child-place-depth.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1414-stat-speed.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1415-server-speed.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1418-node-modules.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1419-dotdot-slashes.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1420-bracket-slash.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1421-posix-unicode.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1422-literal-gitignore.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1426-walk-spawn-threshold-1008.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1428-ndjson-hooks.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1429-parallel-hooks.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1430-dotdot-as-written.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1431-persist-cache-dir.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1437-test-cache-isolation.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1440-fix-main-build.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1448-wildcard-ignored-prefix.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1451-named-dir-never-hidden.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-1454-split-few-files.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/bot-fix-main-place-depth-20261007.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/cc-keen-knuth-f11gyq.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1056-py-ofpf9.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1066-p1-resolve-extension.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1078-argv-config-paths-core.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1079-p2-resolve-config-extensions.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1080-share-vtab-scaffolding.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1081-indicatif-progress.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1096-watch-moved-dir.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1109-watch-moved-out.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1119-ext-plan.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1120-py-ext.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1122-ext-cleanup.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1130-codec-crates.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1131-flatten-row-event.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1139-sse-flatten.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1140-scan-failure-export.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1148-clippy-all-targets.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1164-sigint-fatal.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1170-projection-order.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1172-on-file-path.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1173-py-projection-order.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1184-win-rel-paths.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1185-win-abs-table-names.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1186-win-test-harness.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1196-join-index.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1199-glob-prefix.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1201-single-walk.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1204-embed-batch.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1207-win-argv-quote.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1208-win-nonverbatim-paths.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1215-on-file-batch.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1216-on-file-cleanup.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1223-config-glob-rule.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1223-dir-one-level.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1225-plugin-no-default.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1226-stale-docs.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1232-anchor-plumbing.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1232-config-anchor.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1232-multi-watch.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1232-zero-match.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1238-parallel-walk.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1241-content-prefetch.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1243-ingest-perf.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1249-dotfiles.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1256-symlinks.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1257-trailing-slash.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1258-config-braces.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1258-config-directory.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1258-config-dotnames.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1258-config-gitignore.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1258-config-links.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1258-one-pattern.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1262-brace-literal.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1264-context.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1267-posix-classes.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1268-unbalanced-brackets.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1269-utf8-chars.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1271-node-modules-named.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1272-ancestor-gitignore.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1273-walk-prune.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1285-ingest-fast.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1286-nested-repo.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1305-glob-speed.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1308-glob-speed.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1310-glob-speed.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1311-glob-speed.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1312-glob-speed.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1318-lazy-stat.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1320-walk-speed.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1322-walk-readdir.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1325-parallel-walk.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1326-stream-rows.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1330-python-dirsql-patch.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1330-python-extensions-patch.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1330-scanner-effects.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1330-scanner-gitignore.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1330-vtab-prefetch-flag.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1330-vtab-read.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-1351-dot-dirs.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-epic-953-slice2-reedline.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-epic-953-slice3-format.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-epic-953-stacked-prs-x59wm3.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-issue-986-red-test-e7sjrb.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-tackle-1034-cachesplit.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-tackle-1042-py12.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-tackle-956-xzen74.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6-worker-calls.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/e2e-attestations/claude-tackle-975-n8mc2h.json +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-09-24-query-rows-in-projection-order.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-02-readme-docs-host.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-03-one-glob-rule-for-config-globs.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-03-path-table-directory-one-level.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-04-path-table-dotfiles-hidden.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-05-brace-groups-follow-bash.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-05-cli-context.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-05-gitignore-requires-repo.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-05-path-table-node-modules-named.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-05-path-table-symlinks.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-05-path-table-trailing-slash.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-05-unbalanced-brackets-literal.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-06-config-braces.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-06-config-directory.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-06-config-dotnames.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-06-config-gitignore.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-06-config-globs-anchor-at-the-config.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-06-config-links.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-06-one-glob-compiler.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-06-plugin-no-default-records.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-06-watch-broadcast.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-06-zero-match-config-table-warning.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-07-bracket-slash-literal.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-07-dotdot-and-double-slashes.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-07-dotdot-as-written.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-07-glob-walks-node-modules.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-07-literal-gitignore.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-07-on-file-ndjson.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-07-parallel-hooks.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-07-persist-cache-outside-root.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-07-posix-classes-unicode.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-07-spread-few-large-files.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/2026-10-08-small-walks-stay-on-one-thread.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/migrations.d/README.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/src/lib.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/testing-conventions.toml +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/tests/e2e/speed_of_light.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/tests/integration/binding/__init__.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/python/tests/integration/hermetic/__init__.py +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/CHANGELOG.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/MIGRATIONS.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/README.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/context/.gitattributes +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/context/recipes.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/context/troubleshooting.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/context/usage.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/explanation.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/getting-started.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/agent-skill.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/embed.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/persist.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/query-json.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/index.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/plugins.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/reference/cli.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/reference/columns.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/reference/config.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/reference/glob.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/reference/hooks.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/reference/http-api.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/docs/reference/sdk.md +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/brace.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/cli/context.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/cli/execute.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/cli/repl.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/cli/run.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/cli/table.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/command.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/config.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/default_config.toml +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/extension_resolution.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/functions.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/infer.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/launcher.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/listing.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/on_file.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/parsed_vtab.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/path_table.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/posix_class.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/progress.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/row_event_flat.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/sql_literal.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/tree_walk.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/vtab.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/vtab_scaffold.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.4.104 → dirsql-0.4.105}/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.105"
|
|
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.105"
|
|
629
629
|
dependencies = [
|
|
630
630
|
"dirsql",
|
|
631
631
|
"pyo3",
|
|
@@ -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.105"
|
|
8
8
|
# abi3 note: the `abi3-py310` pyo3 feature (below) builds ONE stable-ABI
|
|
9
9
|
# `cp310-abi3` wheel per platform that loads on every CPython >= 3.10
|
|
10
10
|
# (matching `pyproject.toml`'s `requires-python = ">=3.10"`), instead of
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"command": "uv run python -m pytest tests/e2e/on_file_query_test.py tests/e2e/query_contract_test.py tests/e2e/use_case_transcripts_test.py -x -q",
|
|
3
|
+
"ran_at": 1791462122,
|
|
4
|
+
"exit_code": 0,
|
|
5
|
+
"commit": "e59418c942479166b7edd1a1587ed559574c60b7",
|
|
6
|
+
"branch": "bot/1457-incremental-refresh-1008"
|
|
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.105"
|
|
10
10
|
edition.workspace = true
|
|
11
11
|
# Literal `license` (not `license.workspace = true`) because
|
|
12
12
|
# putitoutthere's preflight check reads `[package].license` directly
|
|
@@ -266,6 +266,28 @@ pub fn ensure_internal_rows_table(conn: &Connection) -> rusqlite::Result<()> {
|
|
|
266
266
|
)
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
+
fn insert_sql(table: &str, columns: &[String]) -> String {
|
|
270
|
+
if columns.is_empty() {
|
|
271
|
+
return format!("INSERT INTO \"{table}\" DEFAULT VALUES");
|
|
272
|
+
}
|
|
273
|
+
let names: Vec<String> = columns.iter().map(|c| format!("\"{c}\"")).collect();
|
|
274
|
+
let placeholders: Vec<String> = (1..=columns.len()).map(|i| format!("?{i}")).collect();
|
|
275
|
+
format!(
|
|
276
|
+
"INSERT INTO \"{table}\" ({}) VALUES ({})",
|
|
277
|
+
names.join(", "),
|
|
278
|
+
placeholders.join(", ")
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/// The rows a [`Db::reconcile_batch_rows`] did not carry over: those only the
|
|
283
|
+
/// table held (`removed`) and those only the new rows hold (`added`), each in
|
|
284
|
+
/// its original order.
|
|
285
|
+
#[derive(Debug, Default)]
|
|
286
|
+
pub struct RowChanges {
|
|
287
|
+
pub removed: Vec<HashMap<String, Value>>,
|
|
288
|
+
pub added: Vec<HashMap<String, Value>>,
|
|
289
|
+
}
|
|
290
|
+
|
|
269
291
|
/// A batch of rows laid out in a table's DDL column order, so each row binds
|
|
270
292
|
/// positionally with no per-cell lookup.
|
|
271
293
|
#[derive(Debug, Clone, PartialEq)]
|
|
@@ -700,18 +722,7 @@ impl Db {
|
|
|
700
722
|
/// interleave batches of different owners.
|
|
701
723
|
pub fn insert_rows(&self, table: &str, rows: &ShapedRows, file_path: &str) -> Result<()> {
|
|
702
724
|
validate_identifier(table)?;
|
|
703
|
-
let
|
|
704
|
-
let sql = if columns.is_empty() {
|
|
705
|
-
format!("INSERT INTO \"{table}\" DEFAULT VALUES")
|
|
706
|
-
} else {
|
|
707
|
-
let names: Vec<String> = columns.iter().map(|c| format!("\"{c}\"")).collect();
|
|
708
|
-
let placeholders: Vec<String> = (1..=columns.len()).map(|i| format!("?{i}")).collect();
|
|
709
|
-
format!(
|
|
710
|
-
"INSERT INTO \"{table}\" ({}) VALUES ({})",
|
|
711
|
-
names.join(", "),
|
|
712
|
-
placeholders.join(", ")
|
|
713
|
-
)
|
|
714
|
-
};
|
|
725
|
+
let sql = insert_sql(table, &rows.columns);
|
|
715
726
|
let tx = if self.conn.is_autocommit() {
|
|
716
727
|
Some(self.conn.unchecked_transaction()?)
|
|
717
728
|
} else {
|
|
@@ -743,6 +754,99 @@ impl Db {
|
|
|
743
754
|
Ok(())
|
|
744
755
|
}
|
|
745
756
|
|
|
757
|
+
/// Make the table's rows, all owned by the batch `owner`, equal `rows`,
|
|
758
|
+
/// writing only the difference. The rows are compared as a multiset (a
|
|
759
|
+
/// batch has no row identity): an equal row already stored is left in
|
|
760
|
+
/// place, a stored row with no match is deleted, and a new row with no
|
|
761
|
+
/// match is inserted. The owner's rowid range is then re-fitted to the
|
|
762
|
+
/// table. Run it inside the caller's transaction.
|
|
763
|
+
pub fn reconcile_batch_rows(
|
|
764
|
+
&self,
|
|
765
|
+
table: &str,
|
|
766
|
+
owner: &str,
|
|
767
|
+
rows: &ShapedRows,
|
|
768
|
+
) -> Result<RowChanges> {
|
|
769
|
+
validate_identifier(table)?;
|
|
770
|
+
let columns = &rows.columns;
|
|
771
|
+
let select = if columns.is_empty() {
|
|
772
|
+
format!("SELECT rowid FROM \"{table}\" ORDER BY rowid")
|
|
773
|
+
} else {
|
|
774
|
+
let names: Vec<String> = columns.iter().map(|c| format!("\"{c}\"")).collect();
|
|
775
|
+
format!(
|
|
776
|
+
"SELECT rowid, {} FROM \"{table}\" ORDER BY rowid",
|
|
777
|
+
names.join(", ")
|
|
778
|
+
)
|
|
779
|
+
};
|
|
780
|
+
let mut stored: Vec<(i64, Vec<Value>)> = Vec::new();
|
|
781
|
+
{
|
|
782
|
+
let mut stmt = self.conn.prepare(&select)?;
|
|
783
|
+
let mut cursor = stmt.query([])?;
|
|
784
|
+
while let Some(row) = cursor.next()? {
|
|
785
|
+
let cells = (0..columns.len())
|
|
786
|
+
.map(|i| row.get::<_, rusqlite::types::Value>(i + 1).map(Value::from))
|
|
787
|
+
.collect::<rusqlite::Result<Vec<_>>>()?;
|
|
788
|
+
stored.push((row.get(0)?, cells));
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
let mut unclaimed: HashMap<String, Vec<usize>> = HashMap::new();
|
|
792
|
+
for (index, (_, cells)) in stored.iter().enumerate().rev() {
|
|
793
|
+
unclaimed
|
|
794
|
+
.entry(format!("{cells:?}"))
|
|
795
|
+
.or_default()
|
|
796
|
+
.push(index);
|
|
797
|
+
}
|
|
798
|
+
let mut added = Vec::new();
|
|
799
|
+
for (index, cells) in rows.cells.iter().enumerate() {
|
|
800
|
+
match unclaimed.get_mut(&format!("{cells:?}")) {
|
|
801
|
+
Some(indexes) if !indexes.is_empty() => {
|
|
802
|
+
indexes.pop();
|
|
803
|
+
}
|
|
804
|
+
_ => added.push(index),
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
let mut removed: Vec<usize> = unclaimed.into_values().flatten().collect();
|
|
808
|
+
removed.sort_unstable();
|
|
809
|
+
|
|
810
|
+
let to_map = |cells: &[Value]| -> HashMap<String, Value> {
|
|
811
|
+
columns.iter().cloned().zip(cells.iter().cloned()).collect()
|
|
812
|
+
};
|
|
813
|
+
let changes = RowChanges {
|
|
814
|
+
removed: removed.iter().map(|&i| to_map(&stored[i].1)).collect(),
|
|
815
|
+
added: added.iter().map(|&i| to_map(&rows.cells[i])).collect(),
|
|
816
|
+
};
|
|
817
|
+
if removed.is_empty() && added.is_empty() {
|
|
818
|
+
return Ok(changes);
|
|
819
|
+
}
|
|
820
|
+
let mut delete = self
|
|
821
|
+
.conn
|
|
822
|
+
.prepare_cached(&format!("DELETE FROM \"{table}\" WHERE rowid = ?1"))?;
|
|
823
|
+
for &index in &removed {
|
|
824
|
+
delete.execute([stored[index].0])?;
|
|
825
|
+
}
|
|
826
|
+
let mut insert = self.conn.prepare_cached(&insert_sql(table, columns))?;
|
|
827
|
+
for &index in &added {
|
|
828
|
+
for (i, value) in rows.cells[index].iter().enumerate() {
|
|
829
|
+
insert.raw_bind_parameter(i + 1, value)?;
|
|
830
|
+
}
|
|
831
|
+
insert.raw_execute()?;
|
|
832
|
+
}
|
|
833
|
+
self.conn.execute(
|
|
834
|
+
"DELETE FROM _dirsql_internal_ranges WHERE table_name = ?1 AND file_path = ?2",
|
|
835
|
+
rusqlite::params![table, owner],
|
|
836
|
+
)?;
|
|
837
|
+
let (first, last): (Option<i64>, Option<i64>) = self.conn.query_row(
|
|
838
|
+
&format!("SELECT min(rowid), max(rowid) FROM \"{table}\""),
|
|
839
|
+
[],
|
|
840
|
+
|r| Ok((r.get(0)?, r.get(1)?)),
|
|
841
|
+
)?;
|
|
842
|
+
if let (Some(first), Some(last)) = (first, last) {
|
|
843
|
+
self.conn
|
|
844
|
+
.prepare_cached(RANGE_INSERT)?
|
|
845
|
+
.execute(rusqlite::params![table, owner, first, last])?;
|
|
846
|
+
}
|
|
847
|
+
Ok(changes)
|
|
848
|
+
}
|
|
849
|
+
|
|
746
850
|
/// Both the table name and every user-provided column name are validated
|
|
747
851
|
/// as safe SQL identifiers before being interpolated. A column key with
|
|
748
852
|
/// SQL syntax (e.g. `id); DROP TABLE t; --`) produces a clean
|
|
@@ -3023,6 +3127,141 @@ mod tests {
|
|
|
3023
3127
|
assert!(range_rows(&db, "t").is_empty());
|
|
3024
3128
|
}
|
|
3025
3129
|
|
|
3130
|
+
fn table_rows(db: &Db, table: &str) -> Vec<(i64, String)> {
|
|
3131
|
+
db.conn()
|
|
3132
|
+
.prepare(&format!("SELECT rowid, id FROM {table} ORDER BY rowid"))
|
|
3133
|
+
.unwrap()
|
|
3134
|
+
.query_map([], |r| Ok((r.get(0)?, r.get(1)?)))
|
|
3135
|
+
.unwrap()
|
|
3136
|
+
.collect::<rusqlite::Result<_>>()
|
|
3137
|
+
.unwrap()
|
|
3138
|
+
}
|
|
3139
|
+
|
|
3140
|
+
fn ids(changes: &[HashMap<String, Value>]) -> Vec<Value> {
|
|
3141
|
+
changes.iter().map(|row| row["id"].clone()).collect()
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
fn batch_db(ids: serde_json::Value) -> Db {
|
|
3145
|
+
let db = Db::new().unwrap();
|
|
3146
|
+
db.create_table("t", "CREATE TABLE t (id TEXT)").unwrap();
|
|
3147
|
+
db.insert_rows("t", &shaped(&db, "t", ids), "").unwrap();
|
|
3148
|
+
db
|
|
3149
|
+
}
|
|
3150
|
+
|
|
3151
|
+
#[test]
|
|
3152
|
+
fn reconcile_batch_rows_leaves_equal_rows_in_place_and_writes_the_rest() {
|
|
3153
|
+
let db = batch_db(serde_json::json!([{"id":"a"},{"id":"b"},{"id":"c"}]));
|
|
3154
|
+
let next = shaped(
|
|
3155
|
+
&db,
|
|
3156
|
+
"t",
|
|
3157
|
+
serde_json::json!([{"id":"a"},{"id":"x"},{"id":"c"}]),
|
|
3158
|
+
);
|
|
3159
|
+
let before = db.conn().total_changes();
|
|
3160
|
+
|
|
3161
|
+
let changes = db.reconcile_batch_rows("t", "", &next).unwrap();
|
|
3162
|
+
|
|
3163
|
+
assert_eq!(
|
|
3164
|
+
table_rows(&db, "t"),
|
|
3165
|
+
vec![(1, "a".into()), (3, "c".into()), (4, "x".into())]
|
|
3166
|
+
);
|
|
3167
|
+
assert_eq!(ids(&changes.removed), vec![Value::Text("b".into())]);
|
|
3168
|
+
assert_eq!(ids(&changes.added), vec![Value::Text("x".into())]);
|
|
3169
|
+
assert_eq!(db.conn().total_changes() - before, 4);
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
#[test]
|
|
3173
|
+
fn reconcile_batch_rows_compares_rows_as_a_multiset() {
|
|
3174
|
+
let db = batch_db(serde_json::json!([{"id":"a"},{"id":"a"},{"id":"a"}]));
|
|
3175
|
+
let next = shaped(&db, "t", serde_json::json!([{"id":"a"},{"id":"a"}]));
|
|
3176
|
+
|
|
3177
|
+
let changes = db.reconcile_batch_rows("t", "", &next).unwrap();
|
|
3178
|
+
|
|
3179
|
+
assert_eq!(table_rows(&db, "t"), vec![(1, "a".into()), (2, "a".into())]);
|
|
3180
|
+
assert_eq!(ids(&changes.removed), vec![Value::Text("a".into())]);
|
|
3181
|
+
assert!(changes.added.is_empty());
|
|
3182
|
+
}
|
|
3183
|
+
|
|
3184
|
+
#[test]
|
|
3185
|
+
fn reconcile_batch_rows_inserts_each_copy_the_table_holds_too_few_of() {
|
|
3186
|
+
let db = batch_db(serde_json::json!([{"id":"a"}]));
|
|
3187
|
+
let next = shaped(
|
|
3188
|
+
&db,
|
|
3189
|
+
"t",
|
|
3190
|
+
serde_json::json!([{"id":"a"},{"id":"a"},{"id":"a"}]),
|
|
3191
|
+
);
|
|
3192
|
+
|
|
3193
|
+
let changes = db.reconcile_batch_rows("t", "", &next).unwrap();
|
|
3194
|
+
|
|
3195
|
+
assert_eq!(
|
|
3196
|
+
table_rows(&db, "t"),
|
|
3197
|
+
vec![(1, "a".into()), (2, "a".into()), (3, "a".into())]
|
|
3198
|
+
);
|
|
3199
|
+
assert_eq!(ids(&changes.added).len(), 2);
|
|
3200
|
+
assert!(changes.removed.is_empty());
|
|
3201
|
+
}
|
|
3202
|
+
|
|
3203
|
+
#[test]
|
|
3204
|
+
fn reconcile_batch_rows_writes_nothing_when_no_row_changed() {
|
|
3205
|
+
let db = batch_db(serde_json::json!([{"id":"a"},{"id":"b"}]));
|
|
3206
|
+
let same = shaped(&db, "t", serde_json::json!([{"id":"b"},{"id":"a"}]));
|
|
3207
|
+
let before = db.conn().total_changes();
|
|
3208
|
+
|
|
3209
|
+
let changes = db.reconcile_batch_rows("t", "", &same).unwrap();
|
|
3210
|
+
|
|
3211
|
+
assert!(changes.removed.is_empty() && changes.added.is_empty());
|
|
3212
|
+
assert_eq!(db.conn().total_changes(), before);
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3215
|
+
#[test]
|
|
3216
|
+
fn reconcile_batch_rows_refits_the_owners_range_to_the_table() {
|
|
3217
|
+
let db = batch_db(serde_json::json!([{"id":"a"},{"id":"b"},{"id":"c"}]));
|
|
3218
|
+
let next = shaped(&db, "t", serde_json::json!([{"id":"b"},{"id":"d"}]));
|
|
3219
|
+
db.reconcile_batch_rows("t", "", &next).unwrap();
|
|
3220
|
+
|
|
3221
|
+
assert_eq!(range_rows(&db, "t"), vec![(String::new(), 2, 3)]);
|
|
3222
|
+
let read: Vec<Value> = db
|
|
3223
|
+
.get_rows_by_file("t", "")
|
|
3224
|
+
.unwrap()
|
|
3225
|
+
.into_iter()
|
|
3226
|
+
.map(|r| r["id"].clone())
|
|
3227
|
+
.collect();
|
|
3228
|
+
assert_eq!(read, vec![Value::Text("b".into()), Value::Text("d".into())]);
|
|
3229
|
+
|
|
3230
|
+
let empty = shaped(&db, "t", serde_json::json!([]));
|
|
3231
|
+
db.reconcile_batch_rows("t", "", &empty).unwrap();
|
|
3232
|
+
assert!(range_rows(&db, "t").is_empty());
|
|
3233
|
+
assert!(table_rows(&db, "t").is_empty());
|
|
3234
|
+
}
|
|
3235
|
+
|
|
3236
|
+
#[test]
|
|
3237
|
+
fn reconcile_batch_rows_binds_an_empty_column_list_by_default_values() {
|
|
3238
|
+
let db = Db::new().unwrap();
|
|
3239
|
+
db.create_table("t", "CREATE TABLE t (id TEXT)").unwrap();
|
|
3240
|
+
let rows = ShapedRows {
|
|
3241
|
+
columns: vec![],
|
|
3242
|
+
cells: vec![vec![]],
|
|
3243
|
+
};
|
|
3244
|
+
db.reconcile_batch_rows("t", "", &rows).unwrap();
|
|
3245
|
+
assert_eq!(table_rows_count(&db), 1);
|
|
3246
|
+
}
|
|
3247
|
+
|
|
3248
|
+
fn table_rows_count(db: &Db) -> i64 {
|
|
3249
|
+
db.conn()
|
|
3250
|
+
.query_row("SELECT count(*) FROM t", [], |r| r.get(0))
|
|
3251
|
+
.unwrap()
|
|
3252
|
+
}
|
|
3253
|
+
|
|
3254
|
+
#[test]
|
|
3255
|
+
fn reconcile_batch_rows_rejects_an_unsafe_table_name() {
|
|
3256
|
+
let db = Db::new().unwrap();
|
|
3257
|
+
let rows = ShapedRows {
|
|
3258
|
+
columns: vec![],
|
|
3259
|
+
cells: vec![],
|
|
3260
|
+
};
|
|
3261
|
+
let err = db.reconcile_batch_rows("bad name", "", &rows).unwrap_err();
|
|
3262
|
+
assert!(matches!(err, DbError::InvalidIdentifier(_)), "got: {err}");
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3026
3265
|
#[test]
|
|
3027
3266
|
fn insert_rows_rejects_an_unsafe_table_name() {
|
|
3028
3267
|
let db = Db::new().unwrap();
|
|
@@ -755,6 +755,8 @@ impl DirSQL {
|
|
|
755
755
|
|
|
756
756
|
for m in matches {
|
|
757
757
|
if self.is_per_table(&m.table_name) {
|
|
758
|
+
let deleted = matches!(event, FileEvent::Deleted(_));
|
|
759
|
+
self.track_batch_file(&m.table_name, &abs_path, &rel_path, deleted);
|
|
758
760
|
pending.mark(&m.table_name, &rel_path);
|
|
759
761
|
continue;
|
|
760
762
|
}
|
|
@@ -832,22 +834,20 @@ impl DirSQL {
|
|
|
832
834
|
else {
|
|
833
835
|
return Vec::new();
|
|
834
836
|
};
|
|
835
|
-
let
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
}
|
|
843
|
-
}
|
|
837
|
+
let abs_paths: Vec<PathBuf> = match self.inner.batch_files.lock() {
|
|
838
|
+
Ok(files) => files
|
|
839
|
+
.get(table)
|
|
840
|
+
.map(|rel_paths| rel_paths.iter().map(|rel| group.anchor.join(rel)).collect())
|
|
841
|
+
.unwrap_or_default(),
|
|
842
|
+
Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
|
|
843
|
+
};
|
|
844
844
|
let raw_rows = match collect_table_rows(hook.as_ref(), &abs_paths) {
|
|
845
845
|
Ok(rows) => rows,
|
|
846
846
|
Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
|
|
847
847
|
};
|
|
848
848
|
let strict = *self.inner.strict_map.get(table).unwrap_or(&false);
|
|
849
849
|
|
|
850
|
-
let
|
|
850
|
+
let changes = {
|
|
851
851
|
let db = match self.inner.db.lock() {
|
|
852
852
|
Ok(g) => g,
|
|
853
853
|
Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
|
|
@@ -856,27 +856,41 @@ impl DirSQL {
|
|
|
856
856
|
Ok(rows) => rows,
|
|
857
857
|
Err(message) => return vec![error_event(Some(table), trigger, message)],
|
|
858
858
|
};
|
|
859
|
-
let old_rows = match db.get_rows_by_file(table, BATCH_OWNER) {
|
|
860
|
-
Ok(rows) => rows,
|
|
861
|
-
Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
|
|
862
|
-
};
|
|
863
859
|
let _tx = match db.conn().unchecked_transaction() {
|
|
864
860
|
Ok(tx) => tx,
|
|
865
861
|
Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
|
|
866
862
|
};
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
863
|
+
let changes = match db.reconcile_batch_rows(table, BATCH_OWNER, &new_rows) {
|
|
864
|
+
Ok(changes) => changes,
|
|
865
|
+
Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
|
|
866
|
+
};
|
|
870
867
|
if let Err(e) = _tx.commit() {
|
|
871
868
|
return vec![error_event(Some(table), trigger, e.to_string())];
|
|
872
869
|
}
|
|
873
|
-
|
|
870
|
+
changes
|
|
874
871
|
};
|
|
875
|
-
if let Ok(mut files) = self.inner.batch_files.lock() {
|
|
876
|
-
files.insert(table.to_string(), rel_paths);
|
|
877
|
-
}
|
|
878
872
|
|
|
879
|
-
differ::diff_unordered(table, &
|
|
873
|
+
differ::diff_unordered(table, &changes.removed, &changes.added, trigger)
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
/// Record in the table's file set whether `abs_path` is, now, one of the
|
|
877
|
+
/// files its per-table hook runs over. The set stays in walk order
|
|
878
|
+
/// (component-wise byte order), so the hook sees the same argument list a
|
|
879
|
+
/// walk of the tree would give it.
|
|
880
|
+
fn track_batch_file(&self, table: &str, abs_path: &Path, rel_path: &str, deleted: bool) {
|
|
881
|
+
let present = !deleted && self.inner.fs.is_file(abs_path).unwrap_or(false);
|
|
882
|
+
let Ok(mut batch_files) = self.inner.batch_files.lock() else {
|
|
883
|
+
return;
|
|
884
|
+
};
|
|
885
|
+
let files = batch_files.entry(table.to_string()).or_default();
|
|
886
|
+
let at = files.binary_search_by(|file| Path::new(file).cmp(Path::new(rel_path)));
|
|
887
|
+
match (present, at) {
|
|
888
|
+
(true, Err(at)) => files.insert(at, rel_path.to_string()),
|
|
889
|
+
(false, Ok(at)) => {
|
|
890
|
+
files.remove(at);
|
|
891
|
+
}
|
|
892
|
+
_ => {}
|
|
893
|
+
}
|
|
880
894
|
}
|
|
881
895
|
|
|
882
896
|
/// Delete the rows of every file recorded beneath `rel_dir`, in every
|
|
@@ -889,9 +903,10 @@ impl DirSQL {
|
|
|
889
903
|
) -> Vec<RowEvent> {
|
|
890
904
|
let prefix = format!("{rel_dir}/");
|
|
891
905
|
let in_group = |table: &str| group.tables.iter().any(|name| name == table);
|
|
892
|
-
if let Ok(batch_files) = self.inner.batch_files.lock() {
|
|
893
|
-
for (table, files) in batch_files.
|
|
906
|
+
if let Ok(mut batch_files) = self.inner.batch_files.lock() {
|
|
907
|
+
for (table, files) in batch_files.iter_mut() {
|
|
894
908
|
if in_group(table) && files.iter().any(|file| file.starts_with(&prefix)) {
|
|
909
|
+
files.retain(|file| !file.starts_with(&prefix));
|
|
895
910
|
pending.mark(table, rel_dir);
|
|
896
911
|
}
|
|
897
912
|
}
|
|
@@ -934,6 +949,7 @@ impl DirSQL {
|
|
|
934
949
|
for (path, table) in self.inner.fs.scan_subtree(base, dir, &group.matcher) {
|
|
935
950
|
let rel_path = scanner::to_slash(path.strip_prefix(base).unwrap_or(&path));
|
|
936
951
|
if self.is_per_table(&table) {
|
|
952
|
+
self.track_batch_file(&table, &path, &rel_path, false);
|
|
937
953
|
pending.mark(&table, &rel_path);
|
|
938
954
|
continue;
|
|
939
955
|
}
|
|
@@ -2344,12 +2360,6 @@ fn stream_table_rows(
|
|
|
2344
2360
|
})
|
|
2345
2361
|
}
|
|
2346
2362
|
|
|
2347
|
-
/// Replace a per-table hook's rows wholesale under [`BATCH_OWNER`].
|
|
2348
|
-
fn replace_table_rows(db: &Db, table: &str, rows: &ShapedRows) -> db::Result<()> {
|
|
2349
|
-
db.delete_rows_by_file(table, BATCH_OWNER)?;
|
|
2350
|
-
db.insert_rows(table, rows, BATCH_OWNER)
|
|
2351
|
-
}
|
|
2352
|
-
|
|
2353
2363
|
fn error_event(table: Option<&str>, rel_path: &str, error: String) -> RowEvent {
|
|
2354
2364
|
RowEvent::Error {
|
|
2355
2365
|
table: table.map(str::to_string),
|
|
@@ -5402,6 +5412,157 @@ mod internal_tests {
|
|
|
5402
5412
|
assert_eq!(row_names(&db), vec!["a.txt", "b.txt"]);
|
|
5403
5413
|
}
|
|
5404
5414
|
|
|
5415
|
+
#[test]
|
|
5416
|
+
fn apply_file_events_refreshes_a_per_table_hook_without_walking_the_tree() {
|
|
5417
|
+
let dir = TempDir::new().unwrap();
|
|
5418
|
+
let root = dir.path().to_path_buf();
|
|
5419
|
+
let a = root.join("a.txt");
|
|
5420
|
+
let b = root.join("b.txt");
|
|
5421
|
+
let fake = Arc::new(FakeFs::default().with_subtree(
|
|
5422
|
+
root.clone(),
|
|
5423
|
+
vec![(a.clone(), "items".into()), (b.clone(), "items".into())],
|
|
5424
|
+
));
|
|
5425
|
+
let (items, calls) = recording_per_table("items", "**/*.txt");
|
|
5426
|
+
let db = DirSQL::with_ignore_and_fs(&root, vec![items], Vec::<String>::new(), fake.clone())
|
|
5427
|
+
.unwrap();
|
|
5428
|
+
|
|
5429
|
+
db.apply_file_events(vec![
|
|
5430
|
+
FileEvent::Created(b.clone()),
|
|
5431
|
+
FileEvent::Created(a.clone()),
|
|
5432
|
+
]);
|
|
5433
|
+
db.apply_file_events(vec![FileEvent::Modified(a.clone())]);
|
|
5434
|
+
db.apply_file_events(vec![FileEvent::Deleted(a.clone())]);
|
|
5435
|
+
|
|
5436
|
+
assert_eq!(
|
|
5437
|
+
fake.subtree_walks(),
|
|
5438
|
+
Vec::<PathBuf>::new(),
|
|
5439
|
+
"a file event must not re-walk the tree"
|
|
5440
|
+
);
|
|
5441
|
+
assert_eq!(
|
|
5442
|
+
*calls.lock().unwrap(),
|
|
5443
|
+
vec![vec![a.clone(), b.clone()], vec![a, b.clone()], vec![b]]
|
|
5444
|
+
);
|
|
5445
|
+
}
|
|
5446
|
+
|
|
5447
|
+
#[test]
|
|
5448
|
+
fn apply_file_events_writes_only_the_rows_a_per_table_refresh_changed() {
|
|
5449
|
+
let dir = TempDir::new().unwrap();
|
|
5450
|
+
let root = dir.path().to_path_buf();
|
|
5451
|
+
let paths: Vec<PathBuf> = (0..20).map(|i| root.join(format!("f{i:02}.txt"))).collect();
|
|
5452
|
+
let found = paths.iter().map(|p| (p.clone(), "items".into())).collect();
|
|
5453
|
+
let fake = Arc::new(FakeFs::default().with_subtree(root.clone(), found));
|
|
5454
|
+
let runs = Arc::new(std::sync::atomic::AtomicUsize::new(0));
|
|
5455
|
+
let counted = Arc::clone(&runs);
|
|
5456
|
+
let items = Table::per_table(
|
|
5457
|
+
"items",
|
|
5458
|
+
"CREATE TABLE items (name TEXT)",
|
|
5459
|
+
"**/*.txt",
|
|
5460
|
+
move |paths: &[PathBuf]| {
|
|
5461
|
+
let run = counted.fetch_add(1, Ordering::SeqCst);
|
|
5462
|
+
Ok(paths
|
|
5463
|
+
.iter()
|
|
5464
|
+
.map(|p| {
|
|
5465
|
+
let name = p.file_name().unwrap().to_string_lossy().into_owned();
|
|
5466
|
+
name_json_row(&if name == "f00.txt" {
|
|
5467
|
+
format!("{name}#{run}")
|
|
5468
|
+
} else {
|
|
5469
|
+
name
|
|
5470
|
+
})
|
|
5471
|
+
})
|
|
5472
|
+
.collect())
|
|
5473
|
+
},
|
|
5474
|
+
);
|
|
5475
|
+
let db =
|
|
5476
|
+
DirSQL::with_ignore_and_fs(&root, vec![items], Vec::<String>::new(), fake).unwrap();
|
|
5477
|
+
db.apply_file_events(paths.iter().cloned().map(FileEvent::Created).collect());
|
|
5478
|
+
let written = || db.inner.db.lock().unwrap().conn().total_changes();
|
|
5479
|
+
let before = written();
|
|
5480
|
+
|
|
5481
|
+
let events = db.apply_file_events(vec![FileEvent::Modified(paths[0].clone())]);
|
|
5482
|
+
|
|
5483
|
+
assert_eq!(events.len(), 1, "{events:?}");
|
|
5484
|
+
let delta = written() - before;
|
|
5485
|
+
assert!(delta <= 6, "one changed row rewrote {delta} rows");
|
|
5486
|
+
assert_eq!(row_names(&db).len(), 20);
|
|
5487
|
+
}
|
|
5488
|
+
|
|
5489
|
+
fn walked_paths(root: &Path, glob: &str) -> Vec<PathBuf> {
|
|
5490
|
+
let matcher = TableMatcher::new(&[(glob, "items")], &[]).unwrap();
|
|
5491
|
+
scanner::scan_subtree(root, root, &matcher)
|
|
5492
|
+
.into_iter()
|
|
5493
|
+
.map(|(path, _)| path)
|
|
5494
|
+
.collect()
|
|
5495
|
+
}
|
|
5496
|
+
|
|
5497
|
+
#[test]
|
|
5498
|
+
fn a_per_table_hook_gets_the_argument_list_a_walk_of_the_tree_gives_it() {
|
|
5499
|
+
let dir = TempDir::new().unwrap();
|
|
5500
|
+
let root = dir.path().canonicalize().unwrap();
|
|
5501
|
+
let write = |rel: &str| {
|
|
5502
|
+
let path = root.join(rel);
|
|
5503
|
+
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
|
|
5504
|
+
std::fs::write(&path, "x").unwrap();
|
|
5505
|
+
path
|
|
5506
|
+
};
|
|
5507
|
+
let (items, calls) = recording_per_table("items", "**/*.txt");
|
|
5508
|
+
let db =
|
|
5509
|
+
DirSQL::with_ignore_and_fs(&root, vec![items], Vec::<String>::new(), Arc::new(RealFs))
|
|
5510
|
+
.unwrap();
|
|
5511
|
+
let last_args = || calls.lock().unwrap().last().cloned().unwrap();
|
|
5512
|
+
|
|
5513
|
+
let events: Vec<FileEvent> = [
|
|
5514
|
+
"z.txt",
|
|
5515
|
+
"a-b.txt",
|
|
5516
|
+
"a/c.txt",
|
|
5517
|
+
".hid.txt",
|
|
5518
|
+
"a/b/d.txt",
|
|
5519
|
+
"n.md",
|
|
5520
|
+
]
|
|
5521
|
+
.into_iter()
|
|
5522
|
+
.map(|rel| FileEvent::Created(write(rel)))
|
|
5523
|
+
.collect();
|
|
5524
|
+
db.apply_file_events(events);
|
|
5525
|
+
assert_eq!(last_args(), walked_paths(&root, "**/*.txt"));
|
|
5526
|
+
|
|
5527
|
+
write("a/c.txt");
|
|
5528
|
+
db.apply_file_events(vec![FileEvent::Modified(root.join("a/c.txt"))]);
|
|
5529
|
+
assert_eq!(last_args(), walked_paths(&root, "**/*.txt"));
|
|
5530
|
+
|
|
5531
|
+
write("m/one.txt");
|
|
5532
|
+
write("m/deep/two.txt");
|
|
5533
|
+
db.apply_file_events(vec![FileEvent::Created(root.join("m"))]);
|
|
5534
|
+
assert_eq!(last_args(), walked_paths(&root, "**/*.txt"));
|
|
5535
|
+
|
|
5536
|
+
std::fs::remove_file(root.join("a-b.txt")).unwrap();
|
|
5537
|
+
db.apply_file_events(vec![FileEvent::Deleted(root.join("a-b.txt"))]);
|
|
5538
|
+
assert_eq!(last_args(), walked_paths(&root, "**/*.txt"));
|
|
5539
|
+
|
|
5540
|
+
std::fs::remove_dir_all(root.join("m")).unwrap();
|
|
5541
|
+
db.apply_file_events(vec![FileEvent::Deleted(root.join("m"))]);
|
|
5542
|
+
assert_eq!(last_args(), walked_paths(&root, "**/*.txt"));
|
|
5543
|
+
}
|
|
5544
|
+
|
|
5545
|
+
#[test]
|
|
5546
|
+
fn a_vanished_file_is_dropped_from_a_per_table_hooks_arguments() {
|
|
5547
|
+
let dir = TempDir::new().unwrap();
|
|
5548
|
+
let root = dir.path().canonicalize().unwrap();
|
|
5549
|
+
let (items, calls) = recording_per_table("items", "*.txt");
|
|
5550
|
+
let db =
|
|
5551
|
+
DirSQL::with_ignore_and_fs(&root, vec![items], Vec::<String>::new(), Arc::new(RealFs))
|
|
5552
|
+
.unwrap();
|
|
5553
|
+
std::fs::write(root.join("a.txt"), "x").unwrap();
|
|
5554
|
+
db.apply_file_events(vec![FileEvent::Created(root.join("a.txt"))]);
|
|
5555
|
+
std::fs::remove_file(root.join("a.txt")).unwrap();
|
|
5556
|
+
|
|
5557
|
+
db.apply_file_events(vec![FileEvent::Modified(root.join("a.txt"))]);
|
|
5558
|
+
|
|
5559
|
+
assert_eq!(
|
|
5560
|
+
calls.lock().unwrap().last().unwrap(),
|
|
5561
|
+
&Vec::<PathBuf>::new()
|
|
5562
|
+
);
|
|
5563
|
+
assert_eq!(row_names(&db), Vec::<String>::new());
|
|
5564
|
+
}
|
|
5565
|
+
|
|
5405
5566
|
fn anchored_table(name: &str, glob: &str, anchor: &str) -> Table {
|
|
5406
5567
|
Table::new(
|
|
5407
5568
|
name,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|