Skip to content

Commit 4e84794

Browse files
authored
test: Add tests for DuckDB (#21)
1 parent ee1f6d2 commit 4e84794

12 files changed

Lines changed: 61 additions & 23 deletions

File tree

.github/workflows/ci.yml

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,14 @@ jobs:
4242
fail-fast: false
4343
matrix:
4444
environment: [py311, py312, py313]
45-
database: [sqlite, mssql]
45+
database: [sqlite, mssql, duckdb]
46+
include:
47+
- database: sqlite
48+
connection-string: sqlite:///test.sqlite3
49+
- database: mssql
50+
connection-string: mssql+pyodbc://sa:Passw0rd@localhost:1433/master?driver=ODBC+Driver+18+for+SQL+Server&Encrypt=no
51+
- database: duckdb
52+
connection-string: duckdb:///test.duckdb
4653
steps:
4754
- name: Checkout branch
4855
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
@@ -55,14 +62,10 @@ jobs:
5562
uses: prefix-dev/setup-pixi@ba3bb36eb2066252b2363392b7739741bb777659 # v0.8.1
5663
with:
5764
environments: ${{ matrix.environment }}
65+
activate-environment: true
5866
- name: Install repository
59-
run: pixi run -e ${{ matrix.environment }} postinstall
60-
- name: Set DB connection string
61-
run: |
62-
if [ "${{ matrix.database }}" == "sqlite" ]; then
63-
echo "DB_CONNECTION_STRING=sqlite:///test.sqlite3" >> $GITHUB_ENV
64-
else
65-
echo "DB_CONNECTION_STRING=mssql+pyodbc://sa:Passw0rd@localhost:1433/master?driver=ODBC+Driver+18+for+SQL+Server&Encrypt=no" >> $GITHUB_ENV
66-
fi
67+
run: pixi run postinstall
6768
- name: Run pytest
68-
run: pixi run -e ${{ matrix.environment }} test-coverage --color=yes
69+
run: pixi run test-coverage --color=yes
70+
env:
71+
DB_CONNECTION_STRING: ${{ matrix.connection-string }}

sqlcompyre/analysis/dialects/__init__.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) QuantCo 2024-2024
1+
# Copyright (c) QuantCo 2024-2025
22
# SPDX-License-Identifier: BSD-3-Clause
33

44
from sqlalchemy.dialects import registry
@@ -37,3 +37,18 @@
3737
)
3838
except ImportError:
3939
pass
40+
41+
# -------------------------------------------------------------------------------------------------
42+
# DuckDB
43+
# -------------------------------------------------------------------------------------------------
44+
45+
try:
46+
from .duckdb import DuckDBDialect # noqa
47+
48+
registry.register(
49+
"duckdb",
50+
"sqlcompyre.analysis.dialects",
51+
"DuckDBDialect",
52+
)
53+
except ImportError:
54+
pass
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright (c) QuantCo 2025-2025
2+
# SPDX-License-Identifier: BSD-3-Clause
3+
4+
from duckdb_engine import Dialect as SqlAlchemyDuckdbDialect
5+
6+
from ._base import DialectProtocol
7+
8+
9+
class DuckDBDialect(SqlAlchemyDuckdbDialect, DialectProtocol): # type: ignore
10+
name: str = "duckdb"
11+
verbose_name: str = "DuckDB"
12+
supports_schemas: bool = False
13+
supports_multi_part_schemas: bool = False
14+
case_sensitive_collation: str = "BINARY"
15+
case_insensitive_collation: str = "NOCASE"
16+
views_support_notnull_columns: bool = False

tests/_shared/dialects.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,9 @@ def dialect_from_connection_url(conn_url: sa.URL) -> DialectProtocol:
3333
from sqlcompyre.analysis.dialects import SQLiteDialect
3434

3535
return SQLiteDialect()
36+
case "duckdb":
37+
from sqlcompyre.analysis.dialects import DuckDBDialect
38+
39+
return DuckDBDialect() # type: ignore
3640
case _:
3741
raise NotImplementedError

tests/analysis/dialects/test_mssql.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919

2020
def table_columns() -> list[sa.Column]:
21-
return [sa.Column("id", sa.Integer(), primary_key=True)]
21+
return [sa.Column("id", sa.Integer(), primary_key=True, autoincrement=False)]
2222

2323

2424
@pytest.fixture(scope="session")

tests/analysis/schema_comparison/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
def table_columns() -> list[sa.Column]:
1313
return [
14-
sa.Column("id", sa.Integer(), primary_key=True),
14+
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=False),
1515
sa.Column("value", sa.Integer()),
1616
]
1717

tests/analysis/table_comparison/conftest.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
def base_columns() -> list[sa.Column]:
2121
return [
22-
sa.Column("id", sa.Integer(), primary_key=True),
22+
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=False),
2323
sa.Column("name", sa.String(length=50)),
2424
sa.Column("age", sa.Integer()),
2525
sa.Column("gpa", sa.Float()),
@@ -28,7 +28,7 @@ def base_columns() -> list[sa.Column]:
2828

2929
def alt_columns() -> list[sa.Column]:
3030
return [
31-
sa.Column("id_v2", sa.Integer(), primary_key=True),
31+
sa.Column("id_v2", sa.Integer(), primary_key=True, autoincrement=False),
3232
sa.Column("name_v2", sa.String(length=50)),
3333
sa.Column("age_v2", sa.Integer()),
3434
sa.Column("gpa_v2", sa.Float()),
@@ -37,7 +37,7 @@ def alt_columns() -> list[sa.Column]:
3737

3838
def alt_columns_small() -> list[sa.Column]:
3939
return [
40-
sa.Column("id", sa.Integer(), primary_key=True),
40+
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=False),
4141
sa.Column("name", sa.String(length=50)),
4242
sa.Column("age_v2", sa.Integer()),
4343
sa.Column("gpa_v2", sa.Float()),
@@ -46,7 +46,7 @@ def alt_columns_small() -> list[sa.Column]:
4646

4747
def cased_columns() -> list[sa.Column]:
4848
return [
49-
sa.Column("Id", sa.Integer(), primary_key=True),
49+
sa.Column("Id", sa.Integer(), primary_key=True, autoincrement=False),
5050
sa.Column("Name", sa.String(length=50)),
5151
sa.Column("Age", sa.Integer()),
5252
sa.Column("Gpa", sa.Float()),

tests/analysis/table_comparison/test_by_column.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
def table_columns() -> list[sa.Column]:
2222
return [
23-
sa.Column("id", sa.Integer(), primary_key=True),
23+
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=False),
2424
sa.Column("value", sa.Integer(), nullable=True),
2525
sa.Column("value_1", sa.Integer(), nullable=True),
2626
]

tests/analysis/table_comparison/test_null_values.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
def table_columns() -> list[sa.Column]:
2121
return [
22-
sa.Column("id", sa.Integer(), primary_key=True),
22+
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=False),
2323
sa.Column("value", sa.Integer(), nullable=True),
2424
]
2525

tests/analysis/table_comparison/test_only_primary_key.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919

2020
def table_columns() -> list[sa.Column]:
21-
return [sa.Column("id", sa.Integer(), primary_key=True)]
21+
return [sa.Column("id", sa.Integer(), primary_key=True, autoincrement=False)]
2222

2323

2424
@pytest.fixture(scope="module")

0 commit comments

Comments
 (0)