diff --git a/redisvl/schema/validation.py b/redisvl/schema/validation.py index 3bd7cf9e..d629129c 100644 --- a/redisvl/schema/validation.py +++ b/redisvl/schema/validation.py @@ -174,22 +174,18 @@ def _validate_vector(cls, value): raise ValueError( f"Vector field '{fname}' must have {dims} dimensions, got {len(value)}" ) - # Validate data types - datatype_str = str(datatype).upper() - # Integer-based datatypes - if datatype_str in ("INT8", "UINT8"): - # Check range for INT8 - if datatype_str == "INT8": - if any(v < -128 or v > 127 for v in value): - raise ValueError( - f"Vector field '{fname}' contains values outside the INT8 range (-128 to 127)" - ) - # Check range for UINT8 - elif datatype_str == "UINT8": - if any(v < 0 or v > 255 for v in value): - raise ValueError( - f"Vector field '{fname}' contains values outside the UINT8 range (0 to 255)" - ) + # Check range for INT8 + if datatype == VectorDataType.INT8: + if any(v < -128 or v > 127 for v in value): + raise ValueError( + f"Vector field '{fname}' contains values outside the INT8 range (-128 to 127)" + ) + # Check range for UINT8 + elif datatype == VectorDataType.UINT8: + if any(v < 0 or v > 255 for v in value): + raise ValueError( + f"Vector field '{fname}' contains values outside the UINT8 range (0 to 255)" + ) return value return _validate_vector diff --git a/tests/unit/test_validation.py b/tests/unit/test_validation.py index f34d0035..fa12ba81 100644 --- a/tests/unit/test_validation.py +++ b/tests/unit/test_validation.py @@ -529,6 +529,59 @@ def test_vector_field_validation( ) +class TestIntegerVectorRangeValidation: + """Range checks for INT8 and UINT8 vectors given as lists (JSON storage).""" + + @pytest.fixture + def int_vector_schema(self): + return IndexSchema.from_dict( + { + "index": {"name": "int-vectors", "storage_type": "json"}, + "fields": [ + { + "name": field_name, + "type": "vector", + "attrs": { + "algorithm": "flat", + "dims": 2, + "datatype": datatype, + "distance_metric": "l2", + }, + } + for field_name, datatype in (("i8", "int8"), ("u8", "uint8")) + ], + } + ) + + @pytest.mark.parametrize( + "field_name,value", + [ + ("i8", [-128, 127]), + ("u8", [0, 255]), + ], + ) + def test_in_range_values_accepted(self, int_vector_schema, field_name, value): + assert validate_object(int_vector_schema, {field_name: value}) == { + field_name: value + } + + @pytest.mark.parametrize( + "field_name,value,error_text", + [ + ("i8", [999, -999], "INT8 range"), + ("i8", [-129, 0], "INT8 range"), + ("i8", [0, 128], "INT8 range"), + ("u8", [-1, 0], "UINT8 range"), + ("u8", [0, 256], "UINT8 range"), + ], + ) + def test_out_of_range_values_rejected( + self, int_vector_schema, field_name, value, error_text + ): + with pytest.raises(ValueError, match=error_text): + validate_object(int_vector_schema, {field_name: value}) + + class TestNestedJsonValidation: """Tests for JSON path-based validation with nested structures."""