Skip to content

Commit 60a2f02

Browse files
committed
always assert against full sql statements
1 parent 3e300f7 commit 60a2f02

5 files changed

Lines changed: 110 additions & 65 deletions

File tree

tests/unit/test_alembic_unit.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,10 @@ def test_create_sql_generation_without_where_clause():
306306
key_field="id",
307307
)
308308
pdb_alembic._create_bm25_index_impl(ops, create_op)
309-
assert "WHERE" not in ops.sql[-1]
309+
assert (
310+
ops.sql[-1]
311+
== 'CREATE INDEX "products_bm25_idx" ON "products" USING bm25 (id, description) WITH (key_field=\'id\')'
312+
)
310313

311314

312315
def test_renderer_emits_where_kwarg():

tests/unit/test_facets_unit.py

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818

1919

2020
def _sql(stmt) -> str:
21-
return str(stmt.compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
21+
sql = str(stmt.compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
22+
return "\n".join(line.rstrip() for line in sql.split("\n")).strip()
2223

2324

2425
def test_metric_and_bucket_builders():
@@ -68,21 +69,27 @@ def test_with_rows_requires_order_and_limit():
6869
def test_with_rows_adds_window_agg_column():
6970
base = select(products.c.id, products.c.description).order_by(products.c.id).limit(10)
7071
stmt = facets.with_rows(base, agg=facets.terms(field="category", size=10), key_field=products.c.id)
71-
sql = _sql(stmt)
72-
73-
assert 'pdb.agg(\'{"terms":{"field":"category","size":10}}\')' in sql
74-
assert "OVER () AS facets" in sql
75-
assert "products.id @@@ pdb.all()" in sql
72+
assert (
73+
_sql(stmt)
74+
== """\
75+
SELECT products.id, products.description, pdb.agg('{"terms":{"field":"category","size":10}}') OVER () AS facets
76+
FROM products
77+
WHERE products.id @@@ pdb.all() ORDER BY products.id
78+
LIMIT 10"""
79+
)
7680

7781

7882
def test_with_rows_accepts_fetch_clause():
7983
base = select(products.c.id, products.c.description).order_by(products.c.id).fetch(10)
8084
stmt = facets.with_rows(base, agg=facets.terms(field="category", size=10), key_field=products.c.id)
81-
sql = _sql(stmt)
82-
83-
assert "OVER () AS facets" in sql
84-
assert "FETCH FIRST (10) ROWS ONLY" in sql
85-
assert "products.id @@@ pdb.all()" in sql
85+
assert (
86+
_sql(stmt)
87+
== """\
88+
SELECT products.id, products.description, pdb.agg('{"terms":{"field":"category","size":10}}') OVER () AS facets
89+
FROM products
90+
WHERE products.id @@@ pdb.all() ORDER BY products.id
91+
FETCH FIRST (10) ROWS ONLY"""
92+
)
8693

8794

8895
def test_extract_uses_mapping_label():
@@ -104,24 +111,27 @@ def test_percentiles_requires_non_empty_percents():
104111
def test_agg_approximate_true_generates_positional_false():
105112
# approximate=True → skip visibility checks → pass false as second positional arg
106113
stmt = select(pdb.agg(facets.value_count(field="id"), approximate=True))
107-
sql = _sql(stmt)
108-
assert "pdb.agg" in sql
109-
assert "approximate =>" not in sql # must NOT use named-arg form
110-
assert "false" in sql.lower()
114+
assert (
115+
_sql(stmt)
116+
== """\
117+
SELECT pdb.agg('{"value_count":{"field":"id"}}', false) AS agg_1"""
118+
)
111119

112120

113121
def test_agg_approximate_false_generates_positional_true():
114122
# approximate=False → force exact → pass true as second positional arg
115123
stmt = select(pdb.agg(facets.value_count(field="id"), approximate=False))
116-
sql = _sql(stmt)
117-
assert "pdb.agg" in sql
118-
assert "approximate =>" not in sql
119-
assert "true" in sql.lower()
124+
assert (
125+
_sql(stmt)
126+
== """\
127+
SELECT pdb.agg('{"value_count":{"field":"id"}}', true) AS agg_1"""
128+
)
120129

121130

122131
def test_agg_no_approximate_omits_second_arg():
123132
stmt = select(pdb.agg(facets.value_count(field="id")))
124-
sql = _sql(stmt)
125-
assert 'pdb.agg(\'{"value_count":{"field":"id"}}\')' in sql
126-
# Only one argument — no trailing comma with a second value
127-
assert sql.count("pdb.agg(") == 1
133+
assert (
134+
_sql(stmt)
135+
== """\
136+
SELECT pdb.agg('{"value_count":{"field":"id"}}') AS agg_1"""
137+
)

tests/unit/test_indexing_unit.py

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
)
3636

3737

38+
def _sql(sql) -> str:
39+
return "\n".join(line.rstrip() for line in str(sql).split("\n")).strip()
40+
41+
3842
def test_tokenizer_renderers_cover_public_wrappers():
3943
assert tokenize.unicode(alias="description_unicode", lowercase=True, stemmer="english").render() == (
4044
"pdb.unicode_words('alias=description_unicode,lowercase=true,stemmer=english')"
@@ -82,12 +86,11 @@ def test_bm25_index_compile_with_tokenizers():
8286
postgresql_with={"key_field": "id"},
8387
)
8488

85-
sql = str(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
86-
87-
assert "USING bm25" in sql
88-
assert "((description)::pdb.unicode_words('lowercase=true,stemmer=english'))" in sql
89-
assert "((category)::pdb.literal_normalized('alias=category_exact'))" in sql
90-
assert "key_field = id" in sql
89+
assert (
90+
_sql(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
91+
== """\
92+
CREATE INDEX products_bm25_idx ON products USING bm25 (id, ((description)::pdb.unicode_words('lowercase=true,stemmer=english')), ((category)::pdb.literal_normalized('alias=category_exact'))) WITH (key_field = id)"""
93+
)
9194

9295

9396
def test_bm25_index_compile_unicode_omits_none_options():
@@ -99,10 +102,11 @@ def test_bm25_index_compile_unicode_omits_none_options():
99102
postgresql_with={"key_field": "id"},
100103
)
101104

102-
sql = str(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
103-
104-
assert "((description)::pdb.unicode_words('lowercase=true'))" in sql
105-
assert "stemmer=null" not in sql
105+
assert (
106+
_sql(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
107+
== """\
108+
CREATE INDEX products_bm25_idx ON products USING bm25 (id, ((description)::pdb.unicode_words('lowercase=true'))) WITH (key_field = id)"""
109+
)
106110

107111

108112
def test_bm25_index_compile_with_structured_tokenizer_config():
@@ -123,9 +127,11 @@ def test_bm25_index_compile_with_structured_tokenizer_config():
123127
postgresql_using="bm25",
124128
postgresql_with={"key_field": "id"},
125129
)
126-
sql = str(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
127-
128-
assert "((description)::pdb.simple('alias=description_simple,lowercase=true,stemmer=english'))" in sql
130+
assert (
131+
_sql(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
132+
== """\
133+
CREATE INDEX products_bm25_structured_idx ON products USING bm25 (id, ((description)::pdb.simple('alias=description_simple,lowercase=true,stemmer=english'))) WITH (key_field = id)"""
134+
)
129135

130136

131137
def test_bm25_index_compile_with_tokenizer_positional_and_named_args():
@@ -146,9 +152,11 @@ def test_bm25_index_compile_with_tokenizer_positional_and_named_args():
146152
postgresql_using="bm25",
147153
postgresql_with={"key_field": "id"},
148154
)
149-
sql = str(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
150-
151-
assert "((description)::pdb.ngram(3,8,'alias=description_ngram,prefix_only=true,positions=true'))" in sql
155+
assert (
156+
_sql(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
157+
== """\
158+
CREATE INDEX products_bm25_ngram_idx ON products USING bm25 (id, ((description)::pdb.ngram(3,8,'alias=description_ngram,prefix_only=true,positions=true'))) WITH (key_field = id)"""
159+
)
152160

153161

154162
def test_tokenizer_from_config_rejects_non_identifier_tokenizer_name():
@@ -169,9 +177,11 @@ def test_bm25_index_compile_lindera_wrapper():
169177
postgresql_using="bm25",
170178
postgresql_with={"key_field": "id"},
171179
)
172-
sql = str(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
173-
174-
assert "((description)::pdb.lindera('japanese','alias=description_jp'))" in sql
180+
assert (
181+
_sql(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
182+
== """\
183+
CREATE INDEX products_bm25_lindera_idx ON products USING bm25 (id, ((description)::pdb.lindera('japanese','alias=description_jp'))) WITH (key_field = id)"""
184+
)
175185

176186

177187
def test_bm25_index_compile_regex_pattern_wrapper():
@@ -182,9 +192,11 @@ def test_bm25_index_compile_regex_pattern_wrapper():
182192
postgresql_using="bm25",
183193
postgresql_with={"key_field": "id"},
184194
)
185-
sql = str(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
186-
187-
assert "((description)::pdb.regex_pattern('(?i)\\\\bh\\\\w*','alias=description_regex'))" in sql
195+
assert (
196+
_sql(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
197+
== """\
198+
CREATE INDEX products_bm25_regex_idx ON products USING bm25 (id, ((description)::pdb.regex_pattern('(?i)\\\\bh\\\\w*','alias=description_regex'))) WITH (key_field = id)"""
199+
)
188200

189201

190202
def test_bm25_index_compile_json_key_with_tokenizer():
@@ -198,9 +210,11 @@ def test_bm25_index_compile_json_key_with_tokenizer():
198210
postgresql_using="bm25",
199211
postgresql_with={"key_field": "id"},
200212
)
201-
sql = str(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
202-
203-
assert "((metadata ->> 'color')::pdb.literal('alias=metadata_color'))" in sql
213+
assert (
214+
_sql(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
215+
== """\
216+
CREATE INDEX products_bm25_json_idx ON products USING bm25 (id, ((metadata ->> 'color')::pdb.literal('alias=metadata_color'))) WITH (key_field = id)"""
217+
)
204218

205219

206220
def test_bm25_index_compile_multiple_json_keys():
@@ -218,10 +232,11 @@ def test_bm25_index_compile_multiple_json_keys():
218232
postgresql_using="bm25",
219233
postgresql_with={"key_field": "id"},
220234
)
221-
sql = str(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
222-
223-
assert "alias=metadata_color" in sql
224-
assert "alias=metadata_location" in sql
235+
assert (
236+
_sql(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
237+
== """\
238+
CREATE INDEX products_bm25_json_multi_idx ON products USING bm25 (id, ((metadata ->> 'color')::pdb.literal('alias=metadata_color')), ((metadata ->> 'location')::pdb.literal('alias=metadata_location'))) WITH (key_field = id)"""
239+
)
225240

226241

227242
def test_bm25_index_compile_non_text_expression_with_pdb_alias():
@@ -234,9 +249,11 @@ def test_bm25_index_compile_non_text_expression_with_pdb_alias():
234249
postgresql_with={"key_field": "id"},
235250
)
236251

237-
sql = str(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
238-
239-
assert "((id + 1)::pdb.alias('next_id'))" in sql
252+
assert (
253+
_sql(CreateIndex(idx).compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
254+
== """\
255+
CREATE INDEX products_bm25_expr_idx ON products USING bm25 (id, description, ((id + 1)::pdb.alias('next_id'))) WITH (key_field = id)"""
256+
)
240257

241258

242259
def test_bm25_field_non_postgres_compile_raises():

tests/unit/test_phase0_modules_unit.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525

2626

2727
def _sql(stmt) -> str:
28-
return str(stmt.compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
28+
sql = str(stmt.compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
29+
return "\n".join(line.rstrip() for line in sql.split("\n")).strip()
2930

3031

3132
def test_error_hierarchy():
@@ -39,11 +40,18 @@ def test_expr_helpers_compile():
3940
concat_stmt = select(pdb_expr.concat_ws(" ", products.c.category, products.c.description))
4041
json_stmt = select(pdb_expr.json_text(products.c.description.cast(postgresql.JSONB), "kind"))
4142

42-
concat_sql = _sql(concat_stmt)
43-
json_sql = _sql(json_stmt)
44-
45-
assert "concat_ws(' ', products.category, products.description)" in concat_sql
46-
assert "CAST(products.description AS JSONB) ->> 'kind'" in json_sql
43+
assert (
44+
_sql(concat_stmt)
45+
== """\
46+
SELECT concat_ws(' ', products.category, products.description) AS concat_ws_1
47+
FROM products"""
48+
)
49+
assert (
50+
_sql(json_stmt)
51+
== """\
52+
SELECT CAST(products.description AS JSONB) ->> 'kind' AS anon_1
53+
FROM products"""
54+
)
4755

4856

4957
def test_inspect_detects_predicates_in_boolean_tree():

tests/unit/test_validation_cache_unit.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626

2727

2828
def _sql(stmt) -> str:
29-
return str(stmt.compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
29+
sql = str(stmt.compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
30+
return "\n".join(line.rstrip() for line in sql.split("\n")).strip()
3031

3132

3233
def test_search_argument_validation_errors():
@@ -137,8 +138,14 @@ def test_with_rows_does_not_inject_sentinel_when_predicate_exists():
137138
.limit(5)
138139
)
139140
stmt = facets.with_rows(base, agg=facets.value_count(field="id"), key_field=products.c.id)
140-
sql = _sql(stmt)
141-
assert "pdb.all()" not in sql
141+
assert (
142+
_sql(stmt)
143+
== """\
144+
SELECT products.id, pdb.agg('{"value_count":{"field":"id"}}') OVER () AS facets
145+
FROM products
146+
WHERE products.description &&& 'running' ORDER BY products.id
147+
LIMIT 5"""
148+
)
142149

143150

144151
def test_with_rows_limit_guard_ignores_limit_identifier_names():

0 commit comments

Comments
 (0)