From 84e76f49114764e2c2c3e80aa997b4c24decba6d Mon Sep 17 00:00:00 2001 From: Alexander Lavrukov Date: Sat, 1 Jun 2024 22:59:27 +0300 Subject: [PATCH] main: FieldValue interface --- .../yoj/databind/expression/FieldValue.java | 286 ++---------------- .../yoj/databind/expression/ModelField.java | 30 +- .../expression/values/BoolFieldValue.java | 26 ++ .../values/ByteArrayFieldValue.java | 28 ++ .../expression/values/NumberFieldValue.java | 28 ++ .../expression/values/RealFieldValue.java | 26 ++ .../expression/values/StringFieldValue.java | 40 +++ .../values/TimestampFieldValue.java | 27 ++ .../expression/values/TupleFieldValue.java | 34 +++ .../expression/values/UuidFieldValue.java | 27 ++ 10 files changed, 284 insertions(+), 268 deletions(-) create mode 100644 databind/src/main/java/tech/ydb/yoj/databind/expression/values/BoolFieldValue.java create mode 100644 databind/src/main/java/tech/ydb/yoj/databind/expression/values/ByteArrayFieldValue.java create mode 100644 databind/src/main/java/tech/ydb/yoj/databind/expression/values/NumberFieldValue.java create mode 100644 databind/src/main/java/tech/ydb/yoj/databind/expression/values/RealFieldValue.java create mode 100644 databind/src/main/java/tech/ydb/yoj/databind/expression/values/StringFieldValue.java create mode 100644 databind/src/main/java/tech/ydb/yoj/databind/expression/values/TimestampFieldValue.java create mode 100644 databind/src/main/java/tech/ydb/yoj/databind/expression/values/TupleFieldValue.java create mode 100644 databind/src/main/java/tech/ydb/yoj/databind/expression/values/UuidFieldValue.java diff --git a/databind/src/main/java/tech/ydb/yoj/databind/expression/FieldValue.java b/databind/src/main/java/tech/ydb/yoj/databind/expression/FieldValue.java index 2b7b817a..97014c55 100644 --- a/databind/src/main/java/tech/ydb/yoj/databind/expression/FieldValue.java +++ b/databind/src/main/java/tech/ydb/yoj/databind/expression/FieldValue.java @@ -1,14 +1,20 @@ package tech.ydb.yoj.databind.expression; import com.google.common.base.Preconditions; -import com.google.common.reflect.TypeToken; import lombok.EqualsAndHashCode; import lombok.NonNull; -import lombok.RequiredArgsConstructor; import lombok.Value; import tech.ydb.yoj.databind.ByteArray; import tech.ydb.yoj.databind.CustomValueTypes; import tech.ydb.yoj.databind.FieldValueType; +import tech.ydb.yoj.databind.expression.values.BoolFieldValue; +import tech.ydb.yoj.databind.expression.values.ByteArrayFieldValue; +import tech.ydb.yoj.databind.expression.values.NumberFieldValue; +import tech.ydb.yoj.databind.expression.values.RealFieldValue; +import tech.ydb.yoj.databind.expression.values.StringFieldValue; +import tech.ydb.yoj.databind.expression.values.TimestampFieldValue; +import tech.ydb.yoj.databind.expression.values.TupleFieldValue; +import tech.ydb.yoj.databind.expression.values.UuidFieldValue; import tech.ydb.yoj.databind.schema.ObjectSchema; import tech.ydb.yoj.databind.schema.Schema.JavaField; @@ -19,96 +25,54 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.UUID; import java.util.stream.Stream; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toCollection; -import static lombok.AccessLevel.PRIVATE; -@Value -@RequiredArgsConstructor(access = PRIVATE) -public class FieldValue { - String str; - Long num; - Double real; - Boolean bool; - Instant timestamp; - Tuple tuple; - ByteArray byteArray; - UUID uuid; +public interface FieldValue { + Comparable getComparableByType(Type fieldType, FieldValueType valueType); - @NonNull - public static FieldValue ofStr(@NonNull String str) { - return new FieldValue(str, null, null, null, null, null, null, null); - } - - @NonNull - public static FieldValue ofNum(long num) { - return new FieldValue(null, num, null, null, null, null, null, null); - } - - @NonNull - public static FieldValue ofReal(double real) { - return new FieldValue(null, null, real, null, null, null, null, null); - } - - @NonNull - public static FieldValue ofBool(boolean bool) { - return new FieldValue(null, null, null, bool, null, null, null, null); - } - - @NonNull - public static FieldValue ofTimestamp(@NonNull Instant timestamp) { - return new FieldValue(null, null, null, null, timestamp, null, null, null); - } - - @NonNull - public static FieldValue ofTuple(@NonNull Tuple tuple) { - return new FieldValue(null, null, null, null, null, tuple, null, null); - } - - @NonNull - public static FieldValue ofByteArray(@NonNull ByteArray byteArray) { - return new FieldValue(null, null, null, null, null, null, byteArray, null); + default Object getRaw(@NonNull JavaField field) { + Comparable cmp = getComparable(field); + return CustomValueTypes.postconvert(field, cmp); } - @NonNull - public static FieldValue ofUuid(@NonNull UUID uuid) { - return new FieldValue(null, null, null, null, null, null, null, uuid); + default Comparable getComparable(@NonNull JavaField field) { + field = field.isFlat() ? field.toFlatField() : field; + return getComparableByType(field.getType(), FieldValueType.forSchemaField(field)); } - @NonNull - public static FieldValue ofObj(@NonNull Object obj, @NonNull JavaField schemaField) { + static FieldValue ofObj(@NonNull Object obj, @NonNull JavaField schemaField) { FieldValueType fvt = FieldValueType.forJavaType(obj.getClass(), schemaField.getField()); obj = CustomValueTypes.preconvert(schemaField, obj); switch (fvt) { case STRING -> { - return ofStr((String) obj); + return new StringFieldValue((String) obj); } case ENUM -> { - return ofStr(((Enum) obj).name()); + return new StringFieldValue(((Enum) obj).name()); } case INTEGER -> { - return ofNum(((Number) obj).longValue()); + return new NumberFieldValue(((Number) obj).longValue()); } case REAL -> { - return ofReal(((Number) obj).doubleValue()); + return new RealFieldValue(((Number) obj).doubleValue()); } case BOOLEAN -> { - return ofBool((Boolean) obj); + return new BoolFieldValue((Boolean) obj); } case BYTE_ARRAY -> { - return ofByteArray((ByteArray) obj); + return new ByteArrayFieldValue((ByteArray) obj); } case TIMESTAMP -> { - return ofTimestamp((Instant) obj); + return new TimestampFieldValue((Instant) obj); } case UUID -> { - return ofUuid((UUID) obj); + return new UuidFieldValue((UUID) obj); } case COMPOSITE -> { ObjectSchema schema = ObjectSchema.of(obj.getClass()); @@ -123,7 +87,7 @@ public static FieldValue ofObj(@NonNull Object obj, @NonNull JavaField schemaFie Preconditions.checkArgument(singleValue != null, "Wrappers must have a non-null value inside them"); return singleValue; } - return ofTuple(new Tuple(obj, allFieldValues)); + return new TupleFieldValue(new Tuple(obj, allFieldValues)); } default -> throw new UnsupportedOperationException("Unsupported value type: not a string, integer, timestamp, UUID, enum, " + "floating-point number, byte array, tuple or wrapper of the above"); @@ -137,40 +101,8 @@ public static FieldValue ofObj(@NonNull Object obj, @NonNull JavaField schemaFie .collect(collectingAndThen(toCollection(ArrayList::new), Collections::unmodifiableList)); } - public boolean isNumber() { - return num != null; - } - - public boolean isReal() { - return real != null; - } - - public boolean isString() { - return str != null; - } - - public boolean isBool() { - return bool != null; - } - - public boolean isTimestamp() { - return timestamp != null; - } - - public boolean isTuple() { - return tuple != null; - } - - public boolean isByteArray() { - return byteArray != null; - } - - public boolean isUuid() { - return uuid != null; - } - @Nullable - public static Comparable getComparable(@NonNull Map values, + static Comparable getComparable(@NonNull Map values, @NonNull JavaField field) { if (field.isFlat()) { Object rawValue = values.get(field.getName()); @@ -180,167 +112,7 @@ public static Comparable getComparable(@NonNull Map values, } } - @NonNull - public Object getRaw(@NonNull JavaField field) { - field = field.isFlat() ? field.toFlatField() : field; - - Type fieldType = field.getType(); - if (FieldValueType.forSchemaField(field).isComposite()) { - Preconditions.checkState(isTuple(), "Value is not a tuple: %s", this); - Preconditions.checkState(tuple.getType().equals(fieldType), - "Tuple value cannot be converted to a composite of type %s: %s", fieldType, this); - return tuple.asComposite(); - } - - Comparable cmp = getComparable(field); - return CustomValueTypes.postconvert(field, cmp); - } - - @NonNull - @SuppressWarnings({"unchecked", "rawtypes"}) - public Comparable getComparable(@NonNull JavaField field) { - field = field.isFlat() ? field.toFlatField() : field; - - Type fieldType = field.getType(); - switch (FieldValueType.forSchemaField(field)) { - case STRING -> { - Preconditions.checkState(isString(), "Value is not a string: " + this); - return str; - } - case ENUM -> { - Preconditions.checkState(isString(), "Value is not a enum constant: " + this); - return Enum.valueOf((Class) TypeToken.of(fieldType).getRawType(), str); - } - case INTEGER -> { - if (isNumber()) { - return num; - } else if (isReal()) { - return real.longValue(); - } else if (isTimestamp()) { - return timestamp.toEpochMilli(); - } - throw new IllegalStateException("Value cannot be converted to integer: " + this); - } - case REAL -> { - if (isReal()) { - return real; - } else if (isNumber()) { - return num.doubleValue(); - } - throw new IllegalStateException("Value cannot be converted to double: " + this); - } - case TIMESTAMP -> { - if (isNumber()) { - return Instant.ofEpochMilli(num); - } else if (isTimestamp()) { - return timestamp; - } - throw new IllegalStateException("Value cannot be converted to timestamp: " + this); - } - case UUID -> { - // Compare UUIDs as String representations - // Rationale: @see https://devblogs.microsoft.com/oldnewthing/20190913-00/?p=102859 - if (isUuid()) { - return uuid.toString(); - } else if (isString()) { - try { - UUID.fromString(str); - return str; - } catch (IllegalArgumentException ignored) { - // ...no-op here because we will throw IllegalStateException right after the try() and if (isString()) - } - } - throw new IllegalStateException("Value cannot be converted to UUID: " + this); - } - case BOOLEAN -> { - Preconditions.checkState(isBool(), "Value is not a boolean: %s", this); - return bool; - } - case BYTE_ARRAY -> { - Preconditions.checkState(isByteArray(), "Value is not a ByteArray: %s", this); - return byteArray; - } - case COMPOSITE -> { - Preconditions.checkState(isTuple(), "Value is not a tuple: %s", this); - Preconditions.checkState(tuple.getType().equals(fieldType), - "Tuple value cannot be converted to a composite of type %s: %s", fieldType, this); - return tuple; - } - default -> throw new UnsupportedOperationException("Unrecognized expected type: " + fieldType); - } - } - - @NonNull - @Override - public String toString() { - if (isNumber()) { - return num.toString(); - } else if (isReal()) { - return real.toString(); - } else if (isString()) { - return "\"" + str + "\""; - } else if (isBool()) { - return bool.toString(); - } else if (isTimestamp()) { - return "#" + timestamp + "#"; - } else if (isByteArray()) { - return byteArray.toString(); - } else if (isTuple()) { - return tuple.toString(); - } else if (isUuid()) { - return "uuid(" + uuid + ")"; - } else { - return "???"; - } - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - FieldValue that = (FieldValue) o; - return Objects.equals(str, that.str) - && Objects.equals(num, that.num) - && Objects.equals(bool, that.bool) - && Objects.equals(timestamp, that.timestamp) - && Objects.equals(real, that.real) - && Objects.equals(tuple, that.tuple) - && Objects.equals(byteArray, that.byteArray) - && Objects.equals(uuid, that.uuid); - } - - @Override - public int hashCode() { - int result = 1; - result = result * 59 + (str == null ? 43 : str.hashCode()); - result = result * 59 + (num == null ? 43 : num.hashCode()); - result = result * 59 + (bool == null ? 43 : bool.hashCode()); - result = result * 59 + (timestamp == null ? 43 : timestamp.hashCode()); - - // For compatibility with old auto-generated hashCode(). - // Old FieldValues had no "real" field - if (real != null) { - result = result * 59 + real.hashCode(); - } - if (tuple != null) { - result = result * 59 + tuple.hashCode(); - } - if (byteArray != null) { - result = result * 59 + byteArray.hashCode(); - } - if (uuid != null) { - result = result * 59 + uuid.hashCode(); - } - - return result; - } - - public record FieldAndValue( + record FieldAndValue( @NonNull JavaField field, @Nullable FieldValue value ) { @@ -369,7 +141,7 @@ public String fieldPath() { } @Value - public static class Tuple implements Comparable { + class Tuple implements Comparable { @Nullable @EqualsAndHashCode.Exclude Object composite; diff --git a/databind/src/main/java/tech/ydb/yoj/databind/expression/ModelField.java b/databind/src/main/java/tech/ydb/yoj/databind/expression/ModelField.java index ffe04210..0917e5d3 100644 --- a/databind/src/main/java/tech/ydb/yoj/databind/expression/ModelField.java +++ b/databind/src/main/java/tech/ydb/yoj/databind/expression/ModelField.java @@ -12,6 +12,14 @@ import tech.ydb.yoj.databind.expression.IllegalExpressionException.FieldTypeError.RealFieldExpected; import tech.ydb.yoj.databind.expression.IllegalExpressionException.FieldTypeError.StringFieldExpected; import tech.ydb.yoj.databind.expression.IllegalExpressionException.FieldTypeError.UnknownEnumConstant; +import tech.ydb.yoj.databind.expression.values.BoolFieldValue; +import tech.ydb.yoj.databind.expression.values.ByteArrayFieldValue; +import tech.ydb.yoj.databind.expression.values.NumberFieldValue; +import tech.ydb.yoj.databind.expression.values.RealFieldValue; +import tech.ydb.yoj.databind.expression.values.StringFieldValue; +import tech.ydb.yoj.databind.expression.values.TimestampFieldValue; +import tech.ydb.yoj.databind.expression.values.TupleFieldValue; +import tech.ydb.yoj.databind.expression.values.UuidFieldValue; import tech.ydb.yoj.databind.schema.Schema; import tech.ydb.yoj.databind.schema.Schema.JavaField; @@ -67,8 +75,8 @@ public Stream flatten() { @NonNull public FieldValue validateValue(@NonNull FieldValue value) { - if (value.isTuple()) { - value.getTuple().streamComponents() + if (value instanceof TupleFieldValue tupleValue) { + tupleValue.tuple().streamComponents() .filter(jfv -> jfv.value() != null) .forEach(jfv -> new ModelField(null, jfv.field()).validateValue(jfv.value())); return value; @@ -76,16 +84,16 @@ public FieldValue validateValue(@NonNull FieldValue value) { JavaField flatField = toFlatField(); FieldValueType fieldValueType = FieldValueType.forSchemaField(flatField); - if (value.isString()) { + if (value instanceof StringFieldValue stringValue) { if (fieldValueType == FieldValueType.ENUM) { TypeToken tt = TypeToken.of(flatField.getType()); - String enumConstant = value.getStr(); + String enumConstant = stringValue.str(); Class clazz = tt.getRawType(); checkArgument(enumHasConstant(clazz, enumConstant), p -> new UnknownEnumConstant(p, enumConstant), p -> format("Unknown enum constant for field \"%s\": \"%s\"", p, enumConstant)); } else if (fieldValueType == FieldValueType.UUID) { - String str = value.getStr(); + String str = stringValue.str(); try { UUID.fromString(str); } catch (IllegalArgumentException e) { @@ -100,29 +108,29 @@ public FieldValue validateValue(@NonNull FieldValue value) { StringFieldExpected::new, p -> format("Specified a string value for non-string field \"%s\"", p)); } - } else if (value.isNumber()) { + } else if (value instanceof NumberFieldValue) { checkArgument( fieldValueType == FieldValueType.INTEGER, IntegerFieldExpected::new, p -> format("Specified an integer value for non-integer field \"%s\"", p)); - } else if (value.isReal()) { + } else if (value instanceof RealFieldValue) { checkArgument( fieldValueType == FieldValueType.REAL, RealFieldExpected::new, p -> format("Specified a real value for non-real field \"%s\"", p)); - } else if (value.isBool()) { + } else if (value instanceof BoolFieldValue) { checkArgument(fieldValueType == FieldValueType.BOOLEAN, BooleanFieldExpected::new, p -> format("Specified a boolean value for non-boolean field \"%s\"", p)); - } else if (value.isByteArray()) { + } else if (value instanceof ByteArrayFieldValue) { checkArgument(fieldValueType == FieldValueType.BYTE_ARRAY, ByteArrayFieldExpected::new, p -> format("Specified a ByteArray value for non-ByteArray field \"%s\"", p)); - } else if (value.isTimestamp()) { + } else if (value instanceof TimestampFieldValue) { checkArgument(fieldValueType == FieldValueType.TIMESTAMP || fieldValueType == FieldValueType.INTEGER, DateTimeFieldExpected::new, p -> format("Specified a timestamp value for non-timestamp field \"%s\"", p)); - } else if (value.isUuid()) { + } else if (value instanceof UuidFieldValue) { checkArgument(fieldValueType == FieldValueType.UUID || fieldValueType == FieldValueType.STRING, IllegalExpressionException.FieldTypeError.UuidFieldExpected::new, p -> format("Specified an UUID value for non-UUID/non-String field \"%s\"", p)); diff --git a/databind/src/main/java/tech/ydb/yoj/databind/expression/values/BoolFieldValue.java b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/BoolFieldValue.java new file mode 100644 index 00000000..b567d6a6 --- /dev/null +++ b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/BoolFieldValue.java @@ -0,0 +1,26 @@ +package tech.ydb.yoj.databind.expression.values; + +import tech.ydb.yoj.databind.FieldValueType; +import tech.ydb.yoj.databind.expression.FieldValue; + +import java.lang.reflect.Type; + +public record BoolFieldValue( + Boolean bool +) implements FieldValue { + @Override + public Comparable getComparableByType(Type fieldType, FieldValueType valueType) { + if (valueType != FieldValueType.BOOLEAN) { + throw new IllegalStateException("Not comparable java field %s and field value %s" + .formatted(valueType, this) + ); + } + + return bool; + } + + @Override + public String toString() { + return bool.toString(); + } +} diff --git a/databind/src/main/java/tech/ydb/yoj/databind/expression/values/ByteArrayFieldValue.java b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/ByteArrayFieldValue.java new file mode 100644 index 00000000..6c88b79d --- /dev/null +++ b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/ByteArrayFieldValue.java @@ -0,0 +1,28 @@ +package tech.ydb.yoj.databind.expression.values; + +import tech.ydb.yoj.databind.ByteArray; +import tech.ydb.yoj.databind.FieldValueType; +import tech.ydb.yoj.databind.expression.FieldValue; + +import java.lang.reflect.Type; +import java.util.Objects; + +public record ByteArrayFieldValue( + ByteArray byteArray +) implements FieldValue { + @Override + public Comparable getComparableByType(Type fieldType, FieldValueType valueType) { + if (Objects.requireNonNull(valueType) != FieldValueType.BYTE_ARRAY) { + throw new IllegalStateException("Not comparable java field %s and field value %s" + .formatted(valueType, this) + ); + } + + return byteArray; + } + + @Override + public String toString() { + return "byte array with hash " + hashCode(); + } +} diff --git a/databind/src/main/java/tech/ydb/yoj/databind/expression/values/NumberFieldValue.java b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/NumberFieldValue.java new file mode 100644 index 00000000..e50de4e2 --- /dev/null +++ b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/NumberFieldValue.java @@ -0,0 +1,28 @@ +package tech.ydb.yoj.databind.expression.values; + +import tech.ydb.yoj.databind.FieldValueType; +import tech.ydb.yoj.databind.expression.FieldValue; + +import java.lang.reflect.Type; +import java.time.Instant; + +public record NumberFieldValue( + Long num +) implements FieldValue { + @Override + public Comparable getComparableByType(Type fieldType, FieldValueType valueType) { + return switch (valueType) { + case INTEGER -> num; + case REAL -> num.doubleValue(); + case TIMESTAMP -> Instant.ofEpochMilli(num); + default -> throw new IllegalStateException("Not comparable java field %s and field value %s" + .formatted(valueType, this) + ); + }; + } + + @Override + public String toString() { + return num.toString(); + } +} diff --git a/databind/src/main/java/tech/ydb/yoj/databind/expression/values/RealFieldValue.java b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/RealFieldValue.java new file mode 100644 index 00000000..936aaca9 --- /dev/null +++ b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/RealFieldValue.java @@ -0,0 +1,26 @@ +package tech.ydb.yoj.databind.expression.values; + +import tech.ydb.yoj.databind.FieldValueType; +import tech.ydb.yoj.databind.expression.FieldValue; + +import java.lang.reflect.Type; + +public record RealFieldValue( + Double real +) implements FieldValue { + @Override + public Comparable getComparableByType(Type fieldType, FieldValueType valueType) { + return switch (valueType) { + case INTEGER -> real.longValue(); + case REAL -> real; + default -> throw new IllegalStateException("Not comparable java field %s and field value %s" + .formatted(valueType, this) + ); + }; + } + + @Override + public String toString() { + return real.toString(); + } +} diff --git a/databind/src/main/java/tech/ydb/yoj/databind/expression/values/StringFieldValue.java b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/StringFieldValue.java new file mode 100644 index 00000000..e409c072 --- /dev/null +++ b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/StringFieldValue.java @@ -0,0 +1,40 @@ +package tech.ydb.yoj.databind.expression.values; + +import com.google.common.reflect.TypeToken; +import lombok.NonNull; +import tech.ydb.yoj.databind.FieldValueType; +import tech.ydb.yoj.databind.expression.FieldValue; + +import java.lang.reflect.Type; +import java.util.UUID; + +public record StringFieldValue( + String str +) implements FieldValue { + @NonNull + public Comparable getComparableByType(Type fieldType, FieldValueType valueType) { + return switch (valueType) { + case STRING -> str; + case ENUM -> Enum.valueOf((Class) TypeToken.of(fieldType).getRawType(), str); + case UUID -> { + // Compare UUIDs as String representations + // Rationale: @see https://devblogs.microsoft.com/oldnewthing/20190913-00/?p=102859 + try { + UUID.fromString(str); + + } catch (IllegalArgumentException ignored) { + throw new IllegalStateException("Value cannot be converted to UUID: " + this); + } + yield str; + } + default -> throw new IllegalStateException("Not comparable java field %s and field value %s" + .formatted(valueType, this) + ); + }; + } + + @Override + public String toString() { + return "\"" + str + "\""; + } +} diff --git a/databind/src/main/java/tech/ydb/yoj/databind/expression/values/TimestampFieldValue.java b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/TimestampFieldValue.java new file mode 100644 index 00000000..5df13b5e --- /dev/null +++ b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/TimestampFieldValue.java @@ -0,0 +1,27 @@ +package tech.ydb.yoj.databind.expression.values; + +import tech.ydb.yoj.databind.FieldValueType; +import tech.ydb.yoj.databind.expression.FieldValue; + +import java.lang.reflect.Type; +import java.time.Instant; + +public record TimestampFieldValue( + Instant timestamp +) implements FieldValue { + @Override + public Comparable getComparableByType(Type fieldType, FieldValueType valueType) { + return switch (valueType) { + case INTEGER -> timestamp.toEpochMilli(); + case TIMESTAMP -> timestamp; + default -> throw new IllegalStateException("Not comparable java field %s and field value %s" + .formatted(valueType, this) + ); + }; + } + + @Override + public String toString() { + return "#" + timestamp + "#"; + } +} diff --git a/databind/src/main/java/tech/ydb/yoj/databind/expression/values/TupleFieldValue.java b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/TupleFieldValue.java new file mode 100644 index 00000000..ef8de3c9 --- /dev/null +++ b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/TupleFieldValue.java @@ -0,0 +1,34 @@ +package tech.ydb.yoj.databind.expression.values; + +import com.google.common.base.Preconditions; +import tech.ydb.yoj.databind.FieldValueType; +import tech.ydb.yoj.databind.expression.FieldValue; + +import java.lang.reflect.Type; +import java.util.Objects; + +public record TupleFieldValue( + Tuple tuple +) implements FieldValue { + @Override + public Comparable getComparableByType(Type fieldType, FieldValueType valueType) { + if (Objects.requireNonNull(valueType) != FieldValueType.COMPOSITE) { + throw new IllegalStateException("Not comparable java field %s and field value %s" + .formatted(valueType, this) + ); + } + + Preconditions.checkState( + tuple.getType().equals(fieldType), + "Tuple value cannot be converted to a composite of type %s: %s", + fieldType, + this + ); + return tuple; + } + + @Override + public String toString() { + return tuple.toString(); + } +} diff --git a/databind/src/main/java/tech/ydb/yoj/databind/expression/values/UuidFieldValue.java b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/UuidFieldValue.java new file mode 100644 index 00000000..fd348cae --- /dev/null +++ b/databind/src/main/java/tech/ydb/yoj/databind/expression/values/UuidFieldValue.java @@ -0,0 +1,27 @@ +package tech.ydb.yoj.databind.expression.values; + +import tech.ydb.yoj.databind.FieldValueType; +import tech.ydb.yoj.databind.expression.FieldValue; + +import java.lang.reflect.Type; +import java.util.Objects; +import java.util.UUID; + +public record UuidFieldValue( + UUID uuid +) implements FieldValue { + @Override + public Comparable getComparableByType(Type fieldType, FieldValueType valueType) { + if (Objects.requireNonNull(valueType) != FieldValueType.UUID) { + throw new IllegalStateException("Not comparable java field %s and field value %s" + .formatted(valueType, this) + ); + } + return uuid.toString(); + } + + @Override + public String toString() { + return uuid.toString(); + } +}