talktodb-api-connector 0.1.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.
- talktodb_api_connector-0.1.0/.github/workflows/publish.yml +38 -0
- talktodb_api_connector-0.1.0/.gitignore +20 -0
- talktodb_api_connector-0.1.0/.python-version +1 -0
- talktodb_api_connector-0.1.0/PKG-INFO +83 -0
- talktodb_api_connector-0.1.0/README.md +69 -0
- talktodb_api_connector-0.1.0/pyproject.toml +27 -0
- talktodb_api_connector-0.1.0/src/talktodb_api_connector/__init__.py +5 -0
- talktodb_api_connector-0.1.0/src/talktodb_api_connector/api/__init__.py +5 -0
- talktodb_api_connector-0.1.0/src/talktodb_api_connector/api/main.py +72 -0
- talktodb_api_connector-0.1.0/src/talktodb_api_connector/api/routes.py +48 -0
- talktodb_api_connector-0.1.0/src/talktodb_api_connector/api/schemas.py +77 -0
- talktodb_api_connector-0.1.0/src/talktodb_api_connector/cli/__init__.py +1 -0
- talktodb_api_connector-0.1.0/src/talktodb_api_connector/cli/main.py +517 -0
- talktodb_api_connector-0.1.0/src/talktodb_api_connector/config.py +108 -0
- talktodb_api_connector-0.1.0/src/talktodb_api_connector/database_registry.py +127 -0
- talktodb_api_connector-0.1.0/src/talktodb_api_connector/repository.py +130 -0
- talktodb_api_connector-0.1.0/src/talktodb_api_connector/service.py +119 -0
- talktodb_api_connector-0.1.0/src/talktodb_api_connector/unit_of_work.py +61 -0
- talktodb_api_connector-0.1.0/uv.lock +566 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Build talktodb-api-connector and upload wheel + sdist to PyPI.
|
|
2
|
+
name: Publish talktodb-api-connector
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
# branches:
|
|
7
|
+
# - main
|
|
8
|
+
# - master
|
|
9
|
+
tags:
|
|
10
|
+
- "v*"
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
build-and-publish:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- name: Checkout
|
|
21
|
+
uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Install uv
|
|
24
|
+
uses: astral-sh/setup-uv@v5
|
|
25
|
+
|
|
26
|
+
- name: Set up Python
|
|
27
|
+
uses: actions/setup-python@v5
|
|
28
|
+
with:
|
|
29
|
+
python-version: "3.12"
|
|
30
|
+
|
|
31
|
+
- name: Build distributions
|
|
32
|
+
run: uv build
|
|
33
|
+
|
|
34
|
+
- name: Publish to PyPI
|
|
35
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
36
|
+
with:
|
|
37
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
38
|
+
packages-dir: dist
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Build outputs
|
|
2
|
+
dist/
|
|
3
|
+
build/
|
|
4
|
+
*.egg-info/
|
|
5
|
+
|
|
6
|
+
# Bytecode
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[cod]
|
|
9
|
+
*$py.class
|
|
10
|
+
|
|
11
|
+
# Local virtual environments
|
|
12
|
+
.venv/
|
|
13
|
+
venv/
|
|
14
|
+
git-personal-config.sh
|
|
15
|
+
# Test / coverage caches (local only)
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.coverage
|
|
18
|
+
.coverage.*
|
|
19
|
+
htmlcov/
|
|
20
|
+
.ruff_cache/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: talktodb-api-connector
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: FastAPI app: configurable SQL backend, read-only mode, access controls
|
|
5
|
+
Author-email: Biman Kumar Das <daskumarbiman2020@gmail.com>
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
|
+
Requires-Dist: asyncpg>=0.32.0
|
|
8
|
+
Requires-Dist: fastapi>=0.141.1
|
|
9
|
+
Requires-Dist: pydantic>=2.13.4
|
|
10
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0
|
|
11
|
+
Requires-Dist: typer>=0.28.0
|
|
12
|
+
Requires-Dist: uvicorn>=0.52.4
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# talktodb-api-connector
|
|
16
|
+
|
|
17
|
+
Runs a small HTTP API on your machine that reads database settings from a local config file and executes SQL you send it. A command-line tool creates and edits that config, starts or stops the API, and on Windows can register the API as a system service. Nothing in the package ships your data off the machine except SQL you choose to run against your own database.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
Install from PyPI with ```pip install talktodb-api-connector```. The talktodb command is added to your PATH.
|
|
22
|
+
|
|
23
|
+
## Commands
|
|
24
|
+
|
|
25
|
+
| Command | Description |
|
|
26
|
+
|---------|-------------|
|
|
27
|
+
| talktodb config set | Set one setting using a dotted name and a value (for example database.host and localhost). |
|
|
28
|
+
| talktodb config ls | Show the current config as JSON; the database password is never printed. |
|
|
29
|
+
| talktodb api start | Check config and database driver, print the config, then start the API in a background process and remember its process id. |
|
|
30
|
+
| talktodb api stop | Stop the API using the saved process id. |
|
|
31
|
+
| talktodb service install | Windows only. Register the API as a Windows service using WinSW; the service is not started automatically. |
|
|
32
|
+
| talktodb service remove | Windows only. Unregister that service and remove the WinSW service definition file. |
|
|
33
|
+
|
|
34
|
+
### Manual run vs Windows service
|
|
35
|
+
|
|
36
|
+
- **talktodb api start** — Run the API yourself as a background process in your user session.
|
|
37
|
+
- **talktodb service install** — Register the same API with Windows so it can start at boot or from Services; each time the service starts, it reads the config file again from disk.
|
|
38
|
+
|
|
39
|
+
## Configuration
|
|
40
|
+
|
|
41
|
+
Settings live in a JSON file in your home directory named .talktodb.config. Use talktodb config set with paths such as server.port or database.host. talktodb config ls shows everything except the database password.
|
|
42
|
+
|
|
43
|
+
### Server (HTTP API)
|
|
44
|
+
|
|
45
|
+
- **server.port** — TCP port the API listens on (default 2026).
|
|
46
|
+
- **server.allowed_origins** — Browser Origin values allowed for cross-origin requests (CORS); default empty list. An empty list means browsers on other sites cannot call the API.
|
|
47
|
+
|
|
48
|
+
The API always binds to 127.0.0.1 on your machine. That address is not stored in the config file.
|
|
49
|
+
|
|
50
|
+
### Database
|
|
51
|
+
|
|
52
|
+
- **database.dialect** — Database kind and async driver (see supported values below); default postgresql.
|
|
53
|
+
- **database.host** — Database server hostname or IP; default 127.0.0.1.
|
|
54
|
+
- **database.port** — Database server port; default 5432.
|
|
55
|
+
- **database.username** — Login user name; default empty.
|
|
56
|
+
- **database.password** — Login password; default empty.
|
|
57
|
+
- **database.database** — Database name to connect to; default empty.
|
|
58
|
+
- **database.read_only** — When true, only read-style SQL (SELECT and similar) is allowed; writes are rejected before they run; default false.
|
|
59
|
+
|
|
60
|
+
#### Supported dialect values
|
|
61
|
+
|
|
62
|
+
The CLI maps these names to async SQLAlchemy drivers:
|
|
63
|
+
|
|
64
|
+
- postgresql or postgres
|
|
65
|
+
- mysql or mariadb
|
|
66
|
+
- sqlite
|
|
67
|
+
- mssql or sqlserver
|
|
68
|
+
- oracle
|
|
69
|
+
|
|
70
|
+
You may also set dialect to a full driver string that already includes a plus sign (for example postgresql+asyncpg). Install the matching Python driver package (such as asyncpg for PostgreSQL) before starting the API.
|
|
71
|
+
|
|
72
|
+
### Example Commands
|
|
73
|
+
```bash
|
|
74
|
+
talktodb config set database.dialect postgresql
|
|
75
|
+
talktodb config set database.host localhost
|
|
76
|
+
talktodb config set database.port 5432
|
|
77
|
+
talktodb config set database.username <csv_user>
|
|
78
|
+
talktodb config set database.password <password>
|
|
79
|
+
talktodb config set database.database talktodb
|
|
80
|
+
talktodb config set database.read_only false
|
|
81
|
+
talktodb config set server.port 2026
|
|
82
|
+
talktodb config set server.allowed_origins []
|
|
83
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# talktodb-api-connector
|
|
2
|
+
|
|
3
|
+
Runs a small HTTP API on your machine that reads database settings from a local config file and executes SQL you send it. A command-line tool creates and edits that config, starts or stops the API, and on Windows can register the API as a system service. Nothing in the package ships your data off the machine except SQL you choose to run against your own database.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
Install from PyPI with ```pip install talktodb-api-connector```. The talktodb command is added to your PATH.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
| Command | Description |
|
|
12
|
+
|---------|-------------|
|
|
13
|
+
| talktodb config set | Set one setting using a dotted name and a value (for example database.host and localhost). |
|
|
14
|
+
| talktodb config ls | Show the current config as JSON; the database password is never printed. |
|
|
15
|
+
| talktodb api start | Check config and database driver, print the config, then start the API in a background process and remember its process id. |
|
|
16
|
+
| talktodb api stop | Stop the API using the saved process id. |
|
|
17
|
+
| talktodb service install | Windows only. Register the API as a Windows service using WinSW; the service is not started automatically. |
|
|
18
|
+
| talktodb service remove | Windows only. Unregister that service and remove the WinSW service definition file. |
|
|
19
|
+
|
|
20
|
+
### Manual run vs Windows service
|
|
21
|
+
|
|
22
|
+
- **talktodb api start** — Run the API yourself as a background process in your user session.
|
|
23
|
+
- **talktodb service install** — Register the same API with Windows so it can start at boot or from Services; each time the service starts, it reads the config file again from disk.
|
|
24
|
+
|
|
25
|
+
## Configuration
|
|
26
|
+
|
|
27
|
+
Settings live in a JSON file in your home directory named .talktodb.config. Use talktodb config set with paths such as server.port or database.host. talktodb config ls shows everything except the database password.
|
|
28
|
+
|
|
29
|
+
### Server (HTTP API)
|
|
30
|
+
|
|
31
|
+
- **server.port** — TCP port the API listens on (default 2026).
|
|
32
|
+
- **server.allowed_origins** — Browser Origin values allowed for cross-origin requests (CORS); default empty list. An empty list means browsers on other sites cannot call the API.
|
|
33
|
+
|
|
34
|
+
The API always binds to 127.0.0.1 on your machine. That address is not stored in the config file.
|
|
35
|
+
|
|
36
|
+
### Database
|
|
37
|
+
|
|
38
|
+
- **database.dialect** — Database kind and async driver (see supported values below); default postgresql.
|
|
39
|
+
- **database.host** — Database server hostname or IP; default 127.0.0.1.
|
|
40
|
+
- **database.port** — Database server port; default 5432.
|
|
41
|
+
- **database.username** — Login user name; default empty.
|
|
42
|
+
- **database.password** — Login password; default empty.
|
|
43
|
+
- **database.database** — Database name to connect to; default empty.
|
|
44
|
+
- **database.read_only** — When true, only read-style SQL (SELECT and similar) is allowed; writes are rejected before they run; default false.
|
|
45
|
+
|
|
46
|
+
#### Supported dialect values
|
|
47
|
+
|
|
48
|
+
The CLI maps these names to async SQLAlchemy drivers:
|
|
49
|
+
|
|
50
|
+
- postgresql or postgres
|
|
51
|
+
- mysql or mariadb
|
|
52
|
+
- sqlite
|
|
53
|
+
- mssql or sqlserver
|
|
54
|
+
- oracle
|
|
55
|
+
|
|
56
|
+
You may also set dialect to a full driver string that already includes a plus sign (for example postgresql+asyncpg). Install the matching Python driver package (such as asyncpg for PostgreSQL) before starting the API.
|
|
57
|
+
|
|
58
|
+
### Example Commands
|
|
59
|
+
```bash
|
|
60
|
+
talktodb config set database.dialect postgresql
|
|
61
|
+
talktodb config set database.host localhost
|
|
62
|
+
talktodb config set database.port 5432
|
|
63
|
+
talktodb config set database.username <csv_user>
|
|
64
|
+
talktodb config set database.password <password>
|
|
65
|
+
talktodb config set database.database talktodb
|
|
66
|
+
talktodb config set database.read_only false
|
|
67
|
+
talktodb config set server.port 2026
|
|
68
|
+
talktodb config set server.allowed_origins []
|
|
69
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "talktodb-api-connector"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "FastAPI app: configurable SQL backend, read-only mode, access controls"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Biman Kumar Das", email = "daskumarbiman2020@gmail.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"asyncpg>=0.32.0",
|
|
12
|
+
"fastapi>=0.141.1",
|
|
13
|
+
"pydantic>=2.13.4",
|
|
14
|
+
"sqlalchemy[asyncio]>=2.0",
|
|
15
|
+
"typer>=0.28.0",
|
|
16
|
+
"uvicorn>=0.52.4",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
talktodb = "talktodb_api_connector.cli.main:main"
|
|
21
|
+
|
|
22
|
+
[build-system]
|
|
23
|
+
requires = ["hatchling"]
|
|
24
|
+
build-backend = "hatchling.build"
|
|
25
|
+
|
|
26
|
+
[tool.hatch.build.targets.wheel]
|
|
27
|
+
packages = ["src/talktodb_api_connector"]
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import sys
|
|
5
|
+
from contextlib import asynccontextmanager
|
|
6
|
+
|
|
7
|
+
from fastapi import FastAPI, Request
|
|
8
|
+
from starlette.middleware.cors import CORSMiddleware
|
|
9
|
+
|
|
10
|
+
from talktodb_api_connector.api.routes import router as api_router
|
|
11
|
+
from talktodb_api_connector.config import load_settings
|
|
12
|
+
from talktodb_api_connector.database_registry import DatabaseConnectionRegistry
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _ensure_app_logging() -> None:
|
|
16
|
+
"""Configure root logging to stderr when nothing else (e.g. uvicorn) configured it."""
|
|
17
|
+
root = logging.getLogger()
|
|
18
|
+
if root.handlers:
|
|
19
|
+
return
|
|
20
|
+
logging.basicConfig(
|
|
21
|
+
level=logging.INFO,
|
|
22
|
+
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
|
|
23
|
+
stream=sys.stderr,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@asynccontextmanager
|
|
28
|
+
async def lifespan(app: FastAPI):
|
|
29
|
+
_ensure_app_logging()
|
|
30
|
+
settings = load_settings()
|
|
31
|
+
app.state.settings = settings
|
|
32
|
+
DatabaseConnectionRegistry.initialize(settings)
|
|
33
|
+
# CORS ingress: only attach middleware when origins are configured. With an
|
|
34
|
+
# empty allowlist we skip CORSMiddleware so browsers receive no
|
|
35
|
+
# Access-Control-Allow-Origin for cross-origin requests (same-origin still works).
|
|
36
|
+
if settings.server.allowed_origins:
|
|
37
|
+
app.add_middleware(
|
|
38
|
+
CORSMiddleware,
|
|
39
|
+
allow_origins=list(settings.server.allowed_origins),
|
|
40
|
+
allow_credentials=True,
|
|
41
|
+
allow_methods=["*"],
|
|
42
|
+
allow_headers=["*"],
|
|
43
|
+
)
|
|
44
|
+
yield
|
|
45
|
+
await DatabaseConnectionRegistry.close()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
app = FastAPI(title="talktodb-api-connector", lifespan=lifespan)
|
|
49
|
+
app.include_router(api_router)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@app.get("/")
|
|
53
|
+
def root(request: Request) -> dict[str, str]:
|
|
54
|
+
"""Health-style root endpoint."""
|
|
55
|
+
settings = request.app.state.settings
|
|
56
|
+
if settings.server.allowed_origins:
|
|
57
|
+
cors_note = (
|
|
58
|
+
f"CORS enabled for {len(settings.server.allowed_origins)} browser origin(s) "
|
|
59
|
+
"(not database access control)"
|
|
60
|
+
)
|
|
61
|
+
else:
|
|
62
|
+
cors_note = (
|
|
63
|
+
"CORS off (allowed_origins empty; no CORSMiddleware — "
|
|
64
|
+
"cross-origin browser requests blocked)"
|
|
65
|
+
)
|
|
66
|
+
return {
|
|
67
|
+
"status": "ok",
|
|
68
|
+
"message": "talktodb-api-connector",
|
|
69
|
+
"bind_host": "127.0.0.1",
|
|
70
|
+
"settings": ("loaded from ~/.talktodb.config (JSON only)"),
|
|
71
|
+
"cors": cors_note,
|
|
72
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""HTTP routes for talktodb-api-connector."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Annotated
|
|
6
|
+
|
|
7
|
+
from fastapi import APIRouter, Depends, Request
|
|
8
|
+
|
|
9
|
+
from talktodb_api_connector.api.schemas import (
|
|
10
|
+
RunDbQueryOutput,
|
|
11
|
+
RunDbQueryRequest,
|
|
12
|
+
SettingsPublic,
|
|
13
|
+
)
|
|
14
|
+
from talktodb_api_connector.service import QueryService
|
|
15
|
+
from talktodb_api_connector.unit_of_work import UnitOfWork
|
|
16
|
+
|
|
17
|
+
router = APIRouter()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
async def get_unit_of_work():
|
|
21
|
+
"""Request-scoped unit of work: session + repository; closes on exit."""
|
|
22
|
+
async with UnitOfWork() as uow:
|
|
23
|
+
yield uow
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_query_service(
|
|
27
|
+
request: Request,
|
|
28
|
+
uow: Annotated[UnitOfWork, Depends(get_unit_of_work)],
|
|
29
|
+
) -> QueryService:
|
|
30
|
+
"""Build :class:`QueryService` from app settings and the request-scoped unit of work."""
|
|
31
|
+
return QueryService(uow, request.app.state.settings)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@router.get("/settings", response_model=SettingsPublic)
|
|
35
|
+
async def get_settings(request: Request) -> SettingsPublic:
|
|
36
|
+
"""Return loaded application settings without the database password."""
|
|
37
|
+
return SettingsPublic.model_validate(
|
|
38
|
+
request.app.state.settings.model_dump(exclude={"database": {"password": True}})
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@router.post("/query", response_model=RunDbQueryOutput)
|
|
43
|
+
async def post_query(
|
|
44
|
+
body: RunDbQueryRequest,
|
|
45
|
+
service: Annotated[QueryService, Depends(get_query_service)],
|
|
46
|
+
) -> RunDbQueryOutput:
|
|
47
|
+
"""Execute SQL; delegates to :class:`QueryService`."""
|
|
48
|
+
return await service.run_query(body.sql, body.params)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""API response models aligned with the agent server tool contracts."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ServerConfigPublic(BaseModel):
|
|
11
|
+
"""Server subsection returned by ``GET /settings``."""
|
|
12
|
+
|
|
13
|
+
model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
|
|
14
|
+
|
|
15
|
+
port: int = Field(default=2026, description="HTTP API bind port (uvicorn; default 2026).")
|
|
16
|
+
allowed_origins: list[str] = Field(
|
|
17
|
+
default_factory=list,
|
|
18
|
+
description="CORS allowlisted browser origins.",
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DatabaseConfigPublic(BaseModel):
|
|
23
|
+
"""Database subsection returned by ``GET /settings`` (password never included)."""
|
|
24
|
+
|
|
25
|
+
model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
|
|
26
|
+
|
|
27
|
+
dialect: str
|
|
28
|
+
host: str = Field(default="127.0.0.1", description="Database server hostname (SQLAlchemy URL).")
|
|
29
|
+
port: int = Field(default=5432, description="Database server port (SQLAlchemy URL).")
|
|
30
|
+
username: str
|
|
31
|
+
database: str
|
|
32
|
+
read_only: bool = Field(default=False, description="When true, only read-style SQL is allowed.")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class SettingsPublic(BaseModel):
|
|
36
|
+
"""Configuration returned by ``GET /settings`` (nested shape; database password omitted)."""
|
|
37
|
+
|
|
38
|
+
model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
|
|
39
|
+
|
|
40
|
+
server: ServerConfigPublic
|
|
41
|
+
database: DatabaseConfigPublic
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class RunDbQueryRequest(BaseModel):
|
|
45
|
+
"""Body for ``POST /query`` — raw SQL and optional bind parameters."""
|
|
46
|
+
|
|
47
|
+
model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
|
|
48
|
+
|
|
49
|
+
sql: str = Field(..., description="SQL statement to execute.")
|
|
50
|
+
params: dict[str, Any] | None = Field(
|
|
51
|
+
default=None,
|
|
52
|
+
description="Optional named parameters for bound placeholders in ``sql``.",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class RunDbQueryOutput(BaseModel):
|
|
57
|
+
"""Structured result for ``run_db_query``-style tooling (matches agent_server shape)."""
|
|
58
|
+
|
|
59
|
+
model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
|
|
60
|
+
|
|
61
|
+
success: bool = Field(..., description="Whether the query completed successfully.")
|
|
62
|
+
error: str | None = Field(
|
|
63
|
+
default=None,
|
|
64
|
+
description="Error message when ``success`` is false.",
|
|
65
|
+
)
|
|
66
|
+
columns: list[str] | None = Field(
|
|
67
|
+
default=None,
|
|
68
|
+
description="Column names in order for row-returning queries.",
|
|
69
|
+
)
|
|
70
|
+
rows: list[list[Any]] | None = Field(
|
|
71
|
+
default=None,
|
|
72
|
+
description="Row values aligned with ``columns`` (list of lists).",
|
|
73
|
+
)
|
|
74
|
+
row_count: int | None = Field(
|
|
75
|
+
default=None,
|
|
76
|
+
description="Number of rows returned or affected, depending on query type.",
|
|
77
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Command-line interface for talktodb-api-connector."""
|