dirsql 0.4.24__tar.gz → 0.4.26__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.24 → dirsql-0.4.26}/Cargo.lock +1 -1
- {dirsql-0.4.24 → dirsql-0.4.26}/PKG-INFO +1 -1
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/_dirsql.pyi +2 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/getting-started.md +1 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/columns-from-paths.md +1 -0
- {dirsql-0.4.24/packages/python → dirsql-0.4.26}/docs/howto/define-tables.md +1 -0
- {dirsql-0.4.24/packages/python → dirsql-0.4.26}/docs/howto/embed.md +3 -0
- {dirsql-0.4.24/packages/rust → dirsql-0.4.26}/docs/howto/extract-from-contents.md +2 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/parse-files-into-columns.md +1 -0
- {dirsql-0.4.24/packages/python → dirsql-0.4.26}/docs/howto/react-to-changes.md +1 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/skip-files.md +1 -0
- {dirsql-0.4.24/packages/rust → dirsql-0.4.26}/docs/howto/write-a-plugin.md +1 -0
- {dirsql-0.4.24/packages/rust → dirsql-0.4.26}/docs/index.md +3 -0
- {dirsql-0.4.24/packages/rust → dirsql-0.4.26}/docs/reference/config.md +16 -2
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/reference/sdk.md +11 -8
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/Cargo.toml +1 -1
- dirsql-0.4.26/packages/python/changelog.d/2026-08-20-declared-table-name.md +3 -0
- {dirsql-0.4.24/packages/rust → dirsql-0.4.26/packages/python}/docs/getting-started.md +1 -0
- {dirsql-0.4.24/packages/rust → dirsql-0.4.26/packages/python}/docs/howto/columns-from-paths.md +1 -0
- {dirsql-0.4.24 → dirsql-0.4.26/packages/python}/docs/howto/define-tables.md +1 -0
- {dirsql-0.4.24 → dirsql-0.4.26/packages/python}/docs/howto/embed.md +3 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/howto/extract-from-contents.md +2 -0
- {dirsql-0.4.24/packages/rust → dirsql-0.4.26/packages/python}/docs/howto/parse-files-into-columns.md +1 -0
- {dirsql-0.4.24/packages/rust → dirsql-0.4.26/packages/python}/docs/howto/react-to-changes.md +1 -0
- {dirsql-0.4.24/packages/rust → dirsql-0.4.26/packages/python}/docs/howto/skip-files.md +1 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/howto/write-a-plugin.md +1 -0
- {dirsql-0.4.24 → dirsql-0.4.26/packages/python}/docs/index.md +3 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/reference/config.md +16 -2
- {dirsql-0.4.24/packages/rust → dirsql-0.4.26/packages/python}/docs/reference/sdk.md +11 -8
- dirsql-0.4.26/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +7 -0
- dirsql-0.4.26/packages/python/migrations.d/2026-08-20-declared-table-name.md +52 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/src/lib.rs +8 -12
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +1 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/benches/db_bench.rs +20 -8
- {dirsql-0.4.24/packages/python → dirsql-0.4.26/packages/rust}/docs/getting-started.md +1 -0
- {dirsql-0.4.24/packages/python → dirsql-0.4.26/packages/rust}/docs/howto/columns-from-paths.md +1 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/howto/define-tables.md +1 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/howto/embed.md +3 -0
- {dirsql-0.4.24 → dirsql-0.4.26/packages/rust}/docs/howto/extract-from-contents.md +2 -0
- {dirsql-0.4.24/packages/python → dirsql-0.4.26/packages/rust}/docs/howto/parse-files-into-columns.md +1 -0
- {dirsql-0.4.24 → dirsql-0.4.26/packages/rust}/docs/howto/react-to-changes.md +1 -0
- {dirsql-0.4.24/packages/python → dirsql-0.4.26/packages/rust}/docs/howto/skip-files.md +1 -0
- {dirsql-0.4.24 → dirsql-0.4.26/packages/rust}/docs/howto/write-a-plugin.md +1 -0
- {dirsql-0.4.24/packages/python → dirsql-0.4.26/packages/rust}/docs/index.md +3 -0
- {dirsql-0.4.24 → dirsql-0.4.26/packages/rust}/docs/reference/config.md +16 -2
- {dirsql-0.4.24/packages/python → dirsql-0.4.26/packages/rust}/docs/reference/sdk.md +11 -8
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/cli/run.rs +1 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/config.rs +93 -32
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/db.rs +70 -351
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/default_config.toml +4 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/lib.rs +96 -27
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/persist.rs +10 -8
- {dirsql-0.4.24 → dirsql-0.4.26}/Cargo.toml +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/README.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/__init__.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/_async.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/discover_plugins/__init__.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/main.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/cli/resolve_config_extensions.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/py.typed +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/resolve_config_extensions.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/dirsql/resolve_extension.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/AGENTS.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/explanation.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/persist.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/query-json.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/package.json +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/plugins.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/reference/cli.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/reference/columns.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/reference/hooks.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/reference/http-api.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/CHANGELOG.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/MIGRATIONS.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/README.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/changelog.d/README.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/conftest.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/explanation.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/howto/persist.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/howto/query-json.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/package.json +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/plugins.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/reference/cli.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/reference/columns.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/reference/hooks.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/reference/http-api.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/migrations.d/README.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/testing-conventions.toml +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/integration/binding/__init__.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/integration/hermetic/__init__.py +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/CHANGELOG.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/Cargo.toml +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/MIGRATIONS.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/README.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/explanation.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/howto/persist.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/howto/query-json.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/plugins.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/reference/cli.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/reference/columns.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/reference/hooks.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/reference/http-api.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/cli/execute.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/command.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/functions.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/infer.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/parsed_cache.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/parsed_vtab.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/path_table.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/sql_literal.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/vtab.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.4.24 → dirsql-0.4.26}/pyproject.toml +0 -0
|
@@ -30,6 +30,7 @@ class ExtensionSpec(TypedDict):
|
|
|
30
30
|
class Table:
|
|
31
31
|
"""A table definition. Construct via keyword arguments only."""
|
|
32
32
|
|
|
33
|
+
name: str
|
|
33
34
|
ddl: str
|
|
34
35
|
glob: str
|
|
35
36
|
strict: bool
|
|
@@ -37,6 +38,7 @@ class Table:
|
|
|
37
38
|
def __init__(
|
|
38
39
|
self,
|
|
39
40
|
*,
|
|
41
|
+
name: str,
|
|
40
42
|
ddl: str,
|
|
41
43
|
glob: str,
|
|
42
44
|
on_file: Callable[[str], list[Row]],
|
|
@@ -60,6 +60,7 @@ async def main() -> None:
|
|
|
60
60
|
"./comments-root",
|
|
61
61
|
tables=[
|
|
62
62
|
Table(
|
|
63
|
+
name="comments",
|
|
63
64
|
ddl="CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
|
|
64
65
|
glob="comments/*/*.json",
|
|
65
66
|
on_file=on_file,
|
|
@@ -83,6 +84,7 @@ const db = new DirSQL({
|
|
|
83
84
|
root: "./comments-root",
|
|
84
85
|
tables: [
|
|
85
86
|
{
|
|
87
|
+
name: "comments",
|
|
86
88
|
ddl: "CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
|
|
87
89
|
glob: "comments/*/*.json",
|
|
88
90
|
onFile: (path) => [
|
|
@@ -129,6 +131,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
129
131
|
let db = DirSQL::builder()
|
|
130
132
|
.root("./comments-root")
|
|
131
133
|
.table(Table::new(
|
|
134
|
+
"comments",
|
|
132
135
|
"CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
|
|
133
136
|
"comments/*/*.json",
|
|
134
137
|
on_file,
|
|
@@ -18,6 +18,7 @@ stdout works. With [`jq`](https://jqlang.org/):
|
|
|
18
18
|
|
|
19
19
|
```toml
|
|
20
20
|
[[table]]
|
|
21
|
+
name = "books"
|
|
21
22
|
ddl = "CREATE TABLE books (title TEXT, author TEXT, year INTEGER)"
|
|
22
23
|
glob = "books/*.json"
|
|
23
24
|
on-file = "jq -c '[{title, author, year}]' {path}"
|
|
@@ -53,6 +54,7 @@ row per line, slurp it:
|
|
|
53
54
|
|
|
54
55
|
```toml
|
|
55
56
|
[[table]]
|
|
57
|
+
name = "events"
|
|
56
58
|
ddl = "CREATE TABLE events (event TEXT, user TEXT)"
|
|
57
59
|
glob = "logs/*.jsonl"
|
|
58
60
|
on-file = "jq -c -s '.' {path}"
|
|
@@ -22,6 +22,7 @@ Exclude the noise in `.dirsql.toml`:
|
|
|
22
22
|
ignore = ["notes/drafts/**", "**/*.tmp"]
|
|
23
23
|
|
|
24
24
|
[[table]]
|
|
25
|
+
name = "notes"
|
|
25
26
|
ddl = "CREATE TABLE notes (basename TEXT)"
|
|
26
27
|
glob = "notes/**/*"
|
|
27
28
|
on-file = '''sh -c 'printf "[{\"basename\":\"%s\"}]" "${1##*/}"' sh {path}'''
|
|
@@ -108,6 +108,7 @@ path = "sqlite_vec"
|
|
|
108
108
|
entrypoint = "sqlite3_vec_init"
|
|
109
109
|
|
|
110
110
|
[[table]]
|
|
111
|
+
name = "notes"
|
|
111
112
|
ddl = "CREATE TABLE notes (path TEXT, text TEXT, embedding TEXT)"
|
|
112
113
|
glob = "notes/*.md"
|
|
113
114
|
on-file = "uv run --with model2vec python embed.py {path} {root}"
|
|
@@ -34,6 +34,7 @@ db = DirSQL(
|
|
|
34
34
|
"./my-project",
|
|
35
35
|
tables=[
|
|
36
36
|
Table(
|
|
37
|
+
name="records",
|
|
37
38
|
ddl="CREATE TABLE records (name TEXT, size INTEGER, type TEXT)",
|
|
38
39
|
glob="data/*.json",
|
|
39
40
|
on_file=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
@@ -52,6 +53,7 @@ let db = DirSQL::new(
|
|
|
52
53
|
"./my-project",
|
|
53
54
|
vec![
|
|
54
55
|
Table::new(
|
|
56
|
+
"records",
|
|
55
57
|
"CREATE TABLE records (name TEXT, size INTEGER, type TEXT)",
|
|
56
58
|
"data/*.json",
|
|
57
59
|
|path| vec![serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap()],
|
|
@@ -70,6 +72,7 @@ const db = new DirSQL({
|
|
|
70
72
|
root: './my-project',
|
|
71
73
|
tables: [
|
|
72
74
|
new Table({
|
|
75
|
+
name: 'records',
|
|
73
76
|
ddl: 'CREATE TABLE records (name TEXT, size INTEGER, type TEXT)',
|
|
74
77
|
glob: 'data/*.json',
|
|
75
78
|
onFile: (path) => [JSON.parse(readFileSync(path, 'utf8'))],
|
|
@@ -166,7 +166,8 @@ what its required `on-file` command emits — dirsql injects nothing (see
|
|
|
166
166
|
|
|
167
167
|
| Key | Required | Description |
|
|
168
168
|
|---|---|---|
|
|
169
|
-
| `
|
|
169
|
+
| `name` | yes | The table's SQL name — the name you query it by. Declared, never derived from `ddl`: dirsql does not read the DDL text. The `ddl` must create a table by this name; if it doesn't, loading fails. |
|
|
170
|
+
| `ddl` | yes | A SQLite `CREATE TABLE` statement, run verbatim. Only the columns declared here are kept; keys the `on-file` command emits that are not declared are dropped. |
|
|
170
171
|
| `glob` | yes | Glob pattern matched against root-relative paths. Every table whose glob matches a file receives that file's rows — a file can populate multiple tables. A `{name}` segment is rewritten to `*` (it matches one path segment but captures nothing). |
|
|
171
172
|
| `on-file` | **yes** | A command run once per matched file; its stdout (a JSON array of row objects) becomes the file's rows. Must be non-empty. A `[[table]]` with no `on-file` is a load error (see [parse errors](#parse-errors)). See [Command hooks](./hooks.md#on-file). |
|
|
172
173
|
| `strict` | no (default `false`) | When `true`, rows whose keys do not exactly match the declared columns are rejected with an error: extra keys error, and every declared column must be supplied by the `on-file` output. When `false`, extra keys are dropped and missing columns become `NULL`. |
|
|
@@ -180,11 +181,13 @@ instead of declaring a table.
|
|
|
180
181
|
|
|
181
182
|
```toml
|
|
182
183
|
[[table]]
|
|
184
|
+
name = "comments"
|
|
183
185
|
ddl = "CREATE TABLE comments (path TEXT, author TEXT, body TEXT)"
|
|
184
186
|
glob = "_comments/*/*.jsonl"
|
|
185
187
|
on-file = "jq -c -s '.' {path}"
|
|
186
188
|
|
|
187
189
|
[[table]]
|
|
190
|
+
name = "papers"
|
|
188
191
|
ddl = "CREATE TABLE papers (paper_id TEXT, title TEXT)"
|
|
189
192
|
glob = "**/meta.json"
|
|
190
193
|
on-file = "uv run python extract_papers.py {path}"
|
|
@@ -241,7 +244,16 @@ SDKs raise/reject) when:
|
|
|
241
244
|
- The TOML is malformed.
|
|
242
245
|
- Any table contains an unknown key (top level, `[dirsql]`, `[[table]]`, or
|
|
243
246
|
`[[dirsql.extension]]`). The error names the offending key.
|
|
244
|
-
- A `[[table]]` entry omits `ddl` or `
|
|
247
|
+
- A `[[table]]` entry omits `name`, `ddl`, or `glob` (or `name` is
|
|
248
|
+
empty/whitespace).
|
|
249
|
+
- A `[[table]]` entry's `ddl` runs but creates no table by its `name`. The
|
|
250
|
+
error carries the entry's name and points at the fix:
|
|
251
|
+
|
|
252
|
+
> `table 'messages': its `ddl` ran but created no table called 'messages'. Set `name` to the table the `ddl` creates.`
|
|
253
|
+
|
|
254
|
+
dirsql asks SQLite's catalog rather than interpreting the DDL, so quoted
|
|
255
|
+
(`CREATE TABLE "messages"`), schema-qualified (`main.messages`) and
|
|
256
|
+
`IF NOT EXISTS` forms all match a plain `name = "messages"`.
|
|
245
257
|
- A `[[table]]` entry omits `on-file` (or it is empty/whitespace). The error
|
|
246
258
|
names the offending glob and points at the fix:
|
|
247
259
|
|
|
@@ -275,11 +287,13 @@ deterministic = true
|
|
|
275
287
|
timeout = "600s"
|
|
276
288
|
|
|
277
289
|
[[table]]
|
|
290
|
+
name = "comments"
|
|
278
291
|
ddl = "CREATE TABLE comments (author TEXT, body TEXT)"
|
|
279
292
|
glob = "_comments/*/*.jsonl"
|
|
280
293
|
on-file = "jq -c -s '.' {path}"
|
|
281
294
|
|
|
282
295
|
[[table]]
|
|
296
|
+
name = "documents"
|
|
283
297
|
ddl = "CREATE TABLE documents (title TEXT, summary TEXT)"
|
|
284
298
|
glob = "**/index.md"
|
|
285
299
|
on-file = "uv run python extract_doc.py {path}"
|
|
@@ -317,27 +317,30 @@ rather than waiting — an intentional, language-idiomatic difference.
|
|
|
317
317
|
::: code-group
|
|
318
318
|
|
|
319
319
|
```python [Python]
|
|
320
|
-
Table(*, ddl: str, glob: str, on_file: Callable[[str], list[dict]], strict: bool = False)
|
|
320
|
+
Table(*, name: str, ddl: str, glob: str, on_file: Callable[[str], list[dict]], strict: bool = False)
|
|
321
321
|
```
|
|
322
322
|
|
|
323
323
|
```typescript [TypeScript]
|
|
324
|
-
new Table({ ddl, glob, onFile, strict? })
|
|
324
|
+
new Table({ name, ddl, glob, onFile, strict? })
|
|
325
325
|
// or a plain object — TableDef and Table are interchangeable:
|
|
326
|
-
{ ddl: string, glob: string, onFile: (path: string) => Record<string, unknown>[], strict?: boolean }
|
|
326
|
+
{ name: string, ddl: string, glob: string, onFile: (path: string) => Record<string, unknown>[], strict?: boolean }
|
|
327
327
|
```
|
|
328
328
|
|
|
329
329
|
```rust [Rust]
|
|
330
|
-
Table::new(ddl, glob, on_file) // on_file: Fn(&str) -> Vec<Row>, infallible
|
|
331
|
-
Table::try_new(ddl, glob, on_file) // on_file: Fn(&str) -> Result<Vec<Row>, _>
|
|
332
|
-
Table::strict(ddl, glob, on_file) // Table::new with strict = true
|
|
330
|
+
Table::new(name, ddl, glob, on_file) // on_file: Fn(&str) -> Vec<Row>, infallible
|
|
331
|
+
Table::try_new(name, ddl, glob, on_file) // on_file: Fn(&str) -> Result<Vec<Row>, _>
|
|
332
|
+
Table::strict(name, ddl, glob, on_file) // Table::new with strict = true
|
|
333
333
|
```
|
|
334
334
|
|
|
335
335
|
:::
|
|
336
336
|
|
|
337
337
|
Maps files to table rows.
|
|
338
338
|
|
|
339
|
-
- `
|
|
340
|
-
|
|
339
|
+
- `name` — The table's SQL name, declared rather than derived from `ddl`.
|
|
340
|
+
Must be unique across all tables. Building fails if the `ddl` creates no
|
|
341
|
+
table by this name (checked against SQLite's catalog, before any file is
|
|
342
|
+
indexed).
|
|
343
|
+
- `ddl` — A SQLite `CREATE TABLE` statement, run verbatim.
|
|
341
344
|
- `glob` — Glob pattern matched against root-relative paths. Every table whose
|
|
342
345
|
glob matches a file receives that file's rows — a file can populate multiple
|
|
343
346
|
tables. A `{name}` segment is rewritten to `*` (it matches one path segment
|
|
@@ -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.26"
|
|
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,3 @@
|
|
|
1
|
+
**Changed**
|
|
2
|
+
|
|
3
|
+
- **A table's name is now declared, not derived from `ddl`.** `Table` takes a required keyword-only `name` (`Table(name=..., ddl=..., glob=..., on_file=...)`), and a `[[table]]` entry in a `.dirsql.toml` requires a `name` key. The core no longer parses the DDL text to find the name; a `name` its `ddl` does not create fails at load with an error naming the entry. `Table.name` is now the declared `str` rather than an `Optional[str]` parsed from the DDL. (#962)
|
|
@@ -60,6 +60,7 @@ async def main() -> None:
|
|
|
60
60
|
"./comments-root",
|
|
61
61
|
tables=[
|
|
62
62
|
Table(
|
|
63
|
+
name="comments",
|
|
63
64
|
ddl="CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
|
|
64
65
|
glob="comments/*/*.json",
|
|
65
66
|
on_file=on_file,
|
|
@@ -83,6 +84,7 @@ const db = new DirSQL({
|
|
|
83
84
|
root: "./comments-root",
|
|
84
85
|
tables: [
|
|
85
86
|
{
|
|
87
|
+
name: "comments",
|
|
86
88
|
ddl: "CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
|
|
87
89
|
glob: "comments/*/*.json",
|
|
88
90
|
onFile: (path) => [
|
|
@@ -129,6 +131,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
129
131
|
let db = DirSQL::builder()
|
|
130
132
|
.root("./comments-root")
|
|
131
133
|
.table(Table::new(
|
|
134
|
+
"comments",
|
|
132
135
|
"CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
|
|
133
136
|
"comments/*/*.json",
|
|
134
137
|
on_file,
|
|
@@ -18,6 +18,7 @@ stdout works. With [`jq`](https://jqlang.org/):
|
|
|
18
18
|
|
|
19
19
|
```toml
|
|
20
20
|
[[table]]
|
|
21
|
+
name = "books"
|
|
21
22
|
ddl = "CREATE TABLE books (title TEXT, author TEXT, year INTEGER)"
|
|
22
23
|
glob = "books/*.json"
|
|
23
24
|
on-file = "jq -c '[{title, author, year}]' {path}"
|
|
@@ -53,6 +54,7 @@ row per line, slurp it:
|
|
|
53
54
|
|
|
54
55
|
```toml
|
|
55
56
|
[[table]]
|
|
57
|
+
name = "events"
|
|
56
58
|
ddl = "CREATE TABLE events (event TEXT, user TEXT)"
|
|
57
59
|
glob = "logs/*.jsonl"
|
|
58
60
|
on-file = "jq -c -s '.' {path}"
|
|
@@ -22,6 +22,7 @@ Exclude the noise in `.dirsql.toml`:
|
|
|
22
22
|
ignore = ["notes/drafts/**", "**/*.tmp"]
|
|
23
23
|
|
|
24
24
|
[[table]]
|
|
25
|
+
name = "notes"
|
|
25
26
|
ddl = "CREATE TABLE notes (basename TEXT)"
|
|
26
27
|
glob = "notes/**/*"
|
|
27
28
|
on-file = '''sh -c 'printf "[{\"basename\":\"%s\"}]" "${1##*/}"' sh {path}'''
|
|
@@ -108,6 +108,7 @@ path = "sqlite_vec"
|
|
|
108
108
|
entrypoint = "sqlite3_vec_init"
|
|
109
109
|
|
|
110
110
|
[[table]]
|
|
111
|
+
name = "notes"
|
|
111
112
|
ddl = "CREATE TABLE notes (path TEXT, text TEXT, embedding TEXT)"
|
|
112
113
|
glob = "notes/*.md"
|
|
113
114
|
on-file = "uv run --with model2vec python embed.py {path} {root}"
|
|
@@ -34,6 +34,7 @@ db = DirSQL(
|
|
|
34
34
|
"./my-project",
|
|
35
35
|
tables=[
|
|
36
36
|
Table(
|
|
37
|
+
name="records",
|
|
37
38
|
ddl="CREATE TABLE records (name TEXT, size INTEGER, type TEXT)",
|
|
38
39
|
glob="data/*.json",
|
|
39
40
|
on_file=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
@@ -52,6 +53,7 @@ let db = DirSQL::new(
|
|
|
52
53
|
"./my-project",
|
|
53
54
|
vec![
|
|
54
55
|
Table::new(
|
|
56
|
+
"records",
|
|
55
57
|
"CREATE TABLE records (name TEXT, size INTEGER, type TEXT)",
|
|
56
58
|
"data/*.json",
|
|
57
59
|
|path| vec![serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap()],
|
|
@@ -70,6 +72,7 @@ const db = new DirSQL({
|
|
|
70
72
|
root: './my-project',
|
|
71
73
|
tables: [
|
|
72
74
|
new Table({
|
|
75
|
+
name: 'records',
|
|
73
76
|
ddl: 'CREATE TABLE records (name TEXT, size INTEGER, type TEXT)',
|
|
74
77
|
glob: 'data/*.json',
|
|
75
78
|
onFile: (path) => [JSON.parse(readFileSync(path, 'utf8'))],
|
|
@@ -166,7 +166,8 @@ what its required `on-file` command emits — dirsql injects nothing (see
|
|
|
166
166
|
|
|
167
167
|
| Key | Required | Description |
|
|
168
168
|
|---|---|---|
|
|
169
|
-
| `
|
|
169
|
+
| `name` | yes | The table's SQL name — the name you query it by. Declared, never derived from `ddl`: dirsql does not read the DDL text. The `ddl` must create a table by this name; if it doesn't, loading fails. |
|
|
170
|
+
| `ddl` | yes | A SQLite `CREATE TABLE` statement, run verbatim. Only the columns declared here are kept; keys the `on-file` command emits that are not declared are dropped. |
|
|
170
171
|
| `glob` | yes | Glob pattern matched against root-relative paths. Every table whose glob matches a file receives that file's rows — a file can populate multiple tables. A `{name}` segment is rewritten to `*` (it matches one path segment but captures nothing). |
|
|
171
172
|
| `on-file` | **yes** | A command run once per matched file; its stdout (a JSON array of row objects) becomes the file's rows. Must be non-empty. A `[[table]]` with no `on-file` is a load error (see [parse errors](#parse-errors)). See [Command hooks](./hooks.md#on-file). |
|
|
172
173
|
| `strict` | no (default `false`) | When `true`, rows whose keys do not exactly match the declared columns are rejected with an error: extra keys error, and every declared column must be supplied by the `on-file` output. When `false`, extra keys are dropped and missing columns become `NULL`. |
|
|
@@ -180,11 +181,13 @@ instead of declaring a table.
|
|
|
180
181
|
|
|
181
182
|
```toml
|
|
182
183
|
[[table]]
|
|
184
|
+
name = "comments"
|
|
183
185
|
ddl = "CREATE TABLE comments (path TEXT, author TEXT, body TEXT)"
|
|
184
186
|
glob = "_comments/*/*.jsonl"
|
|
185
187
|
on-file = "jq -c -s '.' {path}"
|
|
186
188
|
|
|
187
189
|
[[table]]
|
|
190
|
+
name = "papers"
|
|
188
191
|
ddl = "CREATE TABLE papers (paper_id TEXT, title TEXT)"
|
|
189
192
|
glob = "**/meta.json"
|
|
190
193
|
on-file = "uv run python extract_papers.py {path}"
|
|
@@ -241,7 +244,16 @@ SDKs raise/reject) when:
|
|
|
241
244
|
- The TOML is malformed.
|
|
242
245
|
- Any table contains an unknown key (top level, `[dirsql]`, `[[table]]`, or
|
|
243
246
|
`[[dirsql.extension]]`). The error names the offending key.
|
|
244
|
-
- A `[[table]]` entry omits `ddl` or `
|
|
247
|
+
- A `[[table]]` entry omits `name`, `ddl`, or `glob` (or `name` is
|
|
248
|
+
empty/whitespace).
|
|
249
|
+
- A `[[table]]` entry's `ddl` runs but creates no table by its `name`. The
|
|
250
|
+
error carries the entry's name and points at the fix:
|
|
251
|
+
|
|
252
|
+
> `table 'messages': its `ddl` ran but created no table called 'messages'. Set `name` to the table the `ddl` creates.`
|
|
253
|
+
|
|
254
|
+
dirsql asks SQLite's catalog rather than interpreting the DDL, so quoted
|
|
255
|
+
(`CREATE TABLE "messages"`), schema-qualified (`main.messages`) and
|
|
256
|
+
`IF NOT EXISTS` forms all match a plain `name = "messages"`.
|
|
245
257
|
- A `[[table]]` entry omits `on-file` (or it is empty/whitespace). The error
|
|
246
258
|
names the offending glob and points at the fix:
|
|
247
259
|
|
|
@@ -275,11 +287,13 @@ deterministic = true
|
|
|
275
287
|
timeout = "600s"
|
|
276
288
|
|
|
277
289
|
[[table]]
|
|
290
|
+
name = "comments"
|
|
278
291
|
ddl = "CREATE TABLE comments (author TEXT, body TEXT)"
|
|
279
292
|
glob = "_comments/*/*.jsonl"
|
|
280
293
|
on-file = "jq -c -s '.' {path}"
|
|
281
294
|
|
|
282
295
|
[[table]]
|
|
296
|
+
name = "documents"
|
|
283
297
|
ddl = "CREATE TABLE documents (title TEXT, summary TEXT)"
|
|
284
298
|
glob = "**/index.md"
|
|
285
299
|
on-file = "uv run python extract_doc.py {path}"
|
|
@@ -317,27 +317,30 @@ rather than waiting — an intentional, language-idiomatic difference.
|
|
|
317
317
|
::: code-group
|
|
318
318
|
|
|
319
319
|
```python [Python]
|
|
320
|
-
Table(*, ddl: str, glob: str, on_file: Callable[[str], list[dict]], strict: bool = False)
|
|
320
|
+
Table(*, name: str, ddl: str, glob: str, on_file: Callable[[str], list[dict]], strict: bool = False)
|
|
321
321
|
```
|
|
322
322
|
|
|
323
323
|
```typescript [TypeScript]
|
|
324
|
-
new Table({ ddl, glob, onFile, strict? })
|
|
324
|
+
new Table({ name, ddl, glob, onFile, strict? })
|
|
325
325
|
// or a plain object — TableDef and Table are interchangeable:
|
|
326
|
-
{ ddl: string, glob: string, onFile: (path: string) => Record<string, unknown>[], strict?: boolean }
|
|
326
|
+
{ name: string, ddl: string, glob: string, onFile: (path: string) => Record<string, unknown>[], strict?: boolean }
|
|
327
327
|
```
|
|
328
328
|
|
|
329
329
|
```rust [Rust]
|
|
330
|
-
Table::new(ddl, glob, on_file) // on_file: Fn(&str) -> Vec<Row>, infallible
|
|
331
|
-
Table::try_new(ddl, glob, on_file) // on_file: Fn(&str) -> Result<Vec<Row>, _>
|
|
332
|
-
Table::strict(ddl, glob, on_file) // Table::new with strict = true
|
|
330
|
+
Table::new(name, ddl, glob, on_file) // on_file: Fn(&str) -> Vec<Row>, infallible
|
|
331
|
+
Table::try_new(name, ddl, glob, on_file) // on_file: Fn(&str) -> Result<Vec<Row>, _>
|
|
332
|
+
Table::strict(name, ddl, glob, on_file) // Table::new with strict = true
|
|
333
333
|
```
|
|
334
334
|
|
|
335
335
|
:::
|
|
336
336
|
|
|
337
337
|
Maps files to table rows.
|
|
338
338
|
|
|
339
|
-
- `
|
|
340
|
-
|
|
339
|
+
- `name` — The table's SQL name, declared rather than derived from `ddl`.
|
|
340
|
+
Must be unique across all tables. Building fails if the `ddl` creates no
|
|
341
|
+
table by this name (checked against SQLite's catalog, before any file is
|
|
342
|
+
indexed).
|
|
343
|
+
- `ddl` — A SQLite `CREATE TABLE` statement, run verbatim.
|
|
341
344
|
- `glob` — Glob pattern matched against root-relative paths. Every table whose
|
|
342
345
|
glob matches a file receives that file's rows — a file can populate multiple
|
|
343
346
|
tables. A `{name}` segment is rewritten to `*` (it matches one path segment
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
### `Table` and `[[table]]` require an explicit `name` (#962)
|
|
2
|
+
|
|
3
|
+
#### Summary
|
|
4
|
+
|
|
5
|
+
`Table` previously derived its SQL name by parsing the `CREATE TABLE` head of
|
|
6
|
+
`ddl`, exposing the result as an `Optional[str]` attribute. The name is now
|
|
7
|
+
**declared**: `Table` takes a required keyword-only `name`, and a `[[table]]`
|
|
8
|
+
entry in a `.dirsql.toml` requires a `name` key. Whether the `ddl` creates a
|
|
9
|
+
table by that name is checked against SQLite's catalog at load time.
|
|
10
|
+
|
|
11
|
+
#### Required changes
|
|
12
|
+
|
|
13
|
+
| Before | After | Fix |
|
|
14
|
+
| ------ | ----- | --- |
|
|
15
|
+
| `Table(ddl=..., glob=..., on_file=...)` | `TypeError: Table.__new__() missing 1 required keyword argument: 'name'` | Pass `name="<table>"`, matching the table the `ddl` creates. |
|
|
16
|
+
| `[[table]]` with `ddl` + `glob` + `on-file` | `await db.ready()` raises: `Missing required field 'name' in [[table]] entry` | Add `name = "<table>"` to the entry. |
|
|
17
|
+
| `table.name` may be `None` | `table.name` is the declared `str` | Drop any `if table.name is None` handling. |
|
|
18
|
+
|
|
19
|
+
#### Deprecations removed
|
|
20
|
+
|
|
21
|
+
_None._
|
|
22
|
+
|
|
23
|
+
#### Behavior changes without code changes
|
|
24
|
+
|
|
25
|
+
- A `[[table]]` whose `ddl` creates a table under a different name than its
|
|
26
|
+
`name` now raises at `ready()` with an error naming the entry
|
|
27
|
+
(`table 'messages': …`), before any file is ingested.
|
|
28
|
+
- Quoted (`CREATE TABLE "messages"`), schema-qualified and `IF NOT EXISTS` DDL
|
|
29
|
+
keep working unchanged: SQLite records the bare identifier, so a plain
|
|
30
|
+
`name="messages"` matches.
|
|
31
|
+
|
|
32
|
+
#### Verification
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
import asyncio, json
|
|
36
|
+
from dirsql import DirSQL, Table
|
|
37
|
+
|
|
38
|
+
db = DirSQL(
|
|
39
|
+
"./data-root",
|
|
40
|
+
tables=[
|
|
41
|
+
Table(
|
|
42
|
+
name="records",
|
|
43
|
+
ddl="CREATE TABLE records (id TEXT)",
|
|
44
|
+
glob="data/*.json",
|
|
45
|
+
on_file=lambda path: json.load(open(path, encoding="utf-8")),
|
|
46
|
+
)
|
|
47
|
+
],
|
|
48
|
+
)
|
|
49
|
+
asyncio.run(db.ready())
|
|
50
|
+
# -> builds; `SELECT id FROM records` returns the file's rows.
|
|
51
|
+
# Omitting `name=` raises TypeError; a `name` the ddl never creates raises at ready().
|
|
52
|
+
```
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
#[cfg(feature = "extension-module")]
|
|
14
14
|
mod python {
|
|
15
|
-
use ::dirsql::{DirSQL, Extension, Row, RowEvent, Table, Value
|
|
15
|
+
use ::dirsql::{DirSQL, Extension, Row, RowEvent, Table, Value};
|
|
16
16
|
use pyo3::exceptions::{PyOverflowError, PyRuntimeError};
|
|
17
17
|
use pyo3::prelude::*;
|
|
18
18
|
use pyo3::types::{PyBool, PyByteArray, PyBytes, PyDict, PyInt, PyList};
|
|
@@ -24,6 +24,9 @@ mod python {
|
|
|
24
24
|
/// callable for `on_file`.
|
|
25
25
|
#[pyclass(name = "Table", frozen)]
|
|
26
26
|
struct PyTable {
|
|
27
|
+
/// The table's SQL name, declared rather than derived from `ddl`.
|
|
28
|
+
#[pyo3(get)]
|
|
29
|
+
name: String,
|
|
27
30
|
#[pyo3(get)]
|
|
28
31
|
ddl: String,
|
|
29
32
|
#[pyo3(get)]
|
|
@@ -32,27 +35,19 @@ mod python {
|
|
|
32
35
|
on_file: Py<PyAny>,
|
|
33
36
|
#[pyo3(get)]
|
|
34
37
|
strict: bool,
|
|
35
|
-
/// Parsed table name (from `ddl`) via `dirsql::db::parse_table_name`,
|
|
36
|
-
/// or `None` if the DDL doesn't match `CREATE TABLE <name> (...)`.
|
|
37
|
-
/// `None` rather than a construction error so `DirSQL.ready()` keeps
|
|
38
|
-
/// surfacing malformed DDLs as the loud failure path (the core's
|
|
39
|
-
/// `DirSqlError::Ddl`).
|
|
40
|
-
#[pyo3(get)]
|
|
41
|
-
name: Option<String>,
|
|
42
38
|
}
|
|
43
39
|
|
|
44
40
|
#[pymethods]
|
|
45
41
|
impl PyTable {
|
|
46
42
|
#[new]
|
|
47
|
-
#[pyo3(signature = (*, ddl, glob, on_file, strict=false))]
|
|
48
|
-
fn new(ddl: String, glob: String, on_file: Py<PyAny>, strict: bool) -> Self {
|
|
49
|
-
let name = parse_table_name(&ddl);
|
|
43
|
+
#[pyo3(signature = (*, name, ddl, glob, on_file, strict=false))]
|
|
44
|
+
fn new(name: String, ddl: String, glob: String, on_file: Py<PyAny>, strict: bool) -> Self {
|
|
50
45
|
PyTable {
|
|
46
|
+
name,
|
|
51
47
|
ddl,
|
|
52
48
|
glob,
|
|
53
49
|
on_file,
|
|
54
50
|
strict,
|
|
55
|
-
name,
|
|
56
51
|
}
|
|
57
52
|
}
|
|
58
53
|
}
|
|
@@ -235,6 +230,7 @@ mod python {
|
|
|
235
230
|
fn build_table(py: Python<'_>, t: &PyTable) -> Table {
|
|
236
231
|
let on_file_ref = t.on_file.clone_ref(py);
|
|
237
232
|
let mut table = Table::try_new(
|
|
233
|
+
t.name.clone(),
|
|
238
234
|
t.ddl.clone(),
|
|
239
235
|
t.glob.clone(),
|
|
240
236
|
make_on_file_closure(on_file_ref),
|
{dirsql-0.4.24 → dirsql-0.4.26}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml
RENAMED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# injected by the launcher as an ordinary `-c` flag. Adds one table so an
|
|
4
4
|
# installed plugin is observable ("installed = active") with zero config edits.
|
|
5
5
|
[[table]]
|
|
6
|
+
name = "notes"
|
|
6
7
|
ddl = "CREATE TABLE notes (path TEXT, basename TEXT)"
|
|
7
8
|
glob = "*.md"
|
|
8
9
|
on-file = '''sh -c 'rel=${1#"$2"/}; base=${1##*/}; printf "[{\"path\":\"%s\",\"basename\":\"%s\"}]" "$rel" "$base"' sh {path} {root}'''
|