Skip to content
Open
Show file tree
Hide file tree
Changes from all 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