Skip to content
This repository was archived by the owner on Mar 16, 2026. It is now read-only.

Commit c983948

Browse files
committed
refactor of the test_cases
1 parent 2355811 commit c983948

File tree

1 file changed

+138
-74
lines changed

1 file changed

+138
-74
lines changed

tests/unit/test__types.py

Lines changed: 138 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,35 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
import pytest
2-
from google.cloud.bigquery.schema import SchemaField
316

4-
from sqlalchemy_bigquery._types import _get_transitive_schema_fields, STRUCT_FIELD_TYPES
17+
from sqlalchemy_bigquery._types import _get_transitive_schema_fields
18+
from google.cloud.bigquery.schema import SchemaField
519

620

7-
def create_fut(name, field_type, mode="NULLABLE", sub_fields=None):
21+
def create_schema_field_from_dict(schema_dict):
822
"""
9-
Helper function to create a SchemaField object for testing.
10-
`sub_fields` should be a list of already created SchemaField objects.
23+
Helper function to create a SchemaField object from a dictionary representation.
1124
"""
1225
api_repr = {
13-
"name": name,
14-
"type": field_type,
15-
"mode": mode,
16-
"fields": [sf.to_api_repr() for sf in sub_fields] if sub_fields else [],
26+
"name": schema_dict["name"],
27+
"type": schema_dict["type"],
28+
"mode": schema_dict.get("mode", "NULLABLE"),
29+
"fields": [
30+
create_schema_field_from_dict(sf_dict).to_api_repr()
31+
for sf_dict in schema_dict.get("fields", [])
32+
],
1733
}
1834
return SchemaField.from_api_repr(api_repr)
1935

@@ -22,75 +38,105 @@ def create_fut(name, field_type, mode="NULLABLE", sub_fields=None):
2238
(
2339
"STRUCT field, not REPEATED, with sub-fields, should recurse",
2440
[
25-
create_fut(
26-
"s1",
27-
"STRUCT",
28-
"NULLABLE",
29-
sub_fields=[create_fut("child1", "STRING", "NULLABLE")],
41+
create_schema_field_from_dict(
42+
{
43+
"name": "s1",
44+
"type": "STRUCT",
45+
"mode": "NULLABLE",
46+
"fields": [
47+
{"name": "child1", "type": "STRING", "mode": "NULLABLE"}
48+
],
49+
}
3050
)
3151
],
3252
["s1", "s1.child1"],
3353
),
3454
(
3555
"RECORD field (alias for STRUCT), not REPEATED, with sub-fields, should recurse",
3656
[
37-
create_fut(
38-
"r1",
39-
"RECORD",
40-
"NULLABLE",
41-
sub_fields=[create_fut("child_r1", "INTEGER", "NULLABLE")],
57+
create_schema_field_from_dict(
58+
{
59+
"name": "r1",
60+
"type": "RECORD",
61+
"mode": "NULLABLE",
62+
"fields": [
63+
{"name": "child_r1", "type": "INTEGER", "mode": "NULLABLE"}
64+
],
65+
}
4266
)
4367
],
4468
["r1", "r1.child_r1"],
4569
),
4670
(
4771
"STRUCT field, REPEATED, with sub-fields, should NOT recurse",
4872
[
49-
create_fut(
50-
"s2",
51-
"STRUCT",
52-
"REPEATED",
53-
sub_fields=[create_fut("child2", "STRING", "NULLABLE")],
73+
create_schema_field_from_dict(
74+
{
75+
"name": "s2",
76+
"type": "STRUCT",
77+
"mode": "REPEATED",
78+
"fields": [
79+
{"name": "child2", "type": "STRING", "mode": "NULLABLE"}
80+
],
81+
}
5482
)
5583
],
5684
["s2"],
5785
),
5886
(
5987
"Non-STRUCT field (STRING), not REPEATED, should NOT recurse",
60-
[create_fut("f1", "STRING", "NULLABLE")],
88+
[
89+
create_schema_field_from_dict(
90+
{"name": "f1", "type": "STRING", "mode": "NULLABLE"}
91+
)
92+
],
6193
["f1"],
6294
),
6395
(
6496
"Non-STRUCT field (INTEGER), REPEATED, should NOT recurse",
65-
[create_fut("f2", "INTEGER", "REPEATED")],
97+
[
98+
create_schema_field_from_dict(
99+
{"name": "f2", "type": "INTEGER", "mode": "REPEATED"}
100+
)
101+
],
66102
["f2"],
67103
),
68104
(
69105
"Deeply nested STRUCT, not REPEATED, should recurse fully",
70106
[
71-
create_fut(
72-
"s_outer",
73-
"STRUCT",
74-
"NULLABLE",
75-
sub_fields=[
76-
create_fut(
77-
"s_inner1",
78-
"STRUCT",
79-
"NULLABLE",
80-
sub_fields=[create_fut("s_leaf1", "STRING", "NULLABLE")],
81-
),
82-
create_fut("s_sibling", "INTEGER", "NULLABLE"),
83-
create_fut(
84-
"s_inner2_repeated_struct",
85-
"STRUCT",
86-
"REPEATED",
87-
sub_fields=[
88-
create_fut(
89-
"s_leaf2_ignored", "BOOLEAN", "NULLABLE"
90-
) # This sub-field should be ignored
91-
],
92-
),
93-
],
107+
create_schema_field_from_dict(
108+
{
109+
"name": "s_outer",
110+
"type": "STRUCT",
111+
"mode": "NULLABLE",
112+
"fields": [
113+
{
114+
"name": "s_inner1",
115+
"type": "STRUCT",
116+
"mode": "NULLABLE",
117+
"fields": [
118+
{
119+
"name": "s_leaf1",
120+
"type": "STRING",
121+
"mode": "NULLABLE",
122+
}
123+
],
124+
},
125+
{"name": "s_sibling", "type": "INTEGER", "mode": "NULLABLE"},
126+
{
127+
"name": "s_inner2_repeated_struct",
128+
"type": "STRUCT",
129+
"mode": "REPEATED",
130+
"fields": [
131+
{
132+
"name": "s_leaf2_ignored",
133+
"type": "BOOLEAN",
134+
"mode": "NULLABLE",
135+
}
136+
],
137+
},
138+
],
139+
}
94140
)
95141
],
96142
[
@@ -103,35 +149,45 @@ def create_fut(name, field_type, mode="NULLABLE", sub_fields=None):
103149
),
104150
(
105151
"STRUCT field, not REPEATED, but no sub-fields, should not error and not recurse further",
106-
[create_fut("s3", "STRUCT", "NULLABLE", sub_fields=[])],
152+
[
153+
create_schema_field_from_dict(
154+
{"name": "s3", "type": "STRUCT", "mode": "NULLABLE", "fields": []}
155+
)
156+
],
107157
["s3"],
108158
),
109159
(
110160
"Multiple top-level fields with mixed conditions",
111161
[
112-
create_fut("id", "INTEGER", "REQUIRED"),
113-
create_fut(
114-
"user_profile",
115-
"STRUCT",
116-
"NULLABLE",
117-
sub_fields=[
118-
create_fut("name", "STRING", "NULLABLE"),
119-
create_fut(
120-
"addresses",
121-
"RECORD",
122-
"REPEATED",
123-
sub_fields=[ # addresses is REPEATED STRUCT
124-
create_fut(
125-
"street", "STRING", "NULLABLE"
126-
), # This sub-field should be ignored
127-
create_fut(
128-
"city", "STRING", "NULLABLE"
129-
), # This sub-field should be ignored
130-
],
131-
),
132-
],
162+
create_schema_field_from_dict(
163+
{"name": "id", "type": "INTEGER", "mode": "REQUIRED"}
164+
),
165+
create_schema_field_from_dict(
166+
{
167+
"name": "user_profile",
168+
"type": "STRUCT",
169+
"mode": "NULLABLE",
170+
"fields": [
171+
{"name": "name", "type": "STRING", "mode": "NULLABLE"},
172+
{
173+
"name": "addresses",
174+
"type": "RECORD",
175+
"mode": "REPEATED",
176+
"fields": [
177+
{
178+
"name": "street",
179+
"type": "STRING",
180+
"mode": "NULLABLE",
181+
},
182+
{"name": "city", "type": "STRING", "mode": "NULLABLE"},
183+
],
184+
},
185+
],
186+
}
187+
),
188+
create_schema_field_from_dict(
189+
{"name": "tags", "type": "STRING", "mode": "REPEATED"}
133190
),
134-
create_fut("tags", "STRING", "REPEATED"),
135191
],
136192
["id", "user_profile", "user_profile.name", "user_profile.addresses", "tags"],
137193
),
@@ -142,12 +198,20 @@ def create_fut(name, field_type, mode="NULLABLE", sub_fields=None):
142198
),
143199
(
144200
"Field type not in STRUCT_FIELD_TYPES and mode is REPEATED",
145-
[create_fut("f_arr", "FLOAT", "REPEATED")],
201+
[
202+
create_schema_field_from_dict(
203+
{"name": "f_arr", "type": "FLOAT", "mode": "REPEATED"}
204+
)
205+
],
146206
["f_arr"],
147207
),
148208
(
149209
"Field type not in STRUCT_FIELD_TYPES and mode is not REPEATED",
150-
[create_fut("f_single", "DATE", "NULLABLE")],
210+
[
211+
create_schema_field_from_dict(
212+
{"name": "f_single", "type": "DATE", "mode": "NULLABLE"}
213+
)
214+
],
151215
["f_single"],
152216
),
153217
]

0 commit comments

Comments
 (0)