sqlsaber 0.38.0__tar.gz → 0.47.1__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.
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/AGENTS.md +6 -11
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/CLAUDE.md +4 -1
- sqlsaber-0.47.1/PKG-INFO +149 -0
- sqlsaber-0.47.1/README.md +125 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/astro.config.mjs +11 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/src/content/docs/changelog.md +110 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/src/content/docs/guides/authentication.mdx +16 -27
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/src/content/docs/guides/database-setup.mdx +8 -7
- sqlsaber-0.47.1/docs/src/content/docs/guides/getting-started.mdx +119 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/src/content/docs/guides/queries.mdx +26 -0
- sqlsaber-0.47.1/docs/src/content/docs/index.mdx +125 -0
- sqlsaber-0.47.1/docs/src/content/docs/installation.mdx +54 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/src/content/docs/reference/commands.md +1 -2
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/pyproject.toml +1 -1
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/agents/provider_factory.py +42 -81
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/agents/pydantic_ai_agent.py +79 -45
- sqlsaber-0.47.1/src/sqlsaber/api.py +223 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/application/auth_setup.py +4 -107
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/application/model_selection.py +3 -3
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/cli/auth.py +21 -69
- sqlsaber-0.47.1/src/sqlsaber/cli/buffered_streaming.py +166 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/cli/commands.py +59 -58
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/cli/database.py +20 -18
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/cli/display.py +45 -1
- sqlsaber-0.47.1/src/sqlsaber/cli/html_export.py +865 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/cli/interactive.py +10 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/cli/memory.py +14 -15
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/cli/models.py +59 -39
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/cli/onboarding.py +1 -3
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/cli/slash_commands.py +7 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/cli/streaming.py +10 -21
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/cli/threads.py +49 -3
- sqlsaber-0.47.1/src/sqlsaber/cli/update_check.py +149 -0
- sqlsaber-0.47.1/src/sqlsaber/cli/usage.py +67 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/config/api_keys.py +1 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/config/auth.py +10 -6
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/config/providers.py +0 -11
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/config/settings.py +25 -59
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/database/__init__.py +4 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/database/base.py +20 -7
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/database/csv.py +18 -5
- sqlsaber-0.47.1/src/sqlsaber/database/csvs.py +91 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/database/duckdb.py +32 -11
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/database/mysql.py +23 -10
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/database/postgresql.py +23 -10
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/database/resolver.py +63 -7
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/database/schema.py +28 -23
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/database/sqlite.py +31 -15
- sqlsaber-0.47.1/src/sqlsaber/prompts/dangerous_mode.py +13 -0
- sqlsaber-0.47.1/src/sqlsaber/tools/sql_guard.py +365 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/tools/sql_tools.py +35 -15
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_agents/test_provider_factory.py +31 -39
- sqlsaber-0.47.1/tests/test_agents/test_pydantic_ai_agent.py +82 -0
- sqlsaber-0.47.1/tests/test_api/test_database.py +34 -0
- sqlsaber-0.47.1/tests/test_api/test_memory.py +78 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_application/test_auth_setup.py +1 -49
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_cli/test_auth_reset.py +2 -35
- sqlsaber-0.47.1/tests/test_cli/test_commands.py +65 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_cli/test_threads.py +112 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_config/test_settings.py +2 -4
- sqlsaber-0.47.1/tests/test_database/__init__.py +0 -0
- sqlsaber-0.47.1/tests/test_database/test_csvs_connection.py +66 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_database_resolver.py +20 -0
- sqlsaber-0.47.1/tests/test_tools/test_sql_guard.py +779 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_tools/test_sql_tools.py +35 -2
- sqlsaber-0.47.1/uv.lock +3172 -0
- sqlsaber-0.38.0/PKG-INFO +0 -251
- sqlsaber-0.38.0/README.md +0 -227
- sqlsaber-0.38.0/docs/src/content/docs/guides/getting-started.mdx +0 -148
- sqlsaber-0.38.0/docs/src/content/docs/index.mdx +0 -103
- sqlsaber-0.38.0/docs/src/content/docs/installation.mdx +0 -72
- sqlsaber-0.38.0/src/sqlsaber/api.py +0 -139
- sqlsaber-0.38.0/src/sqlsaber/config/oauth_flow.py +0 -288
- sqlsaber-0.38.0/src/sqlsaber/config/oauth_tokens.py +0 -184
- sqlsaber-0.38.0/src/sqlsaber/tools/sql_guard.py +0 -227
- sqlsaber-0.38.0/tests/test_cli/test_commands.py +0 -109
- sqlsaber-0.38.0/tests/test_config/test_oauth.py +0 -154
- sqlsaber-0.38.0/tests/test_tools/test_sql_guard.py +0 -322
- sqlsaber-0.38.0/uv.lock +0 -2263
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/.github/workflows/claude-code-review.yml +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/.github/workflows/claude.yml +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/.github/workflows/deploy-docs.yml +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/.github/workflows/publish.yml +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/.github/workflows/test.yml +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/.gitignore +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/.python-version +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/LICENSE +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/.gitignore +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/.vscode/extensions.json +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/.vscode/launch.json +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/CLAUDE.md +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/package-lock.json +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/package.json +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/public/CNAME +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/public/favicon.svg +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/src/assets/sqlsaber.gif +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/src/content/docs/guides/memory.mdx +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/src/content/docs/guides/models.mdx +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/src/content/docs/guides/threads.md +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/src/content.config.ts +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/src/styles/global.css +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/docs/tsconfig.json +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/legislators.db +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/pytest.ini +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/sqlsaber.gif +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/sqlsaber.svg +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/__init__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/__main__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/agents/__init__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/agents/base.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/application/__init__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/application/db_setup.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/application/prompts.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/cli/__init__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/cli/completers.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/cli/theme.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/config/__init__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/config/database.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/config/logging.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/memory/__init__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/memory/manager.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/memory/storage.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/prompts/__init__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/prompts/claude.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/prompts/memory.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/prompts/openai.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/theme/__init__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/theme/manager.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/threads/__init__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/threads/manager.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/threads/storage.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/tools/__init__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/tools/base.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/src/sqlsaber/tools/registry.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/__init__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/conftest.py +0 -0
- {sqlsaber-0.38.0/tests/test_cli → sqlsaber-0.47.1/tests/test_api}/__init__.py +0 -0
- {sqlsaber-0.38.0/tests/test_config → sqlsaber-0.47.1/tests/test_cli}/__init__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_cli/test_slash_commands.py +0 -0
- {sqlsaber-0.38.0/tests/test_database → sqlsaber-0.47.1/tests/test_config}/__init__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_config/test_database.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_config/test_providers.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_database/test_connection.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_database/test_csv_connection.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_database/test_csv_module.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_database/test_duckdb_module.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_database/test_mysql_module.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_database/test_postgresql_module.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_database/test_schema.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_database/test_schema_display.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_database/test_sqlite_module.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_database/test_timeout.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_theme/test_manager.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_tools/__init__.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_tools/test_base.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/test_tools/test_registry.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/threads/test_threads_manager.py +0 -0
- {sqlsaber-0.38.0 → sqlsaber-0.47.1}/tests/threads/test_threads_storage.py +0 -0
|
@@ -7,13 +7,15 @@
|
|
|
7
7
|
- `tools/`: SQL, introspection, registry.
|
|
8
8
|
- `database/`: connection, resolver, schema utilities.
|
|
9
9
|
- `memory/`, `conversation/`: state and persistence.
|
|
10
|
-
- `config/`: settings, API keys,
|
|
10
|
+
- `config/`: settings, API keys, DB configs.
|
|
11
11
|
- Tests: `tests/` mirror modules (`test_cli/`, `test_tools/`, …).
|
|
12
12
|
- Docs & assets: `docs/`, `sqlsaber.gif`, `sqlsaber.svg`.
|
|
13
13
|
|
|
14
14
|
## Build, Test, and Development Commands
|
|
15
15
|
- Install (editable): `uv sync`
|
|
16
16
|
- Lint: `uv run ruff check .`
|
|
17
|
+
- Type check (all): `uvx ty check src/`
|
|
18
|
+
- Type check (targeted): `uvx ty check <file>`
|
|
17
19
|
- Format: `uv run ruff format .`
|
|
18
20
|
- Tests (all): `uv run pytest -q`
|
|
19
21
|
- Tests (targeted): `uv run pytest tests/test_tools -q`
|
|
@@ -23,7 +25,8 @@
|
|
|
23
25
|
Note: Prefer `uv run ruff ...` over `uvx ruff ...` to avoid hitting user-level uv caches that may be restricted in sandboxed environments.
|
|
24
26
|
|
|
25
27
|
## Coding Style & Naming Conventions
|
|
26
|
-
- Python 3.12+, 4‑space indent, use modern type hints.
|
|
28
|
+
- Python 3.12+, 4‑space indent, strictly use modern (3.12+) type hints approach.
|
|
29
|
+
- Type check must pass without errors always.
|
|
27
30
|
- Ruff is the linter/formatter; code must be clean and formatted.
|
|
28
31
|
- Naming: modules/files `snake_case.py`; classes `PascalCase`; functions/vars `snake_case`; constants `UPPER_SNAKE`.
|
|
29
32
|
- Keep public CLI surfaces in `cli/`; factor reusable logic into modules under `sqlsaber/`.
|
|
@@ -33,12 +36,4 @@ Note: Prefer `uv run ruff ...` over `uvx ruff ...` to avoid hitting user-level u
|
|
|
33
36
|
- Place tests under `tests/`, name files `test_*.py` and mirror package layout.
|
|
34
37
|
- Include tests for new behavior and bug fixes; prefer async tests for async code.
|
|
35
38
|
- Use fixtures from `tests/conftest.py` where possible.
|
|
36
|
-
|
|
37
|
-
## Commit & Pull Request Guidelines
|
|
38
|
-
- Commits: short, imperative; prefer conventional prefixes (e.g., `feat:`, `fix:`, `docs:`). Reference issues/PRs when relevant.
|
|
39
|
-
- PRs must: describe the change and rationale, include tests, pass `ruff` and `pytest`, and update docs/README for user‑visible changes.
|
|
40
|
-
- For CLI UX changes, include before/after samples (command + output snippet).
|
|
41
|
-
|
|
42
|
-
## Security & Configuration Tips
|
|
43
|
-
- Never commit secrets. Configure via CLI: `saber db add` and `saber models set` (credentials stored via system keyring).
|
|
44
|
-
- Queries run read‑only by default; avoid introducing mutating behavior in tools without explicit safeguards.
|
|
39
|
+
- Tests must pass without errors always.
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
- **Run Python**: `uv run python`
|
|
4
4
|
- **Run tests**: `uv run python -m pytest`
|
|
5
5
|
- **Run single test**: `uv run python -m pytest tests/test_path/test_file.py::test_function`
|
|
6
|
+
- **Type check (all)**: `uvx ty check src/`
|
|
7
|
+
- **Type check (targeted)**: `uvx ty check <file>`
|
|
6
8
|
- **Lint**: `uv run ruff check --fix`
|
|
7
9
|
- **Format**: `uv run ruff format`
|
|
8
10
|
|
|
@@ -16,6 +18,7 @@
|
|
|
16
18
|
|
|
17
19
|
- **Imports**: stdlib → 3rd party → local, use relative imports within modules
|
|
18
20
|
- **Naming**: snake_case functions/vars, PascalCase classes, UPPER_SNAKE constants, `_private` methods
|
|
19
|
-
- **Types**: Always use modern type hints (3.12+), async functions for I/O
|
|
21
|
+
- **Types**: Always use ONLY modern type hints (3.12+), async functions for I/O
|
|
22
|
+
- Type check must pass without errors always
|
|
20
23
|
- **Errors**: Use try/finally for cleanup
|
|
21
24
|
- **Docstrings**: Triple-quoted with Args/Returns sections
|
sqlsaber-0.47.1/PKG-INFO
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sqlsaber
|
|
3
|
+
Version: 0.47.1
|
|
4
|
+
Summary: SQLsaber - Open-source agentic SQL assistant
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
|
+
Requires-Dist: aiomysql>=0.2.0
|
|
8
|
+
Requires-Dist: aiosqlite>=0.21.0
|
|
9
|
+
Requires-Dist: asyncpg>=0.30.0
|
|
10
|
+
Requires-Dist: cyclopts>=3.22.1
|
|
11
|
+
Requires-Dist: duckdb>=0.9.2
|
|
12
|
+
Requires-Dist: httpx>=0.28.1
|
|
13
|
+
Requires-Dist: keyring>=25.6.0
|
|
14
|
+
Requires-Dist: keyrings-cryptfile; sys_platform == 'linux'
|
|
15
|
+
Requires-Dist: platformdirs>=4.0.0
|
|
16
|
+
Requires-Dist: prompt-toolkit>3.0.51
|
|
17
|
+
Requires-Dist: pydantic-ai
|
|
18
|
+
Requires-Dist: questionary>=2.1.0
|
|
19
|
+
Requires-Dist: rich>=13.7.0
|
|
20
|
+
Requires-Dist: sqlglot[rs]>=27.20.0
|
|
21
|
+
Requires-Dist: structlog>=25.4.0
|
|
22
|
+
Requires-Dist: tabulate>=0.9.0
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# SQLsaber
|
|
26
|
+
|
|
27
|
+
> SQLsaber is an open-source agentic SQL assistant. Think Claude Code but for SQL.
|
|
28
|
+
|
|
29
|
+
**Ask questions about your data in plain English. SQLsaber writes SQL queries, executes them, and explains the results.**
|
|
30
|
+
|
|
31
|
+

|
|
32
|
+
|
|
33
|
+
SQLsaber reads your schema, writes SQL, executes it, and explains the results—all from a single natural language prompt.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
$ saber "How many orders were placed last month?"
|
|
37
|
+
|
|
38
|
+
# SQLsaber will:
|
|
39
|
+
# 1. Discover relevant tables (orders, order_items, etc.)
|
|
40
|
+
# 2. Analyze their schema
|
|
41
|
+
# 3. Generate and run SQL
|
|
42
|
+
# 4. Return results with explanation
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Why SQLsaber?
|
|
46
|
+
|
|
47
|
+
- **No context switching** — Stay in your terminal, ask questions, get answers
|
|
48
|
+
- **Schema-aware** — Automatically introspects your database; no manual setup
|
|
49
|
+
- **Safe by default** — Read-only queries; won't modify your data
|
|
50
|
+
- **Works with your stack** — PostgreSQL, MySQL, SQLite, DuckDB, and CSV files
|
|
51
|
+
|
|
52
|
+
## Install
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Recommended
|
|
56
|
+
uv tool install sqlsaber
|
|
57
|
+
|
|
58
|
+
# Or with pipx
|
|
59
|
+
pipx install sqlsaber
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Then run:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
saber
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
On first launch, SQLsaber walks you through connecting a database and setting up authentication.
|
|
69
|
+
|
|
70
|
+
## Quick Examples
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Interactive mode
|
|
74
|
+
saber
|
|
75
|
+
|
|
76
|
+
# Single query
|
|
77
|
+
saber "show me users who signed up this week"
|
|
78
|
+
|
|
79
|
+
# Pipe from stdin
|
|
80
|
+
echo "top 10 customers by revenue" | saber
|
|
81
|
+
|
|
82
|
+
# Use a specific database
|
|
83
|
+
saber -d mydb "count active subscriptions"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Features
|
|
87
|
+
|
|
88
|
+
| Feature | Description |
|
|
89
|
+
|---------|-------------|
|
|
90
|
+
| **Schema introspection** | Discovers tables, columns, and relationships automatically |
|
|
91
|
+
| **Conversation memory** | Add context like "dates are stored as Unix timestamps" |
|
|
92
|
+
| **Thread history** | Resume past conversations with `saber threads resume` |
|
|
93
|
+
| **Extended thinking** | Enable `--thinking` for complex analytical queries |
|
|
94
|
+
| **Multiple AI providers** | Anthropic, OpenAI, Google, Groq (Claude Sonnet 4 by default) |
|
|
95
|
+
|
|
96
|
+
## Configuration
|
|
97
|
+
|
|
98
|
+
### Add a database
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
saber db add mydb
|
|
102
|
+
# Prompts for connection details
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Or pass a connection string directly:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
saber -d "postgresql://user:pass@localhost:5432/mydb" "count users"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Change AI model
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
saber models set
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Add memory (context for your database)
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
saber memory add "customer_id in orders table references users.id"
|
|
121
|
+
saber memory add "all timestamps are UTC"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## How It Works
|
|
125
|
+
|
|
126
|
+
1. **Discovery** — Lists tables and identifies relevant ones based on your question
|
|
127
|
+
2. **Schema analysis** — Introspects only the tables needed
|
|
128
|
+
3. **Query generation** — Writes SQL tailored to your database dialect
|
|
129
|
+
4. **Execution** — Runs read-only queries with safety checks
|
|
130
|
+
5. **Results** — Formats output with explanations
|
|
131
|
+
|
|
132
|
+
## Documentation
|
|
133
|
+
|
|
134
|
+
Full docs at [sqlsaber.com](https://sqlsaber.com):
|
|
135
|
+
|
|
136
|
+
- [Installation](https://sqlsaber.com/installation/)
|
|
137
|
+
- [Getting Started](https://sqlsaber.com/guides/getting-started/)
|
|
138
|
+
- [Database Setup](https://sqlsaber.com/guides/database-setup/)
|
|
139
|
+
- [Command Reference](https://sqlsaber.com/reference/commands/)
|
|
140
|
+
|
|
141
|
+
## Contributing
|
|
142
|
+
|
|
143
|
+
Contributions welcome! Please open an issue first to discuss changes.
|
|
144
|
+
|
|
145
|
+
If you find SQLsaber useful, a ⭐ on GitHub helps others discover it.
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
Apache-2.0 — see [LICENSE](./LICENSE)
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# SQLsaber
|
|
2
|
+
|
|
3
|
+
> SQLsaber is an open-source agentic SQL assistant. Think Claude Code but for SQL.
|
|
4
|
+
|
|
5
|
+
**Ask questions about your data in plain English. SQLsaber writes SQL queries, executes them, and explains the results.**
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
SQLsaber reads your schema, writes SQL, executes it, and explains the results—all from a single natural language prompt.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
$ saber "How many orders were placed last month?"
|
|
13
|
+
|
|
14
|
+
# SQLsaber will:
|
|
15
|
+
# 1. Discover relevant tables (orders, order_items, etc.)
|
|
16
|
+
# 2. Analyze their schema
|
|
17
|
+
# 3. Generate and run SQL
|
|
18
|
+
# 4. Return results with explanation
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Why SQLsaber?
|
|
22
|
+
|
|
23
|
+
- **No context switching** — Stay in your terminal, ask questions, get answers
|
|
24
|
+
- **Schema-aware** — Automatically introspects your database; no manual setup
|
|
25
|
+
- **Safe by default** — Read-only queries; won't modify your data
|
|
26
|
+
- **Works with your stack** — PostgreSQL, MySQL, SQLite, DuckDB, and CSV files
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Recommended
|
|
32
|
+
uv tool install sqlsaber
|
|
33
|
+
|
|
34
|
+
# Or with pipx
|
|
35
|
+
pipx install sqlsaber
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Then run:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
saber
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
On first launch, SQLsaber walks you through connecting a database and setting up authentication.
|
|
45
|
+
|
|
46
|
+
## Quick Examples
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Interactive mode
|
|
50
|
+
saber
|
|
51
|
+
|
|
52
|
+
# Single query
|
|
53
|
+
saber "show me users who signed up this week"
|
|
54
|
+
|
|
55
|
+
# Pipe from stdin
|
|
56
|
+
echo "top 10 customers by revenue" | saber
|
|
57
|
+
|
|
58
|
+
# Use a specific database
|
|
59
|
+
saber -d mydb "count active subscriptions"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Features
|
|
63
|
+
|
|
64
|
+
| Feature | Description |
|
|
65
|
+
|---------|-------------|
|
|
66
|
+
| **Schema introspection** | Discovers tables, columns, and relationships automatically |
|
|
67
|
+
| **Conversation memory** | Add context like "dates are stored as Unix timestamps" |
|
|
68
|
+
| **Thread history** | Resume past conversations with `saber threads resume` |
|
|
69
|
+
| **Extended thinking** | Enable `--thinking` for complex analytical queries |
|
|
70
|
+
| **Multiple AI providers** | Anthropic, OpenAI, Google, Groq (Claude Sonnet 4 by default) |
|
|
71
|
+
|
|
72
|
+
## Configuration
|
|
73
|
+
|
|
74
|
+
### Add a database
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
saber db add mydb
|
|
78
|
+
# Prompts for connection details
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Or pass a connection string directly:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
saber -d "postgresql://user:pass@localhost:5432/mydb" "count users"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Change AI model
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
saber models set
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Add memory (context for your database)
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
saber memory add "customer_id in orders table references users.id"
|
|
97
|
+
saber memory add "all timestamps are UTC"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## How It Works
|
|
101
|
+
|
|
102
|
+
1. **Discovery** — Lists tables and identifies relevant ones based on your question
|
|
103
|
+
2. **Schema analysis** — Introspects only the tables needed
|
|
104
|
+
3. **Query generation** — Writes SQL tailored to your database dialect
|
|
105
|
+
4. **Execution** — Runs read-only queries with safety checks
|
|
106
|
+
5. **Results** — Formats output with explanations
|
|
107
|
+
|
|
108
|
+
## Documentation
|
|
109
|
+
|
|
110
|
+
Full docs at [sqlsaber.com](https://sqlsaber.com):
|
|
111
|
+
|
|
112
|
+
- [Installation](https://sqlsaber.com/installation/)
|
|
113
|
+
- [Getting Started](https://sqlsaber.com/guides/getting-started/)
|
|
114
|
+
- [Database Setup](https://sqlsaber.com/guides/database-setup/)
|
|
115
|
+
- [Command Reference](https://sqlsaber.com/reference/commands/)
|
|
116
|
+
|
|
117
|
+
## Contributing
|
|
118
|
+
|
|
119
|
+
Contributions welcome! Please open an issue first to discuss changes.
|
|
120
|
+
|
|
121
|
+
If you find SQLsaber useful, a ⭐ on GitHub helps others discover it.
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
Apache-2.0 — see [LICENSE](./LICENSE)
|
|
@@ -10,6 +10,17 @@ export default defineConfig({
|
|
|
10
10
|
starlight({
|
|
11
11
|
title: "SQLsaber",
|
|
12
12
|
customCss: ["./src/styles/global.css"],
|
|
13
|
+
head: [
|
|
14
|
+
{
|
|
15
|
+
tag: "script",
|
|
16
|
+
attrs: {
|
|
17
|
+
defer: true,
|
|
18
|
+
src: "https://umami.sarthakjariwala.com/script.js",
|
|
19
|
+
"data-website-id": "72be4739-0d77-4d79-be5b-cf31a62bca87",
|
|
20
|
+
"data-domains": "sqlsaber.com",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
],
|
|
13
24
|
social: [
|
|
14
25
|
{
|
|
15
26
|
icon: "github",
|
|
@@ -9,6 +9,116 @@ All notable changes to SQLsaber will be documented here.
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
### v0.47.1
|
|
13
|
+
|
|
14
|
+
#### Fixed
|
|
15
|
+
|
|
16
|
+
- Fixed rendering of update text
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
### v0.47.0 - 2026-01-12
|
|
21
|
+
|
|
22
|
+
#### Added
|
|
23
|
+
|
|
24
|
+
- CLI: allow multiple CSVs via repeated `-d` (each CSV becomes its own DuckDB view)
|
|
25
|
+
- CLI: `saber threads resume` now accepts multiple `-d` CSVs
|
|
26
|
+
- Python API: `SQLSaber(database=[...])` now accepts multiple CSVs
|
|
27
|
+
- CSV view names are derived from file stems; collisions are suffixed (`_2`, `_3`, ...)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
### v0.46.1
|
|
32
|
+
|
|
33
|
+
#### Fixed
|
|
34
|
+
|
|
35
|
+
- Fixed rendering of update text
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
### v0.46.0 - 2026-01-11
|
|
40
|
+
|
|
41
|
+
#### Added
|
|
42
|
+
|
|
43
|
+
- Python API: add `memory` parameter to inject session context (accepts text or a file path)
|
|
44
|
+
- Agent: prefer passed `memory` over saved database memories
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### v0.45.0 - 2026-01-11
|
|
49
|
+
|
|
50
|
+
#### Added
|
|
51
|
+
|
|
52
|
+
- New version check on startup
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
### v0.44.0 - 2026-01-10
|
|
57
|
+
|
|
58
|
+
#### Removed
|
|
59
|
+
|
|
60
|
+
- Removed Anthropic OAuth (Claude Pro/Max subscription) authentication support; Anthropic now requires an API key.
|
|
61
|
+
|
|
62
|
+
#### Changed
|
|
63
|
+
|
|
64
|
+
- `saber auth setup` / onboarding now configure API keys only
|
|
65
|
+
- `saber auth reset` now removes stored API keys only
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### v0.43.0 - 2025-01-08
|
|
70
|
+
|
|
71
|
+
#### Added
|
|
72
|
+
|
|
73
|
+
- `saber threads export` command to export thread transcripts as shareable HTML files
|
|
74
|
+
- Dark and light theme support with toggle button
|
|
75
|
+
- Syntax highlighting for SQL queries
|
|
76
|
+
- Renders markdown content with code blocks, tables, and formatting
|
|
77
|
+
- Tool results displayed as collapsible sections with formatted tables
|
|
78
|
+
- Schema introspection results show columns, types, keys, and comments
|
|
79
|
+
- Includes thread metadata: database, model, timestamps
|
|
80
|
+
- Usage: `saber threads export <thread-id> [-o output.html]`
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### v0.42.0 - 2025-01-05
|
|
85
|
+
|
|
86
|
+
#### Added
|
|
87
|
+
|
|
88
|
+
- Session usage summary displayed on exit
|
|
89
|
+
- Shows input context size (current tokens), total output tokens generated
|
|
90
|
+
- Displays request count and tool call count
|
|
91
|
+
- Summary shown when exiting via `/exit`, `/quit`, or Ctrl+D
|
|
92
|
+
- Also displayed after single-query (non-interactive) mode
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### v0.41.0 - 2025-12-25
|
|
97
|
+
|
|
98
|
+
#### Changed
|
|
99
|
+
|
|
100
|
+
- Simplified event stream handling in agent and API modules
|
|
101
|
+
|
|
102
|
+
### v0.40.0 - 2025-12-24
|
|
103
|
+
|
|
104
|
+
#### Added
|
|
105
|
+
|
|
106
|
+
- `--allow-dangerous` flag to enable INSERT/UPDATE/DELETE and DDL operations
|
|
107
|
+
- Allows a restricted set of DML operations: INSERT, UPDATE, DELETE, MERGE, REPLACE
|
|
108
|
+
- Allows non-destructive DDL operations: CREATE, ALTER
|
|
109
|
+
- Always blocks dangerous operations: DROP, TRUNCATE, transaction control, GRANT/REVOKE
|
|
110
|
+
- Works in both single query and interactive modes
|
|
111
|
+
|
|
112
|
+
### v0.39.0 - 2025-12-15
|
|
113
|
+
|
|
114
|
+
#### Added
|
|
115
|
+
|
|
116
|
+
- Python API now supports `model_name` and `api_key` parameters for programmatic model configuration
|
|
117
|
+
- Override configured model: `SQLSaber(database="...", model_name="anthropic:claude-sonnet-4-20250514")`
|
|
118
|
+
- Override configured model and API key: `SQLSaber(database="...", model_name="anthropic:claude-sonnet-4-20250514", api_key="sk-...")`
|
|
119
|
+
- Falls back to OAuth if `api_key` is not provided but OAuth is configured
|
|
120
|
+
|
|
121
|
+
|
|
12
122
|
### v0.38.0 - 2025-12-01
|
|
13
123
|
|
|
14
124
|
#### Changed
|
|
@@ -3,15 +3,15 @@ title: Authentication
|
|
|
3
3
|
description: Configure LLM provider authentication for SQLsaber
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
import { Aside } from
|
|
6
|
+
import { Aside } from "@astrojs/starlight/components";
|
|
7
7
|
|
|
8
8
|
SQLsaber supports multiple LLM providers.
|
|
9
9
|
|
|
10
10
|
### Providers
|
|
11
11
|
|
|
12
|
-
SQLsaber supports the following LLM providers
|
|
12
|
+
SQLsaber supports the following LLM providers:
|
|
13
13
|
|
|
14
|
-
- **Anthropic** - API key
|
|
14
|
+
- **Anthropic** - API key
|
|
15
15
|
- **OpenAI** - API key
|
|
16
16
|
- **Google** - API key
|
|
17
17
|
- **Groq** - API key
|
|
@@ -20,7 +20,8 @@ SQLsaber supports the following LLM providers and authentication methods:
|
|
|
20
20
|
- **Hugging Face** - API key
|
|
21
21
|
|
|
22
22
|
<Aside type="note">
|
|
23
|
-
|
|
23
|
+
SQLsaber stores API keys securely using your operating system's credentials
|
|
24
|
+
store.
|
|
24
25
|
</Aside>
|
|
25
26
|
|
|
26
27
|
### Quick Setup
|
|
@@ -32,25 +33,14 @@ saber auth setup
|
|
|
32
33
|
```
|
|
33
34
|
|
|
34
35
|
This interactive command will:
|
|
36
|
+
|
|
35
37
|
1. Let you choose your AI provider
|
|
36
|
-
2.
|
|
38
|
+
2. Prompt you for an API key (or use an existing environment variable)
|
|
37
39
|
3. Securely store your credentials
|
|
38
40
|
|
|
39
41
|
#### Anthropic
|
|
40
42
|
|
|
41
|
-
SQLsaber uses Claude Sonnet 4 by default
|
|
42
|
-
|
|
43
|
-
##### Claude Pro/Max subscription (Recommended)
|
|
44
|
-
|
|
45
|
-
> If you have a Claude Pro or Max subscription, you can use it with SQLsaber:
|
|
46
|
-
|
|
47
|
-
1. Run the setup:
|
|
48
|
-
```bash
|
|
49
|
-
saber auth setup
|
|
50
|
-
```
|
|
51
|
-
2. Choose "Anthropic" as your provider
|
|
52
|
-
3. Select "Claude Pro/Max (OAuth)" as the authentication method
|
|
53
|
-
4. Follow the browser-based OAuth flow
|
|
43
|
+
SQLsaber uses Claude Sonnet 4 by default.
|
|
54
44
|
|
|
55
45
|
##### API Key
|
|
56
46
|
|
|
@@ -60,13 +50,9 @@ SQLsaber uses Claude Sonnet 4 by default and supports two authentication methods
|
|
|
60
50
|
saber auth setup
|
|
61
51
|
```
|
|
62
52
|
3. Choose "Anthropic" as your provider
|
|
63
|
-
4.
|
|
64
|
-
5. Enter your API key when prompted
|
|
65
|
-
|
|
66
|
-
<Aside type="note">
|
|
67
|
-
Follow the same steps for setting up other providers.
|
|
68
|
-
</Aside>
|
|
53
|
+
4. Enter your API key when prompted
|
|
69
54
|
|
|
55
|
+
<Aside type="note">Follow the same steps for setting up other providers.</Aside>
|
|
70
56
|
|
|
71
57
|
### Managing Authentication
|
|
72
58
|
|
|
@@ -79,8 +65,9 @@ saber auth status
|
|
|
79
65
|
```
|
|
80
66
|
|
|
81
67
|
This shows:
|
|
82
|
-
|
|
83
|
-
-
|
|
68
|
+
|
|
69
|
+
- Configured providers
|
|
70
|
+
- Whether a provider is configured via environment variable or keychain
|
|
84
71
|
|
|
85
72
|
#### Reset Authentication
|
|
86
73
|
|
|
@@ -91,8 +78,9 @@ saber auth reset
|
|
|
91
78
|
```
|
|
92
79
|
|
|
93
80
|
This will:
|
|
81
|
+
|
|
94
82
|
1. Ask you to select which provider to reset
|
|
95
|
-
2. Remove API
|
|
83
|
+
2. Remove the stored API key from your OS credentials store
|
|
96
84
|
|
|
97
85
|
### Multiple Providers
|
|
98
86
|
|
|
@@ -103,6 +91,7 @@ You can configure multiple providers and switch between them when selecting mode
|
|
|
103
91
|
You can also use environment variables for setting API keys.
|
|
104
92
|
|
|
105
93
|
Example:
|
|
94
|
+
|
|
106
95
|
```bash
|
|
107
96
|
# Anthropic
|
|
108
97
|
export ANTHROPIC_API_KEY="your-api-key"
|
|
@@ -106,18 +106,19 @@ saber db remove my-database
|
|
|
106
106
|
|
|
107
107
|
### Security
|
|
108
108
|
|
|
109
|
-
#### Read-only
|
|
109
|
+
#### Read-only by Default
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
SQLsaber blocks all write operations (INSERT, UPDATE, DELETE, DDL) by default. Only SELECT queries are allowed unless you explicitly enable dangerous mode with `--allow-dangerous`.
|
|
112
|
+
|
|
113
|
+
Even in dangerous mode, destructive operations like DROP, TRUNCATE, and GRANT/REVOKE are always blocked.
|
|
112
114
|
|
|
113
|
-
|
|
115
|
+
#### Read-only Database Role
|
|
114
116
|
|
|
115
|
-
|
|
116
|
-
If you have a read-replica of your production database, consider using those credentials to setup connection.
|
|
117
|
+
> **If you are using SQLsaber with a production database, we recommend setting up a read-only role for your database and using those credentials to setup connection in SQLsaber.**
|
|
117
118
|
|
|
118
|
-
|
|
119
|
+
SQLsaber uses AST-based validation (via sqlglot) to analyze every query before execution. This catches write operations in nested queries, CTEs, subqueries, and dialect-specific dangerous functions. However, no validation is fool-proof.
|
|
119
120
|
|
|
120
|
-
|
|
121
|
+
**The most secure approach is to create a read-only database role and use those credentials with SQLsaber.** This provides database-level enforcement that cannot be bypassed regardless of what queries are generated.
|
|
121
122
|
|
|
122
123
|
<Aside type="note">
|
|
123
124
|
For development setups, this isn't required but is a good practice if you wish
|