Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,11 @@ SDK
Dependabot
PyPI
pypi
pymssql
sqlserver
SQLServerLoader
dbo
tsql
hostname
TLS
sqlglot
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ e2e/.auth/
# Build artifacts
clients/python/queryweaver_client.egg-info/
clients/ts/dist/
wordlist.dic
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ async def main():
# Initialize with FalkorDB connection
qw = QueryWeaver(falkordb_url="redis://localhost:6379")

# Connect a PostgreSQL or MySQL database
# Connect a PostgreSQL, MySQL, SQL Server or Snowflake database
conn = await qw.connect_database("postgresql://user:pass@host:5432/mydb")
print(f"Connected: {conn.database_id}") # "mydb"

Expand Down Expand Up @@ -310,7 +310,7 @@ async with QueryWeaver(falkordb_url="redis://host-a:6379", user_id="tenant_a") a

| Method | Description |
|--------|-------------|
| `connect_database(db_url)` | Connect PostgreSQL/MySQL and load schema |
| `connect_database(db_url)` | Connect PostgreSQL/MySQL/SQL Server/Snowflake and load schema |
| `query(database, question)` | Convert natural language to SQL and execute |
| `get_schema(database)` | Retrieve database schema (tables and relationships) |
| `list_databases()` | List all connected databases |
Expand Down Expand Up @@ -356,7 +356,7 @@ if result.requires_confirmation:
- Python 3.12+
- FalkorDB instance (local or remote)
- OpenAI or Azure OpenAI API key (for LLM)
- Target SQL database (PostgreSQL or MySQL)
- Target SQL database (PostgreSQL, MySQL, SQL Server or Snowflake)

## Development

Expand Down
18 changes: 16 additions & 2 deletions api/core/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,9 @@ def get_database_type_and_loader(
PostgreSQL for backward compatibility on the server path.

When ``sdk_only`` is True, raises ``InvalidArgumentError`` for vendors
that need the ``[server]`` extra (snowflake) or for unknown URL schemes,
so SDK callers get a clean error instead of a deferred ``ImportError``.
that need the ``[server]`` extra (snowflake, sqlserver) or for unknown URL
schemes, so SDK callers get a clean error instead of a deferred
``ImportError``.
"""
if not db_url or db_url == "No URL available for this database.":
return None, None
Expand All @@ -138,6 +139,17 @@ def get_database_type_and_loader(
# pylint: disable=import-outside-toplevel
from api.loaders.snowflake_loader import SnowflakeLoader
return 'snowflake', SnowflakeLoader
if db_url_lower.startswith('sqlserver://'):
if sdk_only:
raise InvalidArgumentError(
"SQL Server requires the [server] extra: "
"pip install queryweaver[server]"
)
# Lazy-import: pymssql is in the [server] extra, not in the core SDK
# install.
# pylint: disable=import-outside-toplevel
from api.loaders.sqlserver_loader import SQLServerLoader
return 'sqlserver', SQLServerLoader

if sdk_only:
raise InvalidArgumentError(
Expand Down Expand Up @@ -205,6 +217,8 @@ def truncate_for_log(query: str, max_length: int = 200) -> str:
"postgres": "postgres",
"mysql": "mysql",
"snowflake": "snowflake",
"sqlserver": "tsql",
"mssql": "tsql",
}

# sqlglot expression class names that represent a write, DDL, privilege change,
Expand Down
4 changes: 3 additions & 1 deletion api/core/schema_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ def _step_start(steps_counter: int) -> dict[str, str]:
"message": f"Step {steps_counter}: Starting database connection",
}

_KNOWN_DB_SCHEMES = ("postgresql://", "postgres://", "mysql://", "snowflake://")
_KNOWN_DB_SCHEMES = (
"postgresql://", "postgres://", "mysql://", "snowflake://", "sqlserver://",
)


def _step_detect_db_type(steps_counter: int, url: str) -> tuple[type[BaseLoader], dict[str, str]]:
Expand Down
Loading
Loading