dirsql 0.3.126__tar.gz → 0.4.0__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.3.126 → dirsql-0.4.0}/Cargo.lock +1 -1
- {dirsql-0.3.126 → dirsql-0.4.0}/PKG-INFO +1 -1
- {dirsql-0.3.126 → dirsql-0.4.0}/docs/.vitepress/config.ts +12 -1
- {dirsql-0.3.126 → dirsql-0.4.0}/docs/AGENTS.md +2 -1
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0}/docs/getting-started.md +47 -30
- dirsql-0.4.0/docs/howto/columns-from-paths.md +77 -0
- dirsql-0.4.0/docs/howto/define-tables.md +76 -0
- {dirsql-0.3.126/packages/python → dirsql-0.4.0}/docs/howto/embed.md +20 -8
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0}/docs/howto/extract-from-contents.md +7 -8
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0}/docs/howto/parse-files-into-columns.md +3 -4
- {dirsql-0.3.126/packages/python → dirsql-0.4.0}/docs/howto/react-to-changes.md +7 -4
- {dirsql-0.3.126 → dirsql-0.4.0}/docs/howto/search-by-meaning.md +9 -5
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0}/docs/howto/skip-files.md +5 -4
- {dirsql-0.3.126 → dirsql-0.4.0}/docs/howto/write-a-plugin.md +10 -5
- dirsql-0.4.0/docs/reference/columns.md +70 -0
- {dirsql-0.3.126/packages/python → dirsql-0.4.0}/docs/reference/config.md +33 -25
- {dirsql-0.3.126/packages/python → dirsql-0.4.0}/docs/reference/hooks.md +4 -4
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0}/docs/reference/sdk.md +9 -9
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/Cargo.toml +1 -1
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/docs/.vitepress/config.ts +12 -1
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/docs/AGENTS.md +2 -1
- {dirsql-0.3.126 → dirsql-0.4.0/packages/python}/docs/getting-started.md +47 -30
- dirsql-0.4.0/packages/python/docs/howto/columns-from-paths.md +77 -0
- dirsql-0.4.0/packages/python/docs/howto/define-tables.md +76 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/python}/docs/howto/embed.md +20 -8
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/docs/howto/extract-from-contents.md +7 -8
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/docs/howto/parse-files-into-columns.md +3 -4
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0/packages/python}/docs/howto/react-to-changes.md +7 -4
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0/packages/python}/docs/howto/search-by-meaning.md +9 -5
- {dirsql-0.3.126 → dirsql-0.4.0/packages/python}/docs/howto/skip-files.md +5 -4
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0/packages/python}/docs/howto/write-a-plugin.md +10 -5
- dirsql-0.4.0/packages/python/docs/reference/columns.md +70 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/python}/docs/reference/config.md +33 -25
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0/packages/python}/docs/reference/hooks.md +4 -4
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/docs/reference/sdk.md +9 -9
- dirsql-0.4.0/packages/python/e2e-attestations/chore-681-ruff-016.json +7 -0
- {dirsql-0.3.126/packages/python → dirsql-0.4.0/packages/rust}/docs/getting-started.md +47 -30
- dirsql-0.4.0/packages/rust/docs/howto/columns-from-paths.md +77 -0
- dirsql-0.4.0/packages/rust/docs/howto/define-tables.md +76 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/docs/howto/embed.md +20 -8
- {dirsql-0.3.126 → dirsql-0.4.0/packages/rust}/docs/howto/extract-from-contents.md +7 -8
- {dirsql-0.3.126 → dirsql-0.4.0/packages/rust}/docs/howto/parse-files-into-columns.md +3 -4
- {dirsql-0.3.126 → dirsql-0.4.0/packages/rust}/docs/howto/react-to-changes.md +7 -4
- {dirsql-0.3.126/packages/python → dirsql-0.4.0/packages/rust}/docs/howto/search-by-meaning.md +9 -5
- {dirsql-0.3.126/packages/python → dirsql-0.4.0/packages/rust}/docs/howto/skip-files.md +5 -4
- {dirsql-0.3.126/packages/python → dirsql-0.4.0/packages/rust}/docs/howto/write-a-plugin.md +10 -5
- dirsql-0.4.0/packages/rust/docs/reference/columns.md +70 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/docs/reference/config.md +33 -25
- {dirsql-0.3.126 → dirsql-0.4.0/packages/rust}/docs/reference/hooks.md +4 -4
- {dirsql-0.3.126 → dirsql-0.4.0/packages/rust}/docs/reference/sdk.md +9 -9
- {dirsql-0.3.126 → dirsql-0.4.0}/pyproject.toml +43 -1
- dirsql-0.3.126/docs/howto/columns-from-paths.md +0 -60
- dirsql-0.3.126/docs/howto/define-tables.md +0 -58
- dirsql-0.3.126/docs/reference/columns.md +0 -80
- dirsql-0.3.126/packages/python/docs/howto/columns-from-paths.md +0 -60
- dirsql-0.3.126/packages/python/docs/howto/define-tables.md +0 -58
- dirsql-0.3.126/packages/python/docs/reference/columns.md +0 -80
- dirsql-0.3.126/packages/python/e2e-attestations/feat-634-slice4-hookless-error.json +0 -7
- dirsql-0.3.126/packages/rust/docs/howto/columns-from-paths.md +0 -60
- dirsql-0.3.126/packages/rust/docs/howto/define-tables.md +0 -58
- dirsql-0.3.126/packages/rust/docs/reference/columns.md +0 -80
- {dirsql-0.3.126 → dirsql-0.4.0}/Cargo.toml +0 -0
- {dirsql-0.3.126/packages/python → dirsql-0.4.0}/README.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/__init__.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/_async.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.3.126/packages/python/tests/integration/binding → dirsql-0.4.0/dirsql/cli}/__init__.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/cli/binary_path.py +0 -0
- {dirsql-0.3.126/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture → dirsql-0.4.0/dirsql/cli/discover_plugins}/__init__.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/cli/is_windows.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/cli/main.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/cli/resolve_config_extensions.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/py.typed +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/resolve_config_extensions.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/dirsql/resolve_extension.py +0 -0
- {dirsql-0.3.126/packages/python → dirsql-0.4.0}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.126/packages/python → dirsql-0.4.0}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.126/packages/python → dirsql-0.4.0}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0}/docs/explanation.md +0 -0
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0}/docs/howto/load-extension.md +0 -0
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0}/docs/howto/persist.md +0 -0
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0}/docs/howto/query-without-config.md +0 -0
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0}/docs/index.md +0 -0
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0}/docs/migrations.md +0 -0
- {dirsql-0.3.126/packages/python → dirsql-0.4.0}/docs/package.json +0 -0
- {dirsql-0.3.126/packages/python → dirsql-0.4.0}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.126/packages/python → dirsql-0.4.0}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0}/docs/reference/cli.md +0 -0
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0}/docs/reference/http-api.md +0 -0
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0}/docs/reference/path-tables.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/CHANGELOG.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/MIGRATIONS.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/python}/README.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0/packages/python}/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0/packages/python}/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/changelog.d/README.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/conftest.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/python}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/python}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/python}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/docs/explanation.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/docs/howto/load-extension.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/docs/howto/persist.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/docs/howto/query-without-config.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/docs/index.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/docs/migrations.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/python}/docs/package.json +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/python}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/python}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/docs/reference/cli.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/docs/reference/http-api.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/docs/reference/path-tables.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0/packages/python}/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.3.126/packages/rust → dirsql-0.4.0/packages/python}/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/migrations.d/README.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/src/lib.rs +0 -0
- {dirsql-0.3.126/packages/python/tests/integration/hermetic → dirsql-0.4.0/packages/python/tests}/__init__.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.3.126/dirsql/cli/discover_plugins → dirsql-0.4.0/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture}/__init__.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.3.126/dirsql/cli → dirsql-0.4.0/packages/python/tests/integration/binding}/__init__.py +0 -0
- {dirsql-0.3.126/packages/python/tests → dirsql-0.4.0/packages/python/tests/integration/hermetic}/__init__.py +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/CHANGELOG.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/Cargo.toml +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/MIGRATIONS.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/README.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-13-batch-ingest-transaction.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-13-chained-pre-post-query-hooks.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-13-fan-out-file-table-matching.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-13-persist-wal.md +0 -0
- {dirsql-0.3.126/packages/python → dirsql-0.4.0/packages/rust}/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-13-repeatable-builder-config.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-13-repeatable-cli-config.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-13-subcommand-local-config-flags.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-19-path-table-query-fallback.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-19-path-table-vtab.md +0 -0
- {dirsql-0.3.126/packages/python → dirsql-0.4.0/packages/rust}/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-20-path-table-glob-semantics.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-20-schema-inference.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-21-on-file-flag.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-23-init-escalation-example.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-23-query-default-cli.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/changelog.d/README.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/rust}/docs/explanation.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/rust}/docs/howto/load-extension.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/rust}/docs/howto/persist.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/rust}/docs/howto/query-without-config.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/rust}/docs/index.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/rust}/docs/migrations.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/rust}/docs/reference/cli.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/rust}/docs/reference/http-api.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0/packages/rust}/docs/reference/path-tables.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/migrations.d/2026-07-13-fan-out-file-table-matching.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/migrations.d/2026-07-13-persist-wal.md +0 -0
- {dirsql-0.3.126/packages/python → dirsql-0.4.0/packages/rust}/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/migrations.d/2026-07-13-subcommand-local-config-flags.md +0 -0
- {dirsql-0.3.126/packages/python → dirsql-0.4.0/packages/rust}/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/migrations.d/2026-07-20-path-table-glob-semantics.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/migrations.d/2026-07-23-init-escalation-example.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/migrations.d/2026-07-23-query-default-cli.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/migrations.d/README.md +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/cli/execute.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/command.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/config.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/db.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/default_config.toml +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/infer.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/lib.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/parsed_vtab.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/path_table.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/vtab.rs +0 -0
- {dirsql-0.3.126 → dirsql-0.4.0}/packages/rust/src/watcher.rs +0 -0
|
@@ -5,6 +5,17 @@ export default defineConfig({
|
|
|
5
5
|
description: 'Ephemeral SQL index over a local directory. Watches a filesystem, ingests structured files into an ephemeral SQLite database, and exposes a SQL query interface.',
|
|
6
6
|
base: '/dirsql/',
|
|
7
7
|
|
|
8
|
+
// Vite blocks dev-server requests whose Host header isn't allowlisted, so
|
|
9
|
+
// `pnpm dev --host` reached by a network hostname (e.g. a Tailscale
|
|
10
|
+
// `*.ts.net` name) 400s. Allow extra hosts from the environment so a
|
|
11
|
+
// personal hostname never has to be committed:
|
|
12
|
+
// VITEPRESS_ALLOWED_HOSTS=my.host.ts.net pnpm dev --host
|
|
13
|
+
vite: {
|
|
14
|
+
server: {
|
|
15
|
+
allowedHosts: process.env.VITEPRESS_ALLOWED_HOSTS?.split(',') ?? []
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
|
|
8
19
|
themeConfig: {
|
|
9
20
|
search: {
|
|
10
21
|
provider: 'local'
|
|
@@ -57,7 +68,7 @@ export default defineConfig({
|
|
|
57
68
|
{ text: 'CLI', link: '/reference/cli' },
|
|
58
69
|
{ text: 'Configuration File', link: '/reference/config' },
|
|
59
70
|
{ text: 'Command Hooks', link: '/reference/hooks' },
|
|
60
|
-
{ text: '
|
|
71
|
+
{ text: 'Columns', link: '/reference/columns' },
|
|
61
72
|
{ text: 'Path-tables', link: '/reference/path-tables' },
|
|
62
73
|
{ text: 'HTTP API', link: '/reference/http-api' },
|
|
63
74
|
{ text: 'SDK', link: '/reference/sdk' },
|
|
@@ -57,7 +57,8 @@ migrated -- a page survives only if a slot wants its content):
|
|
|
57
57
|
`dirsql` in an application.
|
|
58
58
|
- **Reference** (`reference/`) -- CLI flags and defaults; the complete
|
|
59
59
|
`.dirsql.toml` schema; the command hook contract (placeholders, stdout
|
|
60
|
-
protocol, exit codes, timeouts);
|
|
60
|
+
protocol, exit codes, timeouts); the columns model (named tables get their
|
|
61
|
+
hook's output; path-tables get stat columns); the
|
|
61
62
|
HTTP API; the SDK page (`reference/sdk.md`, one page with
|
|
62
63
|
Python/TypeScript/Rust code-groups -- the sole SDK home); plus the
|
|
63
64
|
Migrations include (`migrations.md`).
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Your first dirsql database
|
|
2
2
|
|
|
3
3
|
In this tutorial you will turn a directory of three tiny markdown files into
|
|
4
|
-
a SQL database
|
|
5
|
-
will:
|
|
4
|
+
a SQL database. You will:
|
|
6
5
|
|
|
7
6
|
1. Create the directory and files.
|
|
8
|
-
2. Query them straight away with zero configuration.
|
|
9
|
-
3. Declare your own table
|
|
7
|
+
2. Query them straight away with zero configuration and no code.
|
|
8
|
+
3. Declare your own named table — with a tiny parser that pulls a column out
|
|
9
|
+
of each file — and query it.
|
|
10
10
|
|
|
11
11
|
It takes about five minutes.
|
|
12
12
|
|
|
@@ -140,25 +140,44 @@ A declared table fixes a shape once: you give it a name, scope it to exactly
|
|
|
140
140
|
the files you care about, and then query it by name instead of repeating a
|
|
141
141
|
path in every question. It is also the on-ramp to everything a path-table
|
|
142
142
|
can't do — a named table can be kept live by the watcher, persisted across
|
|
143
|
-
restarts, and given a parser that reads inside your files.
|
|
143
|
+
restarts, and given a parser that reads *inside* your files.
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
That parser is the point: a named table's columns are exactly what its
|
|
146
|
+
`on-file` command emits. `dirsql` adds nothing on its own — so this is where
|
|
147
|
+
you pull a value out of each file. Still inside `my-notes`, write a tiny
|
|
148
|
+
parser that reads a note's title line (the `# Heading`) and its author (the
|
|
149
|
+
folder name), and prints them as a JSON row:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
cat > note.sh <<'EOF'
|
|
153
|
+
#!/usr/bin/env sh
|
|
154
|
+
title=$(sed -n 's/^# //p' "$1" | head -n1)
|
|
155
|
+
author=$(basename "$(dirname "$1")")
|
|
156
|
+
printf '[{"title":%s,"author":%s}]' \
|
|
157
|
+
"$(jq -Rn --arg t "$title" '$t')" \
|
|
158
|
+
"$(jq -Rn --arg a "$author" '$a')"
|
|
159
|
+
EOF
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Now create a `.dirsql.toml` that points a table at it:
|
|
146
163
|
|
|
147
164
|
```bash
|
|
148
165
|
cat > .dirsql.toml <<'EOF'
|
|
149
166
|
[[table]]
|
|
150
|
-
ddl
|
|
151
|
-
glob
|
|
167
|
+
ddl = "CREATE TABLE notes (title TEXT, author TEXT)"
|
|
168
|
+
glob = "notes/**/*.md"
|
|
169
|
+
on-file = "sh note.sh {path}"
|
|
152
170
|
EOF
|
|
153
171
|
```
|
|
154
172
|
|
|
155
|
-
|
|
173
|
+
Three keys define the table:
|
|
156
174
|
|
|
157
175
|
- `glob` selects which files feed the table — every `.md` at any depth under
|
|
158
176
|
`notes/`, relative to the directory the config sits in.
|
|
159
177
|
- `ddl` is ordinary `CREATE TABLE` SQL naming the columns you want to keep.
|
|
160
|
-
|
|
161
|
-
|
|
178
|
+
- `on-file` is the command run once per matched file; `{path}` is the file's
|
|
179
|
+
path, and its printed JSON row becomes the file's row. The columns are
|
|
180
|
+
exactly what it emits — `title` from the heading, `author` from the folder.
|
|
162
181
|
|
|
163
182
|
## 5. Query the table
|
|
164
183
|
|
|
@@ -168,11 +187,11 @@ pass it explicitly with `-c`, **after** the SQL:
|
|
|
168
187
|
::: code-group
|
|
169
188
|
|
|
170
189
|
```bash [npm]
|
|
171
|
-
npx dirsql "SELECT
|
|
190
|
+
npx dirsql "SELECT title, author FROM notes ORDER BY author, title" -c .dirsql.toml | jq
|
|
172
191
|
```
|
|
173
192
|
|
|
174
193
|
```bash [PyPI]
|
|
175
|
-
uvx dirsql "SELECT
|
|
194
|
+
uvx dirsql "SELECT title, author FROM notes ORDER BY author, title" -c .dirsql.toml | jq
|
|
176
195
|
```
|
|
177
196
|
|
|
178
197
|
:::
|
|
@@ -180,35 +199,33 @@ uvx dirsql "SELECT dir, basename, size FROM notes ORDER BY dir, basename" -c .di
|
|
|
180
199
|
```json
|
|
181
200
|
[
|
|
182
201
|
{
|
|
183
|
-
"
|
|
184
|
-
"
|
|
185
|
-
"size": 52
|
|
202
|
+
"author": "alice",
|
|
203
|
+
"title": "Ideas"
|
|
186
204
|
},
|
|
187
205
|
{
|
|
188
|
-
"
|
|
189
|
-
"
|
|
190
|
-
"size": 66
|
|
206
|
+
"author": "alice",
|
|
207
|
+
"title": "Welcome"
|
|
191
208
|
},
|
|
192
209
|
{
|
|
193
|
-
"
|
|
194
|
-
"
|
|
195
|
-
"size": 41
|
|
210
|
+
"author": "bob",
|
|
211
|
+
"title": "Reading list"
|
|
196
212
|
}
|
|
197
213
|
]
|
|
198
214
|
```
|
|
199
215
|
|
|
200
|
-
You queried `FROM notes` by name — no path, no glob to repeat
|
|
201
|
-
|
|
202
|
-
|
|
216
|
+
You queried `FROM notes` by name — no path, no glob to repeat — and `title`
|
|
217
|
+
came from *inside* each file, something a path-table can't reach. Because
|
|
218
|
+
`author` is a real SQL column, you can aggregate on it. Count each author's
|
|
219
|
+
notes:
|
|
203
220
|
|
|
204
221
|
::: code-group
|
|
205
222
|
|
|
206
223
|
```bash [npm]
|
|
207
|
-
npx dirsql query "SELECT
|
|
224
|
+
npx dirsql query "SELECT author, COUNT(*) AS notes FROM notes GROUP BY author ORDER BY author" -c .dirsql.toml | jq
|
|
208
225
|
```
|
|
209
226
|
|
|
210
227
|
```bash [PyPI]
|
|
211
|
-
uvx dirsql query "SELECT
|
|
228
|
+
uvx dirsql query "SELECT author, COUNT(*) AS notes FROM notes GROUP BY author ORDER BY author" -c .dirsql.toml | jq
|
|
212
229
|
```
|
|
213
230
|
|
|
214
231
|
:::
|
|
@@ -216,11 +233,11 @@ uvx dirsql query "SELECT dir, COUNT(*) AS notes FROM notes GROUP BY dir ORDER BY
|
|
|
216
233
|
```json
|
|
217
234
|
[
|
|
218
235
|
{
|
|
219
|
-
"
|
|
236
|
+
"author": "alice",
|
|
220
237
|
"notes": 2
|
|
221
238
|
},
|
|
222
239
|
{
|
|
223
|
-
"
|
|
240
|
+
"author": "bob",
|
|
224
241
|
"notes": 1
|
|
225
242
|
}
|
|
226
243
|
]
|
|
@@ -234,7 +251,7 @@ configuration, and a declared table when you want a named shape to reuse.
|
|
|
234
251
|
- [Query files without a config](./howto/query-without-config.md) — more
|
|
235
252
|
path-table questions you can ask with no setup at all.
|
|
236
253
|
- [Define tables for your files](./howto/define-tables.md) — the full
|
|
237
|
-
`[[table]]` recipe: multiple tables,
|
|
254
|
+
`[[table]]` recipe: multiple tables, each with its own `on-file` parser.
|
|
238
255
|
- [Extract rows from file contents](./howto/extract-from-contents.md) —
|
|
239
256
|
pull columns out of *inside* your files with an `on-file` parser.
|
|
240
257
|
- [CLI](./reference/cli.md) — every flag, plus running `dirsql` as a
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Derive columns from file paths
|
|
2
|
+
|
|
3
|
+
Directory layouts often encode real data — an author, a year, a thread ID —
|
|
4
|
+
as path segments. An [`on-file`](../reference/config.md#table) hook receives
|
|
5
|
+
each file's path and can split it into columns, so a query can group and
|
|
6
|
+
filter on those segments.
|
|
7
|
+
|
|
8
|
+
## 1. Split the path in a hook
|
|
9
|
+
|
|
10
|
+
Suppose photos are filed by year and month:
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
photos/2024/05/beach.jpg
|
|
14
|
+
photos/2024/11/hike.jpg
|
|
15
|
+
photos/2025/01/snow.jpg
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Write a small parser, `pathcols.py`, that turns the path into a row. It
|
|
19
|
+
receives the file's absolute path as its argument and prints a JSON array of
|
|
20
|
+
row objects:
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
#!/usr/bin/env python3
|
|
24
|
+
import json, os, sys
|
|
25
|
+
|
|
26
|
+
parts = sys.argv[1].split(os.sep)
|
|
27
|
+
# .../photos/<year>/<month>/<file>
|
|
28
|
+
print(json.dumps([{"year": parts[-3], "month": parts[-2],
|
|
29
|
+
"basename": os.path.basename(sys.argv[1])}]))
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Point a table at it in `.dirsql.toml`:
|
|
33
|
+
|
|
34
|
+
```toml
|
|
35
|
+
[[table]]
|
|
36
|
+
ddl = "CREATE TABLE photos (year TEXT, month TEXT, basename TEXT)"
|
|
37
|
+
glob = "photos/*/*/*.jpg"
|
|
38
|
+
on-file = "python3 pathcols.py {path}"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The hook emits every column the table has — dirsql injects nothing. `{path}`
|
|
42
|
+
is the matched file's absolute path, one of the placeholders in the
|
|
43
|
+
[command hook contract](../reference/hooks.md#on-file). A column appears only
|
|
44
|
+
because the DDL declares it *and* the hook emits it.
|
|
45
|
+
|
|
46
|
+
## 2. Query the derived columns
|
|
47
|
+
|
|
48
|
+
Pass the config with [`-c`](../reference/cli.md#flags) (`dirsql` does not
|
|
49
|
+
auto-load a `.dirsql.toml` from the current directory):
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
dirsql query "SELECT year, month, basename FROM photos ORDER BY year, month" -c ./.dirsql.toml
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
[{"basename":"beach.jpg","month":"05","year":"2024"},{"basename":"hike.jpg","month":"11","year":"2024"},{"basename":"snow.jpg","month":"01","year":"2025"}]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
They are real SQL columns, so aggregation works:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
dirsql query "SELECT year, COUNT(*) AS photos FROM photos GROUP BY year" -c ./.dirsql.toml
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
[{"photos":2,"year":"2024"},{"photos":1,"year":"2025"}]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Going further
|
|
70
|
+
|
|
71
|
+
- Only need the plain filesystem stat columns (`path`, `basename`, `dir`,
|
|
72
|
+
`ext`, `size`, …) with no code? Query the path directly — a
|
|
73
|
+
[path-table](../reference/path-tables.md) gives them for free, no config.
|
|
74
|
+
- The [tutorial](../getting-started.md) walks the same idea, deriving an
|
|
75
|
+
author from the folder name, starting from zero.
|
|
76
|
+
- When the value you need lives inside the file rather than in its path,
|
|
77
|
+
see [Extract rows from file contents](./extract-from-contents.md).
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Define tables for your files
|
|
2
|
+
|
|
3
|
+
Map a glob of files to a named SQL table so you query exactly the files you
|
|
4
|
+
care about, by name — a shape you can reuse, keep live with the watcher, and
|
|
5
|
+
persist across restarts, instead of repeating an ad-hoc
|
|
6
|
+
[path-table](../reference/path-tables.md) path in every query.
|
|
7
|
+
|
|
8
|
+
## 1. Create a config with a table
|
|
9
|
+
|
|
10
|
+
Suppose your blog posts live under `posts/`, one markdown file each. A named
|
|
11
|
+
table needs three keys: a `glob` that selects the files, a `ddl` that names
|
|
12
|
+
the columns, and an [`on-file`](../reference/config.md#table) hook that emits
|
|
13
|
+
each file's rows. Put a small parser next to the config — `extract.py`, which
|
|
14
|
+
reads a post's title line and prints a JSON array of row objects:
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
#!/usr/bin/env python3
|
|
18
|
+
import json, os, sys
|
|
19
|
+
|
|
20
|
+
text = open(sys.argv[1], encoding="utf-8").read()
|
|
21
|
+
title = next((l[2:].strip() for l in text.splitlines() if l.startswith("# ")), None)
|
|
22
|
+
print(json.dumps([{"title": title, "slug": os.path.basename(sys.argv[1])[:-3]}]))
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Then declare the table in `.dirsql.toml`:
|
|
26
|
+
|
|
27
|
+
```toml
|
|
28
|
+
[[table]]
|
|
29
|
+
ddl = "CREATE TABLE posts (title TEXT, slug TEXT)"
|
|
30
|
+
glob = "posts/**/*.md"
|
|
31
|
+
on-file = "python3 extract.py {path}"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- `glob` selects the files: every `.md` under `posts/`, at any depth, relative
|
|
35
|
+
to the directory containing the config.
|
|
36
|
+
- `ddl` is a plain SQLite `CREATE TABLE` naming the columns you want to keep.
|
|
37
|
+
- `on-file` is **required** — it is where the table's rows come from. dirsql
|
|
38
|
+
injects nothing; the hook emits every column, reading the file (it has
|
|
39
|
+
`{path}`) and deriving whatever it needs. A `[[table]]` with no `on-file` is
|
|
40
|
+
a [config error](../reference/config.md#parse-errors). For plain stat
|
|
41
|
+
columns with no code, query the path directly with a path-table instead.
|
|
42
|
+
|
|
43
|
+
## 2. Query the table
|
|
44
|
+
|
|
45
|
+
Pass the config with [`-c`](../reference/cli.md#flags) — `dirsql` does not
|
|
46
|
+
auto-load a `.dirsql.toml` from the current directory. Each matched file is
|
|
47
|
+
one row:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
dirsql query "SELECT title, slug FROM posts ORDER BY slug" -c ./.dirsql.toml
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
[{"slug":"again","title":"On Recursion"},{"slug":"hello","title":"Hello World"}]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Files that don't match the glob (a `README.txt` next to `posts/`, say) are
|
|
58
|
+
simply not in the table. Only the tables you define are served.
|
|
59
|
+
|
|
60
|
+
## Multiple tables
|
|
61
|
+
|
|
62
|
+
Add one `[[table]]` entry per table — each with its own `glob`, `ddl`, and
|
|
63
|
+
`on-file`. When a file matches several globs, it populates every matching
|
|
64
|
+
table — each table is an independent view. See
|
|
65
|
+
[`[[table]]`](../reference/config.md#table) for the remaining key, `strict`.
|
|
66
|
+
|
|
67
|
+
## Going further
|
|
68
|
+
|
|
69
|
+
- The parser mechanics — placeholders, stdout protocol, per-file failure
|
|
70
|
+
isolation — are the [`on-file` hook contract](../reference/hooks.md#on-file);
|
|
71
|
+
[Extract rows from file contents](./extract-from-contents.md) is the fuller
|
|
72
|
+
recipe.
|
|
73
|
+
- Your directory layout encodes data (authors, dates, IDs)? Split the path in
|
|
74
|
+
the hook — [Derive columns from file paths](./columns-from-paths.md).
|
|
75
|
+
- Why one row per file, rebuilt from disk? See
|
|
76
|
+
[how `dirsql` thinks](../explanation.md).
|
|
@@ -34,22 +34,25 @@ comments/t2/c1.json # {"body": "following up", "author": "alice"}
|
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
Unlike a config-file table, a programmatic table takes an `on_file`
|
|
37
|
-
callback — your code reads each matched file and returns its rows
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
callback — your code reads each matched file and returns its rows. The row's
|
|
38
|
+
columns are exactly what the callback returns; `dirsql` merges nothing on top
|
|
39
|
+
(see [Columns](../reference/columns.md)), so the callback derives the `thread`
|
|
40
|
+
from the file's path itself:
|
|
40
41
|
|
|
41
42
|
::: code-group
|
|
42
43
|
|
|
43
44
|
```python [Python]
|
|
44
45
|
import asyncio
|
|
45
46
|
import json
|
|
47
|
+
import os
|
|
46
48
|
|
|
47
49
|
from dirsql import DirSQL, Table
|
|
48
50
|
|
|
49
51
|
|
|
50
52
|
def on_file(path: str) -> list[dict]:
|
|
53
|
+
thread = os.path.basename(os.path.dirname(path))
|
|
51
54
|
with open(path, encoding="utf-8") as f:
|
|
52
|
-
return [json.load(f)]
|
|
55
|
+
return [{**json.load(f), "thread": thread}]
|
|
53
56
|
|
|
54
57
|
|
|
55
58
|
async def main() -> None:
|
|
@@ -58,7 +61,7 @@ async def main() -> None:
|
|
|
58
61
|
tables=[
|
|
59
62
|
Table(
|
|
60
63
|
ddl="CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
|
|
61
|
-
glob="comments
|
|
64
|
+
glob="comments/*/*.json",
|
|
62
65
|
on_file=on_file,
|
|
63
66
|
)
|
|
64
67
|
],
|
|
@@ -73,6 +76,7 @@ asyncio.run(main())
|
|
|
73
76
|
|
|
74
77
|
```typescript [TypeScript]
|
|
75
78
|
import { readFileSync } from "node:fs";
|
|
79
|
+
import { basename, dirname } from "node:path";
|
|
76
80
|
import { DirSQL } from "dirsql";
|
|
77
81
|
|
|
78
82
|
const db = new DirSQL({
|
|
@@ -80,8 +84,10 @@ const db = new DirSQL({
|
|
|
80
84
|
tables: [
|
|
81
85
|
{
|
|
82
86
|
ddl: "CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
|
|
83
|
-
glob: "comments
|
|
84
|
-
onFile: (path) => [
|
|
87
|
+
glob: "comments/*/*.json",
|
|
88
|
+
onFile: (path) => [
|
|
89
|
+
{ ...JSON.parse(readFileSync(path, "utf8")), thread: basename(dirname(path)) },
|
|
90
|
+
],
|
|
85
91
|
},
|
|
86
92
|
],
|
|
87
93
|
});
|
|
@@ -110,6 +116,12 @@ fn on_file(path: &str) -> Vec<HashMap<String, Value>> {
|
|
|
110
116
|
row.insert(key, Value::Text(s));
|
|
111
117
|
}
|
|
112
118
|
}
|
|
119
|
+
let thread = std::path::Path::new(path)
|
|
120
|
+
.parent()
|
|
121
|
+
.and_then(|p| p.file_name())
|
|
122
|
+
.and_then(|n| n.to_str())
|
|
123
|
+
.unwrap_or_default();
|
|
124
|
+
row.insert("thread".into(), Value::Text(thread.into()));
|
|
113
125
|
vec![row]
|
|
114
126
|
}
|
|
115
127
|
|
|
@@ -118,7 +130,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
118
130
|
.root("./comments-root")
|
|
119
131
|
.table(Table::new(
|
|
120
132
|
"CREATE TABLE comments (thread TEXT, author TEXT, body TEXT)",
|
|
121
|
-
"comments
|
|
133
|
+
"comments/*/*.json",
|
|
122
134
|
on_file,
|
|
123
135
|
))
|
|
124
136
|
.build()?;
|
|
@@ -18,7 +18,7 @@ stdout works. With [`jq`](https://jqlang.org/):
|
|
|
18
18
|
|
|
19
19
|
```toml
|
|
20
20
|
[[table]]
|
|
21
|
-
ddl = "CREATE TABLE books (title TEXT, author TEXT, year INTEGER
|
|
21
|
+
ddl = "CREATE TABLE books (title TEXT, author TEXT, year INTEGER)"
|
|
22
22
|
glob = "books/*.json"
|
|
23
23
|
on-file = "jq -c '[{title, author, year}]' {path}"
|
|
24
24
|
```
|
|
@@ -35,17 +35,16 @@ Pass the config with [`-c`](../reference/cli.md#flags) (`dirsql` does not
|
|
|
35
35
|
auto-load a `.dirsql.toml` from the current directory):
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
dirsql query "SELECT title, author, year
|
|
38
|
+
dirsql query "SELECT title, author, year FROM books ORDER BY year" -c ./.dirsql.toml
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
```json
|
|
42
|
-
[{"
|
|
42
|
+
[{"author":"Charles Dickens","title":"Bleak House","year":1852},{"author":"George Eliot","title":"Middlemarch","year":1871}]
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
`dirsql
|
|
47
|
-
|
|
48
|
-
([precedence](../reference/columns.md#precedence)).
|
|
45
|
+
The table's columns are exactly what the command emits, narrowed to the DDL —
|
|
46
|
+
`dirsql` adds nothing. To include the file's `path`, have the command emit it
|
|
47
|
+
(it has `{path}`); dirsql will not merge it in for you.
|
|
49
48
|
|
|
50
49
|
## Multiple rows per file
|
|
51
50
|
|
|
@@ -54,7 +53,7 @@ row per line, slurp it:
|
|
|
54
53
|
|
|
55
54
|
```toml
|
|
56
55
|
[[table]]
|
|
57
|
-
ddl = "CREATE TABLE events (event TEXT, user TEXT
|
|
56
|
+
ddl = "CREATE TABLE events (event TEXT, user TEXT)"
|
|
58
57
|
glob = "logs/*.jsonl"
|
|
59
58
|
on-file = "jq -c -s '.' {path}"
|
|
60
59
|
```
|
|
@@ -106,10 +106,9 @@ Same command, same rows. The difference is what a declared table brings: it is
|
|
|
106
106
|
indexed on build, kept fresh by the watcher, survives restarts with
|
|
107
107
|
[`--persist`](./persist.md), and a config can declare
|
|
108
108
|
[many tables](./define-tables.md) — each with its own `on-file` — where the flag
|
|
109
|
-
gives every path-table one parser.
|
|
110
|
-
|
|
111
|
-
`
|
|
112
|
-
([precedence](../reference/columns.md#precedence)).
|
|
109
|
+
gives every path-table one parser. In both spellings the table's columns are
|
|
110
|
+
exactly what the parser emits: `dirsql` merges no filesystem facts back on. A
|
|
111
|
+
row that needs the file's `path` emits it (the parser has `{path}`).
|
|
113
112
|
|
|
114
113
|
## Going further
|
|
115
114
|
|
|
@@ -7,13 +7,16 @@ side.
|
|
|
7
7
|
|
|
8
8
|
Row events are emitted for **named tables**, so this flow needs a config —
|
|
9
9
|
[path-tables](../reference/path-tables.md) are scanned per query and are not
|
|
10
|
-
watched. Define one next to your files
|
|
10
|
+
watched. Define one next to your files. A named table's columns are whatever
|
|
11
|
+
its [`on-file`](../reference/config.md#table) hook emits; here a minimal hook
|
|
12
|
+
prints each file's basename:
|
|
11
13
|
|
|
12
14
|
```toml
|
|
13
15
|
# .dirsql.toml
|
|
14
16
|
[[table]]
|
|
15
|
-
ddl
|
|
16
|
-
glob
|
|
17
|
+
ddl = "CREATE TABLE files (basename TEXT)"
|
|
18
|
+
glob = "**/*"
|
|
19
|
+
on-file = '''sh -c 'printf "[{\"basename\":\"%s\"}]" "${1##*/}"' sh {path}'''
|
|
17
20
|
```
|
|
18
21
|
|
|
19
22
|
## 1. Open the stream
|
|
@@ -44,7 +47,7 @@ The stream delivers the resulting row change:
|
|
|
44
47
|
|
|
45
48
|
```
|
|
46
49
|
event: row
|
|
47
|
-
data: {"action":"insert","file_path":"inbox/two.txt","old_row":null,"row":{"basename":"two.txt"
|
|
50
|
+
data: {"action":"insert","file_path":"inbox/two.txt","old_row":null,"row":{"basename":"two.txt"},"table":"files"}
|
|
48
51
|
```
|
|
49
52
|
|
|
50
53
|
Edits arrive as `update` events carrying both the old and new row;
|
|
@@ -41,21 +41,25 @@ notes/tomatoes.md # planting tomato seedlings after the last frost
|
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
Next to them, `embed.py` turns one file into one row carrying its text and
|
|
44
|
-
its embedding (a JSON array, stored as TEXT — `sqlite-vec`
|
|
45
|
-
vectors directly)
|
|
44
|
+
its `path`, text, and embedding (a JSON array, stored as TEXT — `sqlite-vec`
|
|
45
|
+
accepts JSON vectors directly). dirsql injects no columns, so the script emits
|
|
46
|
+
the path itself, deriving it from the `{path}`/`{root}` the hook passes in:
|
|
46
47
|
|
|
47
48
|
```python
|
|
48
49
|
"""Embed one file's text; print a dirsql row array on stdout."""
|
|
49
50
|
import json
|
|
51
|
+
import os
|
|
50
52
|
import sys
|
|
51
53
|
|
|
52
54
|
from model2vec import StaticModel
|
|
53
55
|
|
|
54
|
-
path = sys.argv[1]
|
|
56
|
+
path, root = sys.argv[1], sys.argv[2]
|
|
55
57
|
text = open(path, encoding="utf-8").read()
|
|
56
58
|
model = StaticModel.from_pretrained("minishlab/potion-base-8M")
|
|
57
59
|
vector = model.encode([text])[0]
|
|
58
|
-
|
|
60
|
+
row = {"path": os.path.relpath(path, root), "text": text,
|
|
61
|
+
"embedding": json.dumps([round(float(x), 6) for x in vector])}
|
|
62
|
+
print(json.dumps([row]))
|
|
59
63
|
```
|
|
60
64
|
|
|
61
65
|
And `search.py` turns a `{"q": "..."}` request body into SQL, embedding the
|
|
@@ -98,7 +102,7 @@ entrypoint = "sqlite3_vec_init"
|
|
|
98
102
|
[[table]]
|
|
99
103
|
ddl = "CREATE TABLE notes (path TEXT, text TEXT, embedding TEXT)"
|
|
100
104
|
glob = "notes/*.md"
|
|
101
|
-
on-file = "uv run --with model2vec python embed.py {path}"
|
|
105
|
+
on-file = "uv run --with model2vec python embed.py {path} {root}"
|
|
102
106
|
```
|
|
103
107
|
|
|
104
108
|
The extension is named by package: the Python launcher resolves the
|
|
@@ -22,8 +22,9 @@ Exclude the noise in `.dirsql.toml`:
|
|
|
22
22
|
ignore = ["notes/drafts/**", "**/*.tmp"]
|
|
23
23
|
|
|
24
24
|
[[table]]
|
|
25
|
-
ddl
|
|
26
|
-
glob
|
|
25
|
+
ddl = "CREATE TABLE notes (basename TEXT)"
|
|
26
|
+
glob = "notes/**/*"
|
|
27
|
+
on-file = '''sh -c 'printf "[{\"basename\":\"%s\"}]" "${1##*/}"' sh {path}'''
|
|
27
28
|
```
|
|
28
29
|
|
|
29
30
|
Patterns match against root-relative paths, the same way table globs do. An
|
|
@@ -35,11 +36,11 @@ Pass the config with [`-c`](../reference/cli.md#flags) (`dirsql` does not
|
|
|
35
36
|
auto-load a `.dirsql.toml` from the current directory):
|
|
36
37
|
|
|
37
38
|
```bash
|
|
38
|
-
dirsql query "SELECT
|
|
39
|
+
dirsql query "SELECT basename FROM notes ORDER BY basename" -c ./.dirsql.toml
|
|
39
40
|
```
|
|
40
41
|
|
|
41
42
|
```json
|
|
42
|
-
[{"
|
|
43
|
+
[{"basename":"final.md"}]
|
|
43
44
|
```
|
|
44
45
|
|
|
45
46
|
## Notes
|
|
@@ -72,7 +72,7 @@ Both hook command styles from the [hook contract](../reference/hooks.md) work
|
|
|
72
72
|
in a plugin fragment:
|
|
73
73
|
|
|
74
74
|
- **Console scripts** — a `bin`-style entry point your package installs on
|
|
75
|
-
`PATH` (`embed-file {path}`). Recommended for published plugins: the command
|
|
75
|
+
`PATH` (`embed-file {path} {root}`). Recommended for published plugins: the command
|
|
76
76
|
is bound to your package's interpreter and dependencies, and it is
|
|
77
77
|
language-neutral (the fragment names a command, not a Python file).
|
|
78
78
|
- **Relative scripts** — a path resolved against the fragment's own directory
|
|
@@ -116,23 +116,28 @@ entrypoint = "sqlite3_vec_init"
|
|
|
116
116
|
[[table]]
|
|
117
117
|
ddl = "CREATE TABLE notes (path TEXT, text TEXT, embedding TEXT)"
|
|
118
118
|
glob = "notes/*.md"
|
|
119
|
-
on-file = "uv run --with model2vec python embed.py {path}"
|
|
119
|
+
on-file = "uv run --with model2vec python embed.py {path} {root}"
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
`embed.py` turns one file into one row carrying its text and
|
|
122
|
+
`embed.py` turns one file into one row carrying its path, text, and embedding.
|
|
123
|
+
dirsql injects no columns, so the script emits the path itself, from the
|
|
124
|
+
`{path}`/`{root}` the hook passes in:
|
|
123
125
|
|
|
124
126
|
```python
|
|
125
127
|
"""Embed one file's text; print a dirsql row array on stdout."""
|
|
126
128
|
import json
|
|
129
|
+
import os
|
|
127
130
|
import sys
|
|
128
131
|
|
|
129
132
|
from model2vec import StaticModel
|
|
130
133
|
|
|
131
|
-
path = sys.argv[1]
|
|
134
|
+
path, root = sys.argv[1], sys.argv[2]
|
|
132
135
|
text = open(path, encoding="utf-8").read()
|
|
133
136
|
model = StaticModel.from_pretrained("minishlab/potion-base-8M")
|
|
134
137
|
vector = model.encode([text])[0]
|
|
135
|
-
|
|
138
|
+
row = {"path": os.path.relpath(path, root), "text": text,
|
|
139
|
+
"embedding": json.dumps([round(float(x), 6) for x in vector])}
|
|
140
|
+
print(json.dumps([row]))
|
|
136
141
|
```
|
|
137
142
|
|
|
138
143
|
`search.py` turns a `{"q": "..."}` request body into nearest-neighbor SQL:
|