queryview 0.0.5__tar.gz → 0.0.7__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.
Files changed (176) hide show
  1. {queryview-0.0.5 → queryview-0.0.7}/.github/actions/start-git-daemon/action.yaml +3 -3
  2. {queryview-0.0.5 → queryview-0.0.7}/.github/workflows/publish.yaml +1 -1
  3. {queryview-0.0.5 → queryview-0.0.7}/.gitignore +1 -0
  4. {queryview-0.0.5 → queryview-0.0.7}/CLAUDE.md +12 -0
  5. queryview-0.0.7/CONTRIBUTING.md +124 -0
  6. queryview-0.0.7/PKG-INFO +218 -0
  7. queryview-0.0.7/README.md +194 -0
  8. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/conftest.py +16 -12
  9. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/connect.py +16 -15
  10. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/gitsync.py +85 -23
  11. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/migrations/env.py +1 -1
  12. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/migrations/versions/c7d8e9f0a1b2_workspaces.py +7 -13
  13. queryview-0.0.7/backend/queryview/static/assets/index-Cysz_FnM.js +46 -0
  14. queryview-0.0.7/backend/queryview/static/assets/index-h_3ZdSNd.css +2 -0
  15. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/static/index.html +2 -2
  16. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_api_gitsync.py +1 -1
  17. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_connect_store.py +2 -3
  18. queryview-0.0.7/backend/queryview/test_data_dir.py +51 -0
  19. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_gitsync.py +109 -9
  20. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_mcp_gitsync.py +2 -4
  21. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_migrations.py +5 -7
  22. {queryview-0.0.5 → queryview-0.0.7}/docker/Dockerfile +13 -6
  23. {queryview-0.0.5 → queryview-0.0.7}/docs/connect.md +22 -10
  24. {queryview-0.0.5 → queryview-0.0.7}/docs/explorer.md +22 -9
  25. {queryview-0.0.5 → queryview-0.0.7}/docs/future.md +3 -2
  26. {queryview-0.0.5 → queryview-0.0.7}/docs/gitsync.md +19 -9
  27. {queryview-0.0.5 → queryview-0.0.7}/docs/query.md +31 -4
  28. {queryview-0.0.5 → queryview-0.0.7}/docs/queryview.md +17 -1
  29. {queryview-0.0.5 → queryview-0.0.7}/docs/workspace.md +3 -4
  30. {queryview-0.0.5 → queryview-0.0.7}/e2e/conftest.py +67 -7
  31. queryview-0.0.7/e2e/test_app.py +98 -0
  32. {queryview-0.0.5 → queryview-0.0.7}/e2e/test_dashboard.py +3 -10
  33. {queryview-0.0.5 → queryview-0.0.7}/e2e/test_drivers.py +5 -10
  34. queryview-0.0.7/e2e/test_explorer.py +202 -0
  35. {queryview-0.0.5 → queryview-0.0.7}/e2e/test_gitsync.py +5 -4
  36. queryview-0.0.7/e2e/test_popovers.py +49 -0
  37. {queryview-0.0.5 → queryview-0.0.7}/e2e/test_query.py +69 -11
  38. {queryview-0.0.5 → queryview-0.0.7}/e2e/test_remote.py +3 -11
  39. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/App.tsx +120 -33
  40. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/ExplorerView.tsx +186 -42
  41. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/QueryView.tsx +62 -94
  42. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/controls/GitSyncControls.tsx +0 -0
  43. queryview-0.0.7/frontend/src/app/controls/Spinner.tsx +34 -0
  44. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/controls/WorkspaceSwitcher.tsx +5 -1
  45. queryview-0.0.7/frontend/src/app/controls/useDismiss.ts +28 -0
  46. queryview-0.0.7/frontend/src/app/databaseFilter.test.ts +28 -0
  47. queryview-0.0.7/frontend/src/app/databaseFilter.ts +7 -0
  48. queryview-0.0.7/frontend/src/app/explorerSettings.test.ts +61 -0
  49. queryview-0.0.7/frontend/src/app/explorerSettings.ts +27 -0
  50. queryview-0.0.7/frontend/src/app/testStorage.ts +25 -0
  51. queryview-0.0.7/frontend/src/app/viewSettings.test.ts +65 -0
  52. queryview-0.0.7/frontend/src/app/viewSettings.ts +31 -0
  53. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/workspace.test.ts +1 -8
  54. queryview-0.0.7/frontend/src/core/cells/CellDataModal.tsx +125 -0
  55. queryview-0.0.7/frontend/src/core/cells/structured.test.ts +63 -0
  56. queryview-0.0.7/frontend/src/core/cells/structured.ts +51 -0
  57. queryview-0.0.7/frontend/src/core/cells/structuredTree.test.ts +85 -0
  58. queryview-0.0.7/frontend/src/core/cells/structuredTree.ts +58 -0
  59. queryview-0.0.7/frontend/src/core/results/ResultsTable.tsx +131 -0
  60. queryview-0.0.7/frontend/src/core/results/cellWidth.test.ts +21 -0
  61. queryview-0.0.7/frontend/src/core/results/cellWidth.ts +21 -0
  62. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/index.css +20 -0
  63. {queryview-0.0.5 → queryview-0.0.7}/pyproject.toml +1 -2
  64. {queryview-0.0.5 → queryview-0.0.7}/scripts/setup_browser.sh +1 -1
  65. {queryview-0.0.5 → queryview-0.0.7}/uv.lock +0 -2
  66. queryview-0.0.5/PKG-INFO +0 -210
  67. queryview-0.0.5/README.md +0 -185
  68. queryview-0.0.5/backend/queryview/static/assets/index-B3W6A5bg.css +0 -2
  69. queryview-0.0.5/backend/queryview/static/assets/index-BE8_u4Np.js +0 -44
  70. queryview-0.0.5/backend/queryview/test_db_path.py +0 -58
  71. queryview-0.0.5/e2e/test_app.py +0 -47
  72. queryview-0.0.5/e2e/test_explorer.py +0 -66
  73. queryview-0.0.5/frontend/src/core/results/ResultsTable.tsx +0 -56
  74. {queryview-0.0.5 → queryview-0.0.7}/.claude/settings.json +0 -0
  75. {queryview-0.0.5 → queryview-0.0.7}/.github/workflows/ci.yml +0 -0
  76. {queryview-0.0.5 → queryview-0.0.7}/.mcp.json +0 -0
  77. {queryview-0.0.5 → queryview-0.0.7}/.pre-commit-config.yaml +0 -0
  78. {queryview-0.0.5 → queryview-0.0.7}/LICENSE +0 -0
  79. {queryview-0.0.5 → queryview-0.0.7}/backend/alembic.ini +0 -0
  80. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/__init__.py +0 -0
  81. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/dashboard_queries.py +0 -0
  82. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/dashboards.py +0 -0
  83. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/drivers/__init__.py +0 -0
  84. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/drivers/base.py +0 -0
  85. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/drivers/clickhouse.py +0 -0
  86. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/drivers/duckdb.py +0 -0
  87. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/drivers/postgres.py +0 -0
  88. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/drivers/test_base.py +0 -0
  89. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/drivers/test_clickhouse.py +0 -0
  90. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/drivers/test_contract.py +0 -0
  91. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/drivers/test_duckdb.py +0 -0
  92. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/drivers/test_postgres.py +0 -0
  93. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/main.py +0 -0
  94. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/mcp_server.py +0 -0
  95. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/migrations/script.py.mako +0 -0
  96. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/migrations/versions/9a536b7c0328_initial_schema.py +0 -0
  97. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/migrations/versions/a1b2c3d4e5f6_connection_config_blob.py +0 -0
  98. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/migrations/versions/b2c3d4e5f6a7_predefined_presentation.py +0 -0
  99. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/queries.py +0 -0
  100. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/remote.py +0 -0
  101. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/static/favicon.svg +0 -0
  102. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_api_db.py +0 -0
  103. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_api_export_import.py +0 -0
  104. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_api_workspaces.py +0 -0
  105. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_connect_flow.py +0 -0
  106. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_dashboard_queries.py +0 -0
  107. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_dashboards.py +0 -0
  108. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_main.py +0 -0
  109. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_mcp_mount.py +0 -0
  110. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_queries.py +0 -0
  111. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_remote.py +0 -0
  112. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_validation.py +0 -0
  113. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_workspaces.py +0 -0
  114. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/test_yamlio.py +0 -0
  115. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/validation.py +0 -0
  116. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/workspaces.py +0 -0
  117. {queryview-0.0.5 → queryview-0.0.7}/backend/queryview/yamlio.py +0 -0
  118. {queryview-0.0.5 → queryview-0.0.7}/docs/api.md +0 -0
  119. {queryview-0.0.5 → queryview-0.0.7}/docs/dashboard.md +0 -0
  120. {queryview-0.0.5 → queryview-0.0.7}/docs/export-import.md +0 -0
  121. {queryview-0.0.5 → queryview-0.0.7}/docs/remote.md +0 -0
  122. {queryview-0.0.5 → queryview-0.0.7}/e2e/test_export_import.py +0 -0
  123. {queryview-0.0.5 → queryview-0.0.7}/e2e/test_workspaces.py +0 -0
  124. {queryview-0.0.5 → queryview-0.0.7}/frontend/.gitignore +0 -0
  125. {queryview-0.0.5 → queryview-0.0.7}/frontend/README.md +0 -0
  126. {queryview-0.0.5 → queryview-0.0.7}/frontend/eslint.config.js +0 -0
  127. {queryview-0.0.5 → queryview-0.0.7}/frontend/index.html +0 -0
  128. {queryview-0.0.5 → queryview-0.0.7}/frontend/package.json +0 -0
  129. {queryview-0.0.5 → queryview-0.0.7}/frontend/public/favicon.svg +0 -0
  130. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/DashboardView.tsx +0 -0
  131. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/compactNumber.test.ts +0 -0
  132. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/compactNumber.ts +0 -0
  133. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/connection.ts +0 -0
  134. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/controls/ExportImportControls.tsx +0 -0
  135. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/controls/Toast.tsx +0 -0
  136. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/drivers.ts +0 -0
  137. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/gitsync.test.ts +0 -0
  138. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/gitsync.ts +0 -0
  139. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/promptSuggestions.test.ts +0 -0
  140. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/promptSuggestions.ts +0 -0
  141. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/sessionLock.test.ts +0 -0
  142. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/sessionLock.ts +0 -0
  143. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/workspace.ts +0 -0
  144. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/yamlio.test.ts +0 -0
  145. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/app/yamlio.ts +0 -0
  146. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/cells/CellViewModal.tsx +0 -0
  147. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/cells/ComplexCell.tsx +0 -0
  148. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/cells/cellView.test.ts +0 -0
  149. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/cells/cellView.ts +0 -0
  150. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/cells/cellViewYaml.test.ts +0 -0
  151. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/cells/cellViewYaml.tsx +0 -0
  152. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/cells/complexCells.test.ts +0 -0
  153. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/cells/complexCells.ts +0 -0
  154. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/dashboard/DashboardFrame.tsx +0 -0
  155. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/dashboard/srcDoc.test.ts +0 -0
  156. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/dashboard/srcDoc.ts +0 -0
  157. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/index.ts +0 -0
  158. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/params/queryParams.test.ts +0 -0
  159. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/params/queryParams.ts +0 -0
  160. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/presentation/FieldPickers.tsx +0 -0
  161. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/presentation/presentation.test.ts +0 -0
  162. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/presentation/presentation.ts +0 -0
  163. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/results/rows.test.ts +0 -0
  164. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/core/results/rows.ts +0 -0
  165. {queryview-0.0.5 → queryview-0.0.7}/frontend/src/main.tsx +0 -0
  166. {queryview-0.0.5 → queryview-0.0.7}/frontend/tsconfig.app.json +0 -0
  167. {queryview-0.0.5 → queryview-0.0.7}/frontend/tsconfig.json +0 -0
  168. {queryview-0.0.5 → queryview-0.0.7}/frontend/tsconfig.node.json +0 -0
  169. {queryview-0.0.5 → queryview-0.0.7}/frontend/vite.config.ts +0 -0
  170. {queryview-0.0.5 → queryview-0.0.7}/package-lock.json +0 -0
  171. {queryview-0.0.5 → queryview-0.0.7}/package.json +0 -0
  172. {queryview-0.0.5 → queryview-0.0.7}/pyrightconfig.json +0 -0
  173. {queryview-0.0.5 → queryview-0.0.7}/scripts/dev.sh +0 -0
  174. {queryview-0.0.5 → queryview-0.0.7}/scripts/setup.sh +0 -0
  175. {queryview-0.0.5 → queryview-0.0.7}/scripts/setup_clickhouse.sh +0 -0
  176. {queryview-0.0.5 → queryview-0.0.7}/scripts/setup_postgres.sh +0 -0
@@ -3,8 +3,8 @@ description: >-
3
3
  Start a loopback `git daemon` that serves — and accepts pushes into — bare
4
4
  repos under a base path, so e2e tests exercise git sync against a real
5
5
  git:// remote with no auth. Creates an empty bare repo and exports
6
- GIT_SYNC_REMOTE pointing at it; `--detach` keeps the daemon alive across
7
- steps.
6
+ E2E_GIT_REMOTE pointing at it, which the e2e suite applies to the default
7
+ workspace; `--detach` keeps the daemon alive across steps.
8
8
 
9
9
  runs:
10
10
  using: composite
@@ -15,7 +15,7 @@ runs:
15
15
  GIT_DAEMON_BASE="$RUNNER_TEMP/gitsrv"
16
16
  mkdir -p "$GIT_DAEMON_BASE"
17
17
  git init --bare -b main "$GIT_DAEMON_BASE/queryview.git"
18
- echo "GIT_SYNC_REMOTE=git://127.0.0.1:9418/queryview.git" >> "$GITHUB_ENV"
18
+ echo "E2E_GIT_REMOTE=git://127.0.0.1:9418/queryview.git" >> "$GITHUB_ENV"
19
19
  git daemon --reuseaddr --listen=127.0.0.1 --port=9418 \
20
20
  --base-path="$GIT_DAEMON_BASE" --export-all \
21
21
  --enable=receive-pack --detach
@@ -221,7 +221,7 @@ jobs:
221
221
  - name: Smoke-test installed package
222
222
  working-directory: ${{ runner.temp }}
223
223
  run: |
224
- DB_PATH="$PWD/queryview.db" "$GITHUB_WORKSPACE/.venv/bin/queryview" > server.log 2>&1 &
224
+ DATA_DIR="$PWD/qv-data" "$GITHUB_WORKSPACE/.venv/bin/queryview" > server.log 2>&1 &
225
225
  pid=$!
226
226
  for i in $(seq 1 30); do
227
227
  curl -sf http://localhost:8000/api/health > /dev/null && break
@@ -26,6 +26,7 @@ backend/queryview/static/
26
26
  backend/*.db
27
27
  backend/*.db-*
28
28
  backend/*.key
29
+ backend/db.sqlite*
29
30
 
30
31
  # Editor
31
32
  .DS_Store
@@ -3,6 +3,18 @@
3
3
  1. Avoid `Co-Authored-By: Claude` (and similar Claude/AI attribution) trailers in
4
4
  commit messages and PR bodies.
5
5
 
6
+ # Data Privacy
7
+
8
+ 1. **Never commit tenant data.** Real customer, tenant, or environment
9
+ identifiers (database and table names, hostnames, account or user names,
10
+ query results, screenshots of live data) must not appear in code, tests,
11
+ fixtures, docs, or commit messages.
12
+ 2. **Always anonymize.** When an example needs realistic-looking data, invent
13
+ generic names (e.g. `sales_reporting`, `example.internal`). Rewrite any
14
+ pasted samples before using them.
15
+ 3. If tenant data slips into history, rewrite the commits to remove it and
16
+ force-push the branch rather than adding a follow-up commit.
17
+
6
18
  # Operational Guidelines
7
19
 
8
20
  1. Use `uv run` (e.g. `uv run pytest`, `uv run python ...`), not `python -m` or a
@@ -0,0 +1,124 @@
1
+ # Contributing to QueryView
2
+
3
+ QueryView is a **Python** backend (**FastAPI + SQLModel**) serving `/api/*`, a
4
+ **Vite + React + TypeScript** SPA with **Tailwind CSS**, and a
5
+ **[Playwright](https://playwright.dev)** end-to-end suite. This page covers
6
+ working on it; [README.md](README.md) covers running it.
7
+
8
+ ## Layout
9
+
10
+ ```
11
+ .
12
+ ├── backend/ # Python FastAPI + SQLModel app exposing /api/* (queryview package)
13
+ ├── frontend/ # Vite + React + TS + Tailwind v4 SPA (npm workspace)
14
+ ├── e2e/ # Playwright (pytest) browser tests
15
+ ├── docs/ # Feature and API documentation
16
+ ├── pyproject.toml # Backend deps + console script + e2e `test` group (uv)
17
+ └── package.json # npm workspace root: dev orchestration + frontend build
18
+ ```
19
+
20
+ ## Prerequisites
21
+
22
+ - [uv](https://docs.astral.sh/uv/) — runs the Python backend and the Playwright
23
+ (pytest) e2e suite (it manages the Python toolchain and dependencies for you).
24
+ - [Node.js](https://nodejs.org) 20+ (with npm) — runs the root tasks and the
25
+ Vite frontend.
26
+
27
+ npm runs the frontend and the root task scripts; uv handles the backend's and
28
+ e2e suite's Python virtualenv and dependencies.
29
+
30
+ ## Install
31
+
32
+ Install the backend's Python dependencies (uv reads the root `pyproject.toml`;
33
+ the package lives in `backend/queryview`):
34
+
35
+ ```bash
36
+ uv sync
37
+ ```
38
+
39
+ Install the JavaScript dependencies for the frontend workspace:
40
+
41
+ ```bash
42
+ npm install
43
+ ```
44
+
45
+ Install the e2e tooling (the `test` dependency group) and fetch the Playwright
46
+ browser:
47
+
48
+ ```bash
49
+ uv sync --group test
50
+ uv run --group test playwright install chromium
51
+ ```
52
+
53
+ ## Run dev servers
54
+
55
+ Run backend and frontend together:
56
+
57
+ ```bash
58
+ npm run dev
59
+ ```
60
+
61
+ Or individually:
62
+
63
+ ```bash
64
+ npm run backend # uvicorn --reload on http://localhost:8000
65
+ npm run frontend # http://localhost:5173
66
+ ```
67
+
68
+ The Vite dev server proxies `/api/*` to the FastAPI backend, so the SPA can call the API on the same origin.
69
+
70
+ ## Build & preview production
71
+
72
+ ```bash
73
+ npm run build # produces frontend/dist/
74
+ npm run start # SERVE_STATIC=1, FastAPI serves dist/ + /api on :8000
75
+ npm run preview # build && start in one shot
76
+ ```
77
+
78
+ In production there is no Vite — the FastAPI backend serves the bundled SPA from `frontend/dist/` and falls back to `index.html` for any unknown non-`/api` path so client-side routing works. Override the dist location with `STATIC_ROOT=/path/to/dist`.
79
+
80
+ ## Tests
81
+
82
+ Backend unit tests live beside the code they test inside `backend/queryview`,
83
+ and ship in the wheel:
84
+
85
+ ```bash
86
+ uv run --group test pytest backend/queryview
87
+ ```
88
+
89
+ The e2e suite is [pytest-playwright](https://playwright.dev/python/docs/test-runners),
90
+ installed via the `test` dependency group and run through `uv`. Start the dev
91
+ servers (`npm run dev`) in one terminal, then in another:
92
+
93
+ ```bash
94
+ uv run --group test pytest
95
+ ```
96
+
97
+ Override the target URL with `BASE_URL=http://localhost:4173 uv run --group test pytest` (e.g. to test a built preview). To run the full suite against a real ClickHouse the way CI does, use `scripts/setup.sh`.
98
+
99
+ ## Lint & type-check
100
+
101
+ [pre-commit](https://pre-commit.com) runs ruff (lint + format) and pyright, the
102
+ same checks CI's `lint` job runs. Pyright resolves imports from the project's
103
+ `.venv`, so sync first:
104
+
105
+ ```bash
106
+ uv sync --group dev
107
+ uv run pre-commit install # once, to run on every commit
108
+ uv run pre-commit run --all-files
109
+ ```
110
+
111
+ ## Release to PyPI
112
+
113
+ The **Publish to PyPI** workflow (`.github/workflows/publish.yaml`, manual
114
+ dispatch with a `vX.Y.Z` tag input) builds the SPA into the wheel
115
+ (`queryview/static/`), then gates the release on the installed wheel: an HTTP
116
+ smoke test, the packaged backend test suite (`pytest --pyargs queryview`), and
117
+ the Playwright e2e suite driving the packaged server (skippable via the
118
+ `skip-e2e` input for emergencies). It then publishes
119
+ [`queryview`](https://pypi.org/project/queryview/) via PyPI trusted publishing,
120
+ pushes the tag, and creates the GitHub release. The package version comes
121
+ from the tag (no version bump in `pyproject.toml`).
122
+
123
+ An installed wheel serves the bundled UI by default — see the
124
+ [quick start](README.md#quick-start).
@@ -0,0 +1,218 @@
1
+ Metadata-Version: 2.5
2
+ Name: queryview
3
+ Version: 0.0.7
4
+ Summary: Local SQL workbench for ClickHouse, Postgres and DuckDB, with a built-in MCP server for AI agents
5
+ Project-URL: Homepage, https://github.com/kolodkin/queryview
6
+ Project-URL: Repository, https://github.com/kolodkin/queryview
7
+ Project-URL: Issues, https://github.com/kolodkin/queryview/issues
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Requires-Python: >=3.11
11
+ Requires-Dist: aiosqlite>=0.22.1
12
+ Requires-Dist: alembic>=1.13
13
+ Requires-Dist: asyncpg>=0.29
14
+ Requires-Dist: cryptography>=42
15
+ Requires-Dist: duckdb>=1.0
16
+ Requires-Dist: fastapi>=0.110
17
+ Requires-Dist: httpx>=0.27
18
+ Requires-Dist: mcp<2,>=1.9
19
+ Requires-Dist: pyyaml>=6
20
+ Requires-Dist: sqlalchemy[asyncio]>=2.0
21
+ Requires-Dist: sqlmodel>=0.0.16
22
+ Requires-Dist: uvicorn>=0.29
23
+ Description-Content-Type: text/markdown
24
+
25
+ # QueryView
26
+
27
+ A local SQL workbench for **ClickHouse**, **Postgres** and **DuckDB** — and a
28
+ place to let an AI agent do the querying for you.
29
+
30
+ Everything happens at one prompt: type `connect prod` to open a database,
31
+ `query` to run SQL, `explorer` to click through tables, `dashboard` to open a
32
+ saved dashboard. Saved queries and dashboards live in workspaces that can back
33
+ themselves up to a git remote. A built-in MCP server lets an agent run
34
+ read-only queries, push a query or a whole dashboard into your open browser tab,
35
+ and snapshot your work to git.
36
+
37
+ QueryView is a **single-user tool that runs on your own machine**. It has no
38
+ login and assumes it is reachable only from localhost — don't expose its port.
39
+
40
+ ## Quick start
41
+
42
+ Run the released package — API + bundled SPA on http://localhost:8000:
43
+
44
+ ```bash
45
+ uvx queryview
46
+ ```
47
+
48
+ `--port` (or the `PORT` env var) picks the listen port, default 8000:
49
+ `uvx queryview --port 9000`.
50
+
51
+ Or run the container image — every release publishes
52
+ `ghcr.io/kolodkin/queryview` to GHCR for `linux/amd64` and `linux/arm64`, tagged
53
+ `vX.Y.Z` and (for non-pre-releases) `latest`:
54
+
55
+ ```bash
56
+ docker run -p 8000:8000 ghcr.io/kolodkin/queryview:latest
57
+ ```
58
+
59
+ To serve on a different host port, remap it (the container keeps listening on
60
+ 8000, which its healthcheck probes): `docker run -p 9000:8000 ...`. QueryView
61
+ expects to be reached from localhost only, so prefer binding the published port
62
+ to loopback: `docker run -p 127.0.0.1:8000:8000 ...`.
63
+
64
+ The command above keeps its state inside the container, so connections and
65
+ workspaces are lost when the container is removed. See
66
+ [Run with Docker](#run-with-docker) for a persistent setup.
67
+
68
+ ## What you can do
69
+
70
+ Open http://localhost:8000 and type into the prompt:
71
+
72
+ | Command | What happens |
73
+ |---|---|
74
+ | `new clickhouse` / `new postgres` / `new duckdb` | Create a connection — host, port and credentials, or a file path for DuckDB. Passwords are encrypted at rest. |
75
+ | `connect <name>` | Open a saved connection and pick a database — that opens the explorer. The last one reconnects automatically next time. |
76
+ | `query` | Run SQL: paginated results, column picker, save/load reusable queries, download the page as CSV. |
77
+ | `explorer` | Browse tables without typing SQL — a sidebar of tables with row/size estimates, click to page through rows. |
78
+ | `dashboard [name]` | Open a saved dashboard: an HTML layout that re-runs its queries against live data every time you open it. |
79
+
80
+ Beyond the prompt:
81
+
82
+ - **Workspaces** group your saved queries and dashboards, and each can sync to
83
+ its own git remote for backup, history and restore —
84
+ [workspace.md](docs/workspace.md), [gitsync.md](docs/gitsync.md).
85
+ - **YAML export/import** moves a single query, a dashboard, or a whole
86
+ workspace between instances with no git involved —
87
+ [export-import.md](docs/export-import.md).
88
+ - **MCP** lets an agent query your databases and author dashboards — see
89
+ [below](#mcp-server).
90
+
91
+ ## Run with Docker
92
+
93
+ The image runs as the non-root user `queryview` (UID 1000) and sets
94
+ `DATA_DIR=/var/lib/queryview`, so every piece of state lives directly under that
95
+ one directory:
96
+
97
+ | Path | Contents |
98
+ |---|---|
99
+ | `/var/lib/queryview/db.sqlite` | SQLite store: connections, workspaces, queries, dashboards |
100
+ | `/var/lib/queryview/encryption.key` | Key that encrypts stored connection passwords |
101
+ | `/var/lib/queryview/gitsync/` | Local clones used by workspace git sync |
102
+
103
+ Mount a volume at `/var/lib/queryview` and all three persist across container
104
+ restarts, removals and upgrades.
105
+
106
+ ### Persisting it
107
+
108
+ ```bash
109
+ mkdir -p ~/.queryview
110
+ docker run -d --name queryview \
111
+ -p 127.0.0.1:8000:8000 \
112
+ -v ~/.queryview:/var/lib/queryview \
113
+ ghcr.io/kolodkin/queryview:latest
114
+ ```
115
+
116
+ Create the directory first so Docker doesn't create it owned by root. The
117
+ container runs as UID 1000, the first user on most Linux distributions; if
118
+ `id -u` prints something else, add `--user "$(id -u):$(id -g)"` so the
119
+ container writes the files as you.
120
+
121
+ `~/.queryview` is also where a local `uvx queryview` keeps its state, so the
122
+ container and a local run share one database, key and set of clones with no
123
+ extra setup. Don't run both at once: each would serve the same SQLite file.
124
+
125
+ To let Docker own the location instead, swap the path for a named volume,
126
+ `-v queryview-data:/var/lib/queryview`. Docker seeds it from the image, so
127
+ ownership is already right and there is nothing to create up front, but the
128
+ state no longer lines up with a local run.
129
+
130
+ ### Git sync
131
+
132
+ The image ships `git`, so workspace git sync works in the container, and its
133
+ clones live under `/var/lib/queryview/gitsync/`, which the mount above already
134
+ covers. Give the workspace an HTTPS remote carrying a scoped, expiring token —
135
+ [docs/gitsync.md](docs/gitsync.md) has the URL form and what becomes of the
136
+ credential.
137
+
138
+ SSH also works, but nothing in the container can answer a prompt: the key must
139
+ be passphrase-free and `known_hosts` must already list the host. Mount one
140
+ dedicated deploy key, not your whole `.ssh`, readable by UID 1000:
141
+
142
+ ```bash
143
+ docker run -d --name queryview \
144
+ -p 127.0.0.1:8000:8000 \
145
+ -v ~/.queryview:/var/lib/queryview \
146
+ -v ~/.ssh/queryview_deploy:/home/queryview/.ssh/id_ed25519:ro \
147
+ -v ~/.ssh/known_hosts:/home/queryview/.ssh/known_hosts:ro \
148
+ ghcr.io/kolodkin/queryview:latest
149
+ ```
150
+
151
+ ## MCP server
152
+
153
+ The backend mounts a FastMCP server (Streamable HTTP) at
154
+ `http://localhost:8000/mcp/`. There is nothing extra to start — it runs inside
155
+ the server process (`uvx queryview`, `npm run dev`, ...). Registering the client
156
+ is a separate, one-time step on the machine running the agent: an HTTP MCP
157
+ server can't install itself into someone else's client.
158
+
159
+ ```bash
160
+ claude mcp add --transport http queryview http://localhost:8000/mcp/
161
+ ```
162
+
163
+ Three things to get right:
164
+
165
+ - **Prefer the trailing slash.** The mount serves `/mcp/`. The slashless
166
+ `/mcp` also works — it 307-redirects — but registering the canonical path
167
+ skips a round trip on every call.
168
+ - **Match the port.** The URL must point at the port QueryView actually
169
+ listens on — `--port 9000` means `http://localhost:9000/mcp/`, and
170
+ `docker run -p 9000:8000` means the *host* port, `9000`, not the container's
171
+ `8000`.
172
+ - **Start QueryView first.** The client dials this URL when it starts; if
173
+ nothing is listening it reports a connection error and stays failed until you
174
+ reconnect it.
175
+
176
+ QueryView is a **local, single-user tool**: it assumes it is reachable only from
177
+ localhost. `/mcp/` is unauthenticated, and its tools can query every configured
178
+ connection and rewrite workspace git state, so don't publish the port. Bind the
179
+ container to loopback — `docker run -p 127.0.0.1:8000:8000 ...` — since a plain
180
+ `-p 8000:8000` listens on all interfaces.
181
+
182
+ Tools: `run_query` (read-only SQL, rows returned to the agent), `push_query`
183
+ and `push_dashboard` (fill a live browser session), `list_queries` /
184
+ `list_dashboards`, and `git_store` / `git_history` / `git_restore` (workspace
185
+ git backups). The push tools target an **armed** browser session: enable
186
+ "Allow remote control" from the agent icon next to the connection pill and use
187
+ the session id it shows. See [docs/remote.md](docs/remote.md) for the full
188
+ protocol.
189
+
190
+ ## Where your data lives
191
+
192
+ All state lives in one data directory, `~/.queryview` on every OS, relocated
193
+ with `DATA_DIR`. Inside are the SQLite store `db.sqlite`, the local
194
+ password-encryption key `encryption.key`, and the workspace git-sync clones
195
+ under `gitsync/`. Back that directory up — or give each workspace a git remote
196
+ and let [git sync](docs/gitsync.md) do it.
197
+
198
+ ## Documentation
199
+
200
+ - [queryview.md](docs/queryview.md) — the single-prompt page.
201
+ - [connect.md](docs/connect.md) — connections, drivers, sessions, storage.
202
+ - [query.md](docs/query.md) — the query panel: pagination, predefined queries, CSV.
203
+ - [explorer.md](docs/explorer.md) — the table navigator.
204
+ - [dashboard.md](docs/dashboard.md) — dashboards and how agents author them.
205
+ - [workspace.md](docs/workspace.md) — workspaces.
206
+ - [gitsync.md](docs/gitsync.md) — git backup, history and restore.
207
+ - [export-import.md](docs/export-import.md) — YAML export and import.
208
+ - [remote.md](docs/remote.md) — the remote-control protocol behind the MCP push tools.
209
+ - [api.md](docs/api.md) — the full HTTP endpoint reference.
210
+
211
+ ## Contributing
212
+
213
+ Development setup, tests and the release process are in
214
+ [CONTRIBUTING.md](CONTRIBUTING.md).
215
+
216
+ ## License
217
+
218
+ [MIT](LICENSE).
@@ -0,0 +1,194 @@
1
+ # QueryView
2
+
3
+ A local SQL workbench for **ClickHouse**, **Postgres** and **DuckDB** — and a
4
+ place to let an AI agent do the querying for you.
5
+
6
+ Everything happens at one prompt: type `connect prod` to open a database,
7
+ `query` to run SQL, `explorer` to click through tables, `dashboard` to open a
8
+ saved dashboard. Saved queries and dashboards live in workspaces that can back
9
+ themselves up to a git remote. A built-in MCP server lets an agent run
10
+ read-only queries, push a query or a whole dashboard into your open browser tab,
11
+ and snapshot your work to git.
12
+
13
+ QueryView is a **single-user tool that runs on your own machine**. It has no
14
+ login and assumes it is reachable only from localhost — don't expose its port.
15
+
16
+ ## Quick start
17
+
18
+ Run the released package — API + bundled SPA on http://localhost:8000:
19
+
20
+ ```bash
21
+ uvx queryview
22
+ ```
23
+
24
+ `--port` (or the `PORT` env var) picks the listen port, default 8000:
25
+ `uvx queryview --port 9000`.
26
+
27
+ Or run the container image — every release publishes
28
+ `ghcr.io/kolodkin/queryview` to GHCR for `linux/amd64` and `linux/arm64`, tagged
29
+ `vX.Y.Z` and (for non-pre-releases) `latest`:
30
+
31
+ ```bash
32
+ docker run -p 8000:8000 ghcr.io/kolodkin/queryview:latest
33
+ ```
34
+
35
+ To serve on a different host port, remap it (the container keeps listening on
36
+ 8000, which its healthcheck probes): `docker run -p 9000:8000 ...`. QueryView
37
+ expects to be reached from localhost only, so prefer binding the published port
38
+ to loopback: `docker run -p 127.0.0.1:8000:8000 ...`.
39
+
40
+ The command above keeps its state inside the container, so connections and
41
+ workspaces are lost when the container is removed. See
42
+ [Run with Docker](#run-with-docker) for a persistent setup.
43
+
44
+ ## What you can do
45
+
46
+ Open http://localhost:8000 and type into the prompt:
47
+
48
+ | Command | What happens |
49
+ |---|---|
50
+ | `new clickhouse` / `new postgres` / `new duckdb` | Create a connection — host, port and credentials, or a file path for DuckDB. Passwords are encrypted at rest. |
51
+ | `connect <name>` | Open a saved connection and pick a database — that opens the explorer. The last one reconnects automatically next time. |
52
+ | `query` | Run SQL: paginated results, column picker, save/load reusable queries, download the page as CSV. |
53
+ | `explorer` | Browse tables without typing SQL — a sidebar of tables with row/size estimates, click to page through rows. |
54
+ | `dashboard [name]` | Open a saved dashboard: an HTML layout that re-runs its queries against live data every time you open it. |
55
+
56
+ Beyond the prompt:
57
+
58
+ - **Workspaces** group your saved queries and dashboards, and each can sync to
59
+ its own git remote for backup, history and restore —
60
+ [workspace.md](docs/workspace.md), [gitsync.md](docs/gitsync.md).
61
+ - **YAML export/import** moves a single query, a dashboard, or a whole
62
+ workspace between instances with no git involved —
63
+ [export-import.md](docs/export-import.md).
64
+ - **MCP** lets an agent query your databases and author dashboards — see
65
+ [below](#mcp-server).
66
+
67
+ ## Run with Docker
68
+
69
+ The image runs as the non-root user `queryview` (UID 1000) and sets
70
+ `DATA_DIR=/var/lib/queryview`, so every piece of state lives directly under that
71
+ one directory:
72
+
73
+ | Path | Contents |
74
+ |---|---|
75
+ | `/var/lib/queryview/db.sqlite` | SQLite store: connections, workspaces, queries, dashboards |
76
+ | `/var/lib/queryview/encryption.key` | Key that encrypts stored connection passwords |
77
+ | `/var/lib/queryview/gitsync/` | Local clones used by workspace git sync |
78
+
79
+ Mount a volume at `/var/lib/queryview` and all three persist across container
80
+ restarts, removals and upgrades.
81
+
82
+ ### Persisting it
83
+
84
+ ```bash
85
+ mkdir -p ~/.queryview
86
+ docker run -d --name queryview \
87
+ -p 127.0.0.1:8000:8000 \
88
+ -v ~/.queryview:/var/lib/queryview \
89
+ ghcr.io/kolodkin/queryview:latest
90
+ ```
91
+
92
+ Create the directory first so Docker doesn't create it owned by root. The
93
+ container runs as UID 1000, the first user on most Linux distributions; if
94
+ `id -u` prints something else, add `--user "$(id -u):$(id -g)"` so the
95
+ container writes the files as you.
96
+
97
+ `~/.queryview` is also where a local `uvx queryview` keeps its state, so the
98
+ container and a local run share one database, key and set of clones with no
99
+ extra setup. Don't run both at once: each would serve the same SQLite file.
100
+
101
+ To let Docker own the location instead, swap the path for a named volume,
102
+ `-v queryview-data:/var/lib/queryview`. Docker seeds it from the image, so
103
+ ownership is already right and there is nothing to create up front, but the
104
+ state no longer lines up with a local run.
105
+
106
+ ### Git sync
107
+
108
+ The image ships `git`, so workspace git sync works in the container, and its
109
+ clones live under `/var/lib/queryview/gitsync/`, which the mount above already
110
+ covers. Give the workspace an HTTPS remote carrying a scoped, expiring token —
111
+ [docs/gitsync.md](docs/gitsync.md) has the URL form and what becomes of the
112
+ credential.
113
+
114
+ SSH also works, but nothing in the container can answer a prompt: the key must
115
+ be passphrase-free and `known_hosts` must already list the host. Mount one
116
+ dedicated deploy key, not your whole `.ssh`, readable by UID 1000:
117
+
118
+ ```bash
119
+ docker run -d --name queryview \
120
+ -p 127.0.0.1:8000:8000 \
121
+ -v ~/.queryview:/var/lib/queryview \
122
+ -v ~/.ssh/queryview_deploy:/home/queryview/.ssh/id_ed25519:ro \
123
+ -v ~/.ssh/known_hosts:/home/queryview/.ssh/known_hosts:ro \
124
+ ghcr.io/kolodkin/queryview:latest
125
+ ```
126
+
127
+ ## MCP server
128
+
129
+ The backend mounts a FastMCP server (Streamable HTTP) at
130
+ `http://localhost:8000/mcp/`. There is nothing extra to start — it runs inside
131
+ the server process (`uvx queryview`, `npm run dev`, ...). Registering the client
132
+ is a separate, one-time step on the machine running the agent: an HTTP MCP
133
+ server can't install itself into someone else's client.
134
+
135
+ ```bash
136
+ claude mcp add --transport http queryview http://localhost:8000/mcp/
137
+ ```
138
+
139
+ Three things to get right:
140
+
141
+ - **Prefer the trailing slash.** The mount serves `/mcp/`. The slashless
142
+ `/mcp` also works — it 307-redirects — but registering the canonical path
143
+ skips a round trip on every call.
144
+ - **Match the port.** The URL must point at the port QueryView actually
145
+ listens on — `--port 9000` means `http://localhost:9000/mcp/`, and
146
+ `docker run -p 9000:8000` means the *host* port, `9000`, not the container's
147
+ `8000`.
148
+ - **Start QueryView first.** The client dials this URL when it starts; if
149
+ nothing is listening it reports a connection error and stays failed until you
150
+ reconnect it.
151
+
152
+ QueryView is a **local, single-user tool**: it assumes it is reachable only from
153
+ localhost. `/mcp/` is unauthenticated, and its tools can query every configured
154
+ connection and rewrite workspace git state, so don't publish the port. Bind the
155
+ container to loopback — `docker run -p 127.0.0.1:8000:8000 ...` — since a plain
156
+ `-p 8000:8000` listens on all interfaces.
157
+
158
+ Tools: `run_query` (read-only SQL, rows returned to the agent), `push_query`
159
+ and `push_dashboard` (fill a live browser session), `list_queries` /
160
+ `list_dashboards`, and `git_store` / `git_history` / `git_restore` (workspace
161
+ git backups). The push tools target an **armed** browser session: enable
162
+ "Allow remote control" from the agent icon next to the connection pill and use
163
+ the session id it shows. See [docs/remote.md](docs/remote.md) for the full
164
+ protocol.
165
+
166
+ ## Where your data lives
167
+
168
+ All state lives in one data directory, `~/.queryview` on every OS, relocated
169
+ with `DATA_DIR`. Inside are the SQLite store `db.sqlite`, the local
170
+ password-encryption key `encryption.key`, and the workspace git-sync clones
171
+ under `gitsync/`. Back that directory up — or give each workspace a git remote
172
+ and let [git sync](docs/gitsync.md) do it.
173
+
174
+ ## Documentation
175
+
176
+ - [queryview.md](docs/queryview.md) — the single-prompt page.
177
+ - [connect.md](docs/connect.md) — connections, drivers, sessions, storage.
178
+ - [query.md](docs/query.md) — the query panel: pagination, predefined queries, CSV.
179
+ - [explorer.md](docs/explorer.md) — the table navigator.
180
+ - [dashboard.md](docs/dashboard.md) — dashboards and how agents author them.
181
+ - [workspace.md](docs/workspace.md) — workspaces.
182
+ - [gitsync.md](docs/gitsync.md) — git backup, history and restore.
183
+ - [export-import.md](docs/export-import.md) — YAML export and import.
184
+ - [remote.md](docs/remote.md) — the remote-control protocol behind the MCP push tools.
185
+ - [api.md](docs/api.md) — the full HTTP endpoint reference.
186
+
187
+ ## Contributing
188
+
189
+ Development setup, tests and the release process are in
190
+ [CONTRIBUTING.md](CONTRIBUTING.md).
191
+
192
+ ## License
193
+
194
+ [MIT](LICENSE).
@@ -1,8 +1,8 @@
1
1
  """Shared fixtures for backend (non-e2e) tests.
2
2
 
3
- Redirects the SQLite store and encryption-key file to a per-session tempdir so
4
- tests don't touch the real `backend/queryview.db`, and resets the lazy
5
- module-level engine/schema state in `queryview.connect` before tests run."""
3
+ Redirects the data directory to a per-session tempdir so tests don't touch the
4
+ real one, and resets the lazy module-level engine/schema state in
5
+ `queryview.connect` before tests run."""
6
6
 
7
7
  from __future__ import annotations
8
8
 
@@ -14,7 +14,18 @@ import pytest
14
14
 
15
15
 
16
16
  @pytest.fixture
17
- def git_env(tmp_path, monkeypatch):
17
+ def clone_base(tmp_path, monkeypatch) -> Path:
18
+ """Redirect every workspace's sync clone into this test's tmpdir, so clones
19
+ never land in the session data dir and can't leak between tests."""
20
+ from queryview import gitsync
21
+
22
+ base = tmp_path / "clones"
23
+ monkeypatch.setattr(gitsync, "_clone_base", lambda: base)
24
+ return base
25
+
26
+
27
+ @pytest.fixture
28
+ def git_env(tmp_path, clone_base):
18
29
  """A local bare repo as the default workspace's git-sync remote + a fresh
19
30
  per-workspace clone base dir. Resets the default workspace to 'no remote'
20
31
  on teardown so unconfigured-state tests stay valid."""
@@ -28,7 +39,6 @@ def git_env(tmp_path, monkeypatch):
28
39
  check=True,
29
40
  capture_output=True,
30
41
  )
31
- monkeypatch.setenv("GIT_SYNC_DIR", str(tmp_path / "clones"))
32
42
  asyncio.run(update_workspace(DEFAULT_WORKSPACE, remote=str(remote)))
33
43
  yield remote
34
44
  asyncio.run(update_workspace(DEFAULT_WORKSPACE, remote=None))
@@ -69,13 +79,7 @@ def default_ws_id() -> int:
69
79
  @pytest.fixture(scope="session", autouse=True)
70
80
  def _isolated_db(tmp_path_factory: pytest.TempPathFactory):
71
81
  tmp: Path = tmp_path_factory.mktemp("qv_backend_tests")
72
- os.environ["DB_PATH"] = str(tmp / "test.db")
73
- os.environ["DB_KEY_PATH"] = str(tmp / "test.db.key")
74
-
75
- # The workspaces migration seeds the default workspace from GIT_SYNC_*;
76
- # tests control that per-test (monkeypatch), never from ambient env.
77
- os.environ.pop("GIT_SYNC_REMOTE", None)
78
- os.environ.pop("GIT_SYNC_BRANCH", None)
82
+ os.environ["DATA_DIR"] = str(tmp)
79
83
 
80
84
  # Reset the lazy globals so the next DB touch picks up the new paths.
81
85
  import queryview.connect as _c