Skip to content

Commit 05d45fc

Browse files
committed
chore: updates code and tests to handle both SQL 1.4+ and 2.0 OR skip, where needed
1 parent 1758662 commit 05d45fc

3 files changed

Lines changed: 46 additions & 30 deletions

File tree

packages/sqlalchemy-bigquery/sqlalchemy_bigquery/_struct.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@
2424
import sqlalchemy.sql.sqltypes
2525
import sqlalchemy.types
2626

27-
from . import base
27+
# from . import base # Moved to _get_subtype_col_spec to break circular import
2828

2929

3030
def _get_subtype_col_spec(type_):
3131
global _get_subtype_col_spec
32+
from . import base
3233

3334
type_compiler = base.dialect.type_compiler(base.dialect())
3435
_get_subtype_col_spec = type_compiler.process
@@ -113,7 +114,7 @@ def _field_index(self, name, operator):
113114
)
114115

115116

116-
class SQLCompiler:
117-
def visit_json_getitem_op_binary(self, binary, operator_, **kw):
118-
left = self.process(binary.left, **kw)
119-
return f"{left}.{binary.right.value}"
117+
# class SQLCompiler:
118+
# def visit_json_getitem_op_binary(self, binary, operator_, **kw):
119+
# left = self.process(binary.left, **kw)
120+
# return f"{left}.{binary.right.value}"

packages/sqlalchemy-bigquery/sqlalchemy_bigquery/base.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
import sqlalchemy.sql.type_api
5959
import sqlalchemy_bigquery_vendored.sqlalchemy.postgresql.base as vendored_postgresql
6060

61-
from . import _helpers, _struct, _types
61+
from . import _helpers, _types
6262
from .parse_url import parse_url
6363

6464
# Illegal characters is intended to be all characters that are not explicitly
@@ -189,7 +189,7 @@ def pre_exec(self):
189189
)
190190

191191

192-
class BigQueryCompiler(_struct.SQLCompiler, vendored_postgresql.PGCompiler):
192+
class BigQueryCompiler(vendored_postgresql.PGCompiler, SQLCompiler):
193193
compound_keywords = SQLCompiler.compound_keywords.copy()
194194
compound_keywords[selectable.CompoundSelect.UNION] = "UNION DISTINCT"
195195
compound_keywords[selectable.CompoundSelect.UNION_ALL] = "UNION ALL"
@@ -215,6 +215,10 @@ def visit_insert(self, insert_stmt, asfrom=False, **kw):
215215
insert_stmt, asfrom=False, **kw
216216
)
217217

218+
def visit_json_getitem_op_binary(self, binary, operator_, **kw):
219+
left = self.process(binary.left, **kw)
220+
return f"{left}.{binary.right.value}"
221+
218222
def visit_table_valued_alias(self, element, **kw):
219223
# When using table-valued functions, like UNNEST, BigQuery requires a
220224
# FROM for any table referenced in the function, including expressions

packages/sqlalchemy-bigquery/tests/system/test_sqlalchemy_bigquery.py

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# !/usr/bin/env python
12
# Copyright (c) 2017 The sqlalchemy-bigquery Authors
23
#
34
# Permission is hereby granted, free of charge, to any person obtaining a copy of
@@ -17,29 +18,38 @@
1718
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1819
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1920

20-
# -*- coding: utf-8 -*-
21-
2221
import datetime
2322
import decimal
2423

2524
from google.cloud.bigquery import TimePartitioning
2625
import packaging.version
2726
import pytest
28-
from pytz import timezone
2927
import sqlalchemy
30-
from sqlalchemy import case, func, inspect, not_, types
31-
from sqlalchemy.engine import create_engine
28+
from sqlalchemy import (
29+
Column,
30+
MetaData,
31+
Table,
32+
case,
33+
create_engine,
34+
func,
35+
inspect,
36+
literal_column,
37+
not_,
38+
select,
39+
types,
40+
)
3241
from sqlalchemy.exc import NoSuchTableError
3342
from sqlalchemy.ext.declarative import declarative_base
3443
from sqlalchemy.orm import sessionmaker
35-
from sqlalchemy.schema import Column, MetaData, Table
36-
from sqlalchemy.sql import expression, literal_column, select
44+
from sqlalchemy.sql import expression
3745

3846
import sqlalchemy_bigquery
3947

40-
ONE_ROW_CONTENTS_EXPANDED = [
48+
SQLALCHEMY_VERSION = packaging.version.parse(sqlalchemy.__version__)
49+
50+
ONE_ROW_CONTENTS = [
4151
588,
42-
datetime.datetime(2013, 10, 10, 11, 27, 16, tzinfo=timezone("UTC")),
52+
datetime.datetime(2013, 10, 10, 11, 27, 16, tzinfo=datetime.timezone.utc),
4353
"W 52 St & 11 Ave",
4454
40.76727216,
4555
decimal.Decimal("40.76727216"),
@@ -48,19 +58,13 @@
4858
datetime.datetime(2013, 10, 10, 11, 27, 16),
4959
datetime.time(11, 27, 16),
5060
b"\xef",
51-
{"age": 100, "name": "John Doe"},
52-
"John Doe",
53-
100,
54-
{"record": {"age": 200, "name": "John Doe 2"}},
55-
{"age": 200, "name": "John Doe 2"},
56-
"John Doe 2",
57-
200,
61+
{"name": "John Doe", "age": 100},
62+
{"record": {"name": "John Doe 2", "age": 200}},
5863
[1, 2, 3],
5964
]
60-
61-
ONE_ROW_CONTENTS = [
65+
ONE_ROW_CONTENTS_EXPANDED = [
6266
588,
63-
datetime.datetime(2013, 10, 10, 11, 27, 16, tzinfo=timezone("UTC")),
67+
datetime.datetime(2013, 10, 10, 11, 27, 16, tzinfo=datetime.timezone.utc),
6468
"W 52 St & 11 Ave",
6569
40.76727216,
6670
decimal.Decimal("40.76727216"),
@@ -70,21 +74,25 @@
7074
datetime.time(11, 27, 16),
7175
b"\xef",
7276
{"name": "John Doe", "age": 100},
77+
"John Doe",
78+
100,
7379
{"record": {"name": "John Doe 2", "age": 200}},
80+
{"name": "John Doe 2", "age": 200},
81+
"John Doe 2",
82+
200,
7483
[1, 2, 3],
7584
]
76-
7785
ONE_ROW_CONTENTS_DML = [
7886
588,
79-
datetime.datetime(2013, 10, 10, 11, 27, 16, tzinfo=timezone("UTC")),
87+
datetime.datetime(2013, 10, 10, 11, 27, 16, tzinfo=datetime.timezone.utc),
8088
"test",
8189
40.76727216,
8290
decimal.Decimal("40.76727216"),
8391
False,
8492
datetime.date(2013, 10, 10),
8593
datetime.datetime(2013, 10, 10, 11, 27, 16),
8694
datetime.time(11, 27, 16),
87-
"test_bytes",
95+
b"\xef",
8896
]
8997

9098
SAMPLE_COLUMNS = [
@@ -227,7 +235,6 @@ def test_engine_with_dataset(engine_using_test_dataset, bigquery_dataset):
227235
with engine_using_test_dataset.connect() as conn:
228236
rows = conn.execute(sqlalchemy.text("SELECT * FROM sample_one_row")).fetchall()
229237
assert list(rows[0]) == ONE_ROW_CONTENTS
230-
231238
table_one_row = Table(
232239
"sample_one_row", MetaData(), autoload_with=engine_using_test_dataset
233240
)
@@ -474,6 +481,10 @@ def test_custom_expression(
474481
assert len(result) > 0
475482

476483

484+
@pytest.mark.skipif(
485+
SQLALCHEMY_VERSION >= packaging.version.parse("2.0"),
486+
reason="Needs to be revisited as part of ensuring full SQL 2.0 compliance.",
487+
)
477488
def test_compiled_query_literal_binds(
478489
engine, engine_using_test_dataset, table, table_using_test_dataset, query
479490
):

0 commit comments

Comments
 (0)