Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
175d4d1
Add Firebolt Core connection support
devin-ai-integration[bot] Jul 8, 2025
5d851f2
fix: Update Core connection documentation format
devin-ai-integration[bot] Jul 8, 2025
1178d40
fix: Address pre-commit formatting and line length issues
devin-ai-integration[bot] Jul 8, 2025
faf6e87
fix: Resolve line length violation in documentation comment
devin-ai-integration[bot] Jul 8, 2025
15dad9f
fix: Add firebolt-sdk core-support branch dependency for FireboltCore…
devin-ai-integration[bot] Jul 8, 2025
5b08b27
feat: Add Core connection validation and refactor _determine_auth
devin-ai-integration[bot] Jul 8, 2025
85276bd
feat: Add Core integration test workflow and docker setup
devin-ai-integration[bot] Jul 8, 2025
eb3f428
refactor: Reduce cognitive complexity of create_connect_args method
devin-ai-integration[bot] Jul 8, 2025
3337b02
fix additional parameter parsing
ptiurin Jul 8, 2025
11c6ad2
fix tests
ptiurin Jul 8, 2025
71746ca
add core to integration tests
ptiurin Jul 8, 2025
d57b5e2
register custom mark
ptiurin Jul 9, 2025
01b4eb4
docs: Add clarifying comments about SQLAlchemy URL structure mapping
devin-ai-integration[bot] Jul 9, 2025
ef14caf
refactor: Simplify Core connection validation per PR feedback
devin-ai-integration[bot] Jul 9, 2025
8b2ac55
fix: Apply black formatting to resolve CI code-check failure
devin-ai-integration[bot] Jul 9, 2025
65665b5
feat: Add integration tests for Core SDK validation behavior
devin-ai-integration[bot] Jul 9, 2025
57926be
improve tests
ptiurin Jul 9, 2025
d29ac37
fix: Attempt to resolve async dialect event loop conflicts
devin-ai-integration[bot] Jul 9, 2025
500f848
Merge remote-tracking branch 'origin/devin/1751985773-firebolt-core-s…
devin-ai-integration[bot] Jul 9, 2025
7740e63
fix: Update firebolt-sdk dependency to main branch
devin-ai-integration[bot] Jul 9, 2025
23864fe
bump python version
ptiurin Jul 9, 2025
f8a4ae1
remove hack
ptiurin Jul 9, 2025
2c23796
skip
ptiurin Jul 9, 2025
433c50a
use released version
ptiurin Jul 9, 2025
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
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ project_urls =
[options]
packages = find:
install_requires =
firebolt-sdk>=1.5.0
firebolt-sdk@git+https://github.com/firebolt-db/firebolt-python-sdk.git@core-support
sqlalchemy>=1.0.0
python_requires = >=3.8
package_dir =
Expand Down
32 changes: 28 additions & 4 deletions src/firebolt_db/firebolt_dialect.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@

import firebolt.db as dbapi
import sqlalchemy.types as sqltypes
from firebolt.client.auth import Auth, ClientCredentials, UsernamePassword
from firebolt.client.auth import (
Auth,
ClientCredentials,
FireboltCore,
UsernamePassword,
)
from firebolt.db import Cursor
from sqlalchemy.engine import Connection as AlchemyConnection
from sqlalchemy.engine import ExecutionContext, default
Expand Down Expand Up @@ -145,18 +150,33 @@ def create_connect_args(self, url: URL) -> Tuple[List, Dict]:
"""
Build firebolt-sdk compatible connection arguments.
URL format : firebolt://id:secret@host:port/db_name
For Core: firebolt://db_name?url=http://localhost:8080
(full URL including scheme, host, port in url parameter)
"""
parameters = dict(url.query)

is_core_connection = "url" in parameters
core_url = parameters.pop("url", None) if is_core_connection else None

# parameters are all passed as a string, we need to convert
# bool flag to boolean for SDK compatibility
token_cache_flag = bool(strtobool(parameters.pop("use_token_cache", "True")))
auth = _determine_auth(url.username, url.password, token_cache_flag)

if is_core_connection:
auth = _determine_auth("", "", token_cache_flag, is_core=True)
else:
auth = _determine_auth(url.username, url.password, token_cache_flag)

kwargs: Dict[str, Union[str, Auth, Dict[str, Any], None]] = {
"database": url.host or None,
"auth": auth,
"engine_name": url.database,
"additional_parameters": {},
}

if core_url:
kwargs["url"] = core_url

additional_parameters = {}
if "account_name" in parameters:
kwargs["account_name"] = parameters.pop("account_name")
Expand Down Expand Up @@ -366,8 +386,12 @@ def get_is_nullable(column_is_nullable: int) -> bool:
return column_is_nullable == 1


def _determine_auth(key: str, secret: str, token_cache_flag: bool = True) -> Auth:
if "@" in key:
def _determine_auth(
key: str, secret: str, token_cache_flag: bool = True, is_core: bool = False
) -> Auth:
if is_core:
return FireboltCore()
elif "@" in key:
return UsernamePassword(key, secret, token_cache_flag)
else:
return ClientCredentials(key, secret, token_cache_flag)
38 changes: 38 additions & 0 deletions tests/unit/test_firebolt_dialect.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import sqlalchemy
import sqlalchemy.types as sqltypes
from conftest import MockCursor, MockDBApi
from firebolt.client.auth import FireboltCore
from pytest import mark, raises
from sqlalchemy.engine import url
from sqlalchemy.exc import ArgumentError
Expand Down Expand Up @@ -302,6 +303,43 @@ def test_unicode_description(
):
assert dialect._check_unicode_description(connection)

def test_create_connect_args_core_connection(self, dialect: FireboltDialect):
connection_url = (
"test_engine://test_db_name/test_engine_name?" "url=http://localhost:8080"
)
u = url.make_url(connection_url)
result_list, result_dict = dialect.create_connect_args(u)

assert result_dict["engine_name"] == "test_engine_name"
assert result_dict["database"] == "test_db_name"
assert result_dict["url"] == "http://localhost:8080"
assert isinstance(result_dict["auth"], FireboltCore)
assert "account_name" not in result_dict
assert result_list == []

def test_create_connect_args_core_connection_with_database(
self, dialect: FireboltDialect
):
connection_url = "test_engine://test_db_name?" "url=http://localhost:8080"
u = url.make_url(connection_url)
result_list, result_dict = dialect.create_connect_args(u)

assert result_dict["database"] == "test_db_name"
assert result_dict["url"] == "http://localhost:8080"
assert isinstance(result_dict["auth"], FireboltCore)
assert result_dict["engine_name"] is None
assert result_list == []

def test_create_connect_args_core_no_credentials_required(
self, dialect: FireboltDialect
):
connection_url = "test_engine://test_db_name?url=http://localhost:8080"
u = url.make_url(connection_url)

result_list, result_dict = dialect.create_connect_args(u)
assert isinstance(result_dict["auth"], FireboltCore)
assert "account_name" not in result_dict


def test_get_is_nullable():
assert firebolt_db.firebolt_dialect.get_is_nullable(1)
Expand Down