Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit74e75e8

Browse files
authored
feat: support insertAll for range (#1909)
* feat: support insertAll for range* revert INTERVAL regex* lint* add unit test* lint
1 parent0e39066 commit74e75e8

File tree

2 files changed

+162
-4
lines changed

2 files changed

+162
-4
lines changed

‎google/cloud/bigquery/_helpers.py‎

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
r"(?P<days>-?\d+) "
5151
r"(?P<time_sign>-?)(?P<hours>\d+):(?P<minutes>\d+):(?P<seconds>\d+)\.?(?P<fraction>\d*)?$"
5252
)
53+
_RANGE_PATTERN=re.compile(r"\[.*, .*\)")
5354

5455
BIGQUERY_EMULATOR_HOST="BIGQUERY_EMULATOR_HOST"
5556
"""Environment variable defining host for emulator."""
@@ -334,9 +335,8 @@ def _range_from_json(value, field):
334335
The parsed range object from ``value`` if the ``field`` is not
335336
null (otherwise it is :data:`None`).
336337
"""
337-
range_literal=re.compile(r"\[.*, .*\)")
338338
if_not_null(value,field):
339-
ifrange_literal.match(value):
339+
if_RANGE_PATTERN.match(value):
340340
start,end=value[1:-1].split(", ")
341341
start=_range_element_from_json(start,field.range_element_type)
342342
end=_range_element_from_json(end,field.range_element_type)
@@ -531,6 +531,52 @@ def _time_to_json(value):
531531
returnvalue
532532

533533

534+
def_range_element_to_json(value,element_type=None):
535+
"""Coerce 'value' to an JSON-compatible representation."""
536+
ifvalueisNone:
537+
returnNone
538+
elifisinstance(value,str):
539+
ifvalue.upper()in ("UNBOUNDED","NULL"):
540+
returnNone
541+
else:
542+
# We do not enforce range element value to be valid to reduce
543+
# redundancy with backend.
544+
returnvalue
545+
elif (
546+
element_typeandelement_type.element_type.upper()in_SUPPORTED_RANGE_ELEMENTS
547+
):
548+
converter=_SCALAR_VALUE_TO_JSON_ROW.get(element_type.element_type.upper())
549+
returnconverter(value)
550+
else:
551+
raiseValueError(
552+
f"Unsupported RANGE element type{element_type}, or "
553+
"element type is empty. Must be DATE, DATETIME, or "
554+
"TIMESTAMP"
555+
)
556+
557+
558+
def_range_field_to_json(range_element_type,value):
559+
"""Coerce 'value' to an JSON-compatible representation."""
560+
ifisinstance(value,str):
561+
# string literal
562+
if_RANGE_PATTERN.match(value):
563+
start,end=value[1:-1].split(", ")
564+
else:
565+
raiseValueError(f"RANGE literal{value} has incorrect format")
566+
elifisinstance(value,dict):
567+
# dictionary
568+
start=value.get("start")
569+
end=value.get("end")
570+
else:
571+
raiseValueError(
572+
f"Unsupported type of RANGE value{value}, must be ""string or dict"
573+
)
574+
575+
start=_range_element_to_json(start,range_element_type)
576+
end=_range_element_to_json(end,range_element_type)
577+
return {"start":start,"end":end}
578+
579+
534580
# Converters used for scalar values marshalled to the BigQuery API, such as in
535581
# query parameters or the tabledata.insert API.
536582
_SCALAR_VALUE_TO_JSON_ROW= {
@@ -676,6 +722,8 @@ def _single_field_to_json(field, row_value):
676722

677723
iffield.field_type=="RECORD":
678724
return_record_field_to_json(field.fields,row_value)
725+
iffield.field_type=="RANGE":
726+
return_range_field_to_json(field.range_element_type,row_value)
679727

680728
return_scalar_field_to_json(field,row_value)
681729

‎tests/unit/test__helpers.py‎

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,10 +1049,22 @@ def test_w_datetime(self):
10491049
self.assertEqual(self._call_fut(when),"12:13:41")
10501050

10511051

1052-
def_make_field(field_type,mode="NULLABLE",name="testing",fields=()):
1052+
def_make_field(
1053+
field_type,
1054+
mode="NULLABLE",
1055+
name="testing",
1056+
fields=(),
1057+
range_element_type=None,
1058+
):
10531059
fromgoogle.cloud.bigquery.schemaimportSchemaField
10541060

1055-
returnSchemaField(name=name,field_type=field_type,mode=mode,fields=fields)
1061+
returnSchemaField(
1062+
name=name,
1063+
field_type=field_type,
1064+
mode=mode,
1065+
fields=fields,
1066+
range_element_type=range_element_type,
1067+
)
10561068

10571069

10581070
classTest_scalar_field_to_json(unittest.TestCase):
@@ -1251,6 +1263,98 @@ def test_w_dict_unknown_fields(self):
12511263
)
12521264

12531265

1266+
classTest_range_field_to_json(unittest.TestCase):
1267+
def_call_fut(self,field,value):
1268+
fromgoogle.cloud.bigquery._helpersimport_range_field_to_json
1269+
1270+
return_range_field_to_json(field,value)
1271+
1272+
deftest_w_date(self):
1273+
field=_make_field("RANGE",range_element_type="DATE")
1274+
start=datetime.date(2016,12,3)
1275+
original= {"start":start}
1276+
converted=self._call_fut(field.range_element_type,original)
1277+
expected= {"start":"2016-12-03","end":None}
1278+
self.assertEqual(converted,expected)
1279+
1280+
deftest_w_date_string(self):
1281+
field=_make_field("RANGE",range_element_type="DATE")
1282+
original= {"start":"2016-12-03"}
1283+
converted=self._call_fut(field.range_element_type,original)
1284+
expected= {"start":"2016-12-03","end":None}
1285+
self.assertEqual(converted,expected)
1286+
1287+
deftest_w_datetime(self):
1288+
field=_make_field("RANGE",range_element_type="DATETIME")
1289+
start=datetime.datetime(2016,12,3,14,11,27,123456)
1290+
original= {"start":start}
1291+
converted=self._call_fut(field.range_element_type,original)
1292+
expected= {"start":"2016-12-03T14:11:27.123456","end":None}
1293+
self.assertEqual(converted,expected)
1294+
1295+
deftest_w_datetime_string(self):
1296+
field=_make_field("RANGE",range_element_type="DATETIME")
1297+
original= {"start":"2016-12-03T14:11:27.123456"}
1298+
converted=self._call_fut(field.range_element_type,original)
1299+
expected= {"start":"2016-12-03T14:11:27.123456","end":None}
1300+
self.assertEqual(converted,expected)
1301+
1302+
deftest_w_timestamp(self):
1303+
fromgoogle.cloud._helpersimportUTC
1304+
1305+
field=_make_field("RANGE",range_element_type="TIMESTAMP")
1306+
start=datetime.datetime(2016,12,3,14,11,27,123456,tzinfo=UTC)
1307+
original= {"start":start}
1308+
converted=self._call_fut(field.range_element_type,original)
1309+
expected= {"start":"2016-12-03T14:11:27.123456Z","end":None}
1310+
self.assertEqual(converted,expected)
1311+
1312+
deftest_w_timestamp_string(self):
1313+
field=_make_field("RANGE",range_element_type="TIMESTAMP")
1314+
original= {"start":"2016-12-03T14:11:27.123456Z"}
1315+
converted=self._call_fut(field.range_element_type,original)
1316+
expected= {"start":"2016-12-03T14:11:27.123456Z","end":None}
1317+
self.assertEqual(converted,expected)
1318+
1319+
deftest_w_timestamp_float(self):
1320+
field=_make_field("RANGE",range_element_type="TIMESTAMP")
1321+
original= {"start":12.34567}
1322+
converted=self._call_fut(field.range_element_type,original)
1323+
expected= {"start":12.34567,"end":None}
1324+
self.assertEqual(converted,expected)
1325+
1326+
deftest_w_string_literal(self):
1327+
field=_make_field("RANGE",range_element_type="DATE")
1328+
original="[2016-12-03, UNBOUNDED)"
1329+
converted=self._call_fut(field.range_element_type,original)
1330+
expected= {"start":"2016-12-03","end":None}
1331+
self.assertEqual(converted,expected)
1332+
1333+
deftest_w_unsupported_range_element_type(self):
1334+
field=_make_field("RANGE",range_element_type="TIME")
1335+
withself.assertRaises(ValueError):
1336+
self._call_fut(
1337+
field.range_element_type,
1338+
{"start":datetime.time(12,13,41)},
1339+
)
1340+
1341+
deftest_w_no_range_element_type(self):
1342+
field=_make_field("RANGE")
1343+
withself.assertRaises(ValueError):
1344+
self._call_fut(field.range_element_type,"2016-12-03")
1345+
1346+
deftest_w_incorrect_literal_format(self):
1347+
field=_make_field("RANGE",range_element_type="DATE")
1348+
original="[2016-12-03, UNBOUNDED]"
1349+
withself.assertRaises(ValueError):
1350+
self._call_fut(field.range_element_type,original)
1351+
1352+
deftest_w_unsupported_representation(self):
1353+
field=_make_field("RANGE",range_element_type="DATE")
1354+
withself.assertRaises(ValueError):
1355+
self._call_fut(field.range_element_type,object())
1356+
1357+
12541358
classTest_field_to_json(unittest.TestCase):
12551359
def_call_fut(self,field,value):
12561360
fromgoogle.cloud.bigquery._helpersimport_field_to_json
@@ -1285,6 +1389,12 @@ def test_w_scalar(self):
12851389
converted=self._call_fut(field,original)
12861390
self.assertEqual(converted,str(original))
12871391

1392+
deftest_w_range(self):
1393+
field=_make_field("RANGE",range_element_type="DATE")
1394+
original= {"start":"2016-12-03","end":"2024-12-03"}
1395+
converted=self._call_fut(field,original)
1396+
self.assertEqual(converted,original)
1397+
12881398

12891399
classTest_snake_to_camel_case(unittest.TestCase):
12901400
def_call_fut(self,value):

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp