Skip to content

Commit

Permalink
feat: add support of float32 type (#1113)
Browse files Browse the repository at this point in the history
* feat: add support of float32 type

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* incorporate changes

* incorporate changes

* handle case for infinity

* fix build

* fix tests

---------

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
  • Loading branch information
rahul2393 and gcf-owl-bot[bot] committed Mar 12, 2024
1 parent a92c6d3 commit 7e0b46a
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 11 deletions.
5 changes: 5 additions & 0 deletions google/cloud/spanner_v1/_helpers.py
Expand Up @@ -228,6 +228,11 @@ def _parse_value_pb(value_pb, field_type):
return float(value_pb.string_value)
else:
return value_pb.number_value
elif type_code == TypeCode.FLOAT32:
if value_pb.HasField("string_value"):
return float(value_pb.string_value)
else:
return value_pb.number_value
elif type_code == TypeCode.DATE:
return _date_from_iso8601_date(value_pb.string_value)
elif type_code == TypeCode.TIMESTAMP:
Expand Down
1 change: 1 addition & 0 deletions google/cloud/spanner_v1/param_types.py
Expand Up @@ -26,6 +26,7 @@
BOOL = Type(code=TypeCode.BOOL)
INT64 = Type(code=TypeCode.INT64)
FLOAT64 = Type(code=TypeCode.FLOAT64)
FLOAT32 = Type(code=TypeCode.FLOAT32)
DATE = Type(code=TypeCode.DATE)
TIMESTAMP = Type(code=TypeCode.TIMESTAMP)
NUMERIC = Type(code=TypeCode.NUMERIC)
Expand Down
1 change: 1 addition & 0 deletions google/cloud/spanner_v1/streamed.py
Expand Up @@ -332,6 +332,7 @@ def _merge_struct(lhs, rhs, type_):
TypeCode.BYTES: _merge_string,
TypeCode.DATE: _merge_string,
TypeCode.FLOAT64: _merge_float64,
TypeCode.FLOAT32: _merge_float64,
TypeCode.INT64: _merge_string,
TypeCode.STRING: _merge_string,
TypeCode.STRUCT: _merge_struct,
Expand Down
3 changes: 3 additions & 0 deletions tests/system/_sample_data.py
Expand Up @@ -90,5 +90,8 @@ def _check_cell_data(found_cell, expected_cell, recurse_into_lists=True):
for found_item, expected_item in zip(found_cell, expected_cell):
_check_cell_data(found_item, expected_item)

elif isinstance(found_cell, float) and not math.isinf(found_cell):
assert abs(found_cell - expected_cell) < 0.00001

else:
assert found_cell == expected_cell
41 changes: 41 additions & 0 deletions tests/system/test_session_api.py
Expand Up @@ -2216,6 +2216,47 @@ def test_execute_sql_w_float_bindings_transfinite(sessions_database, database_di
)


def test_execute_sql_w_float32_bindings(sessions_database, database_dialect):
pytest.skip("float32 is not yet supported in production.")
_bind_test_helper(
sessions_database,
database_dialect,
spanner_v1.param_types.FLOAT32,
42.3,
[12.3, 456.0, 7.89],
)


def test_execute_sql_w_float32_bindings_transfinite(
sessions_database, database_dialect
):
pytest.skip("float32 is not yet supported in production.")
key = "p1" if database_dialect == DatabaseDialect.POSTGRESQL else "neg_inf"
placeholder = "$1" if database_dialect == DatabaseDialect.POSTGRESQL else f"@{key}"

# Find -inf
_check_sql_results(
sessions_database,
sql=f"SELECT {placeholder}",
params={key: NEG_INF},
param_types={key: spanner_v1.param_types.FLOAT32},
expected=[(NEG_INF,)],
order=False,
)

key = "p1" if database_dialect == DatabaseDialect.POSTGRESQL else "pos_inf"
placeholder = "$1" if database_dialect == DatabaseDialect.POSTGRESQL else f"@{key}"
# Find +inf
_check_sql_results(
sessions_database,
sql=f"SELECT {placeholder}",
params={key: POS_INF},
param_types={key: spanner_v1.param_types.FLOAT32},
expected=[(POS_INF,)],
order=False,
)


def test_execute_sql_w_bytes_bindings(sessions_database, database_dialect):
_bind_test_helper(
sessions_database,
Expand Down
21 changes: 21 additions & 0 deletions tests/unit/test__helpers.py
Expand Up @@ -466,6 +466,27 @@ def test_w_float_str(self):

self.assertEqual(self._callFUT(value_pb, field_type), expected_value)

def test_w_float32(self):
from google.cloud.spanner_v1 import Type, TypeCode
from google.protobuf.struct_pb2 import Value

VALUE = 3.14159
field_type = Type(code=TypeCode.FLOAT32)
value_pb = Value(number_value=VALUE)

self.assertEqual(self._callFUT(value_pb, field_type), VALUE)

def test_w_float32_str(self):
from google.cloud.spanner_v1 import Type, TypeCode
from google.protobuf.struct_pb2 import Value

VALUE = "3.14159"
field_type = Type(code=TypeCode.FLOAT32)
value_pb = Value(string_value=VALUE)
expected_value = 3.14159

self.assertEqual(self._callFUT(value_pb, field_type), expected_value)

def test_w_date(self):
import datetime
from google.protobuf.struct_pb2 import Value
Expand Down
21 changes: 10 additions & 11 deletions tests/unit/test_param_types.py
Expand Up @@ -18,9 +18,7 @@

class Test_ArrayParamType(unittest.TestCase):
def test_it(self):
from google.cloud.spanner_v1 import Type
from google.cloud.spanner_v1 import TypeCode
from google.cloud.spanner_v1 import param_types
from google.cloud.spanner_v1 import Type, TypeCode, param_types

expected = Type(
code=TypeCode.ARRAY, array_element_type=Type(code=TypeCode.INT64)
Expand All @@ -33,15 +31,13 @@ def test_it(self):

class Test_Struct(unittest.TestCase):
def test_it(self):
from google.cloud.spanner_v1 import Type
from google.cloud.spanner_v1 import TypeCode
from google.cloud.spanner_v1 import StructType
from google.cloud.spanner_v1 import param_types
from google.cloud.spanner_v1 import StructType, Type, TypeCode, param_types

struct_type = StructType(
fields=[
StructType.Field(name="name", type_=Type(code=TypeCode.STRING)),
StructType.Field(name="count", type_=Type(code=TypeCode.INT64)),
StructType.Field(name="float32", type_=Type(code=TypeCode.FLOAT32)),
]
)
expected = Type(code=TypeCode.STRUCT, struct_type=struct_type)
Expand All @@ -50,6 +46,7 @@ def test_it(self):
[
param_types.StructField("name", param_types.STRING),
param_types.StructField("count", param_types.INT64),
param_types.StructField("float32", param_types.FLOAT32),
]
)

Expand All @@ -58,10 +55,12 @@ def test_it(self):

class Test_JsonbParamType(unittest.TestCase):
def test_it(self):
from google.cloud.spanner_v1 import Type
from google.cloud.spanner_v1 import TypeCode
from google.cloud.spanner_v1 import TypeAnnotationCode
from google.cloud.spanner_v1 import param_types
from google.cloud.spanner_v1 import (
Type,
TypeAnnotationCode,
TypeCode,
param_types,
)

expected = Type(
code=TypeCode.JSON,
Expand Down

0 comments on commit 7e0b46a

Please sign in to comment.