You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by am...@apache.org on 2021/11/12 14:01:39 UTC
[ignite-3] branch main updated: IGNITE-14484 Implement RecordView
API. (#435)
This is an automated email from the ASF dual-hosted git repository.
amashenkov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new af06c65 IGNITE-14484 Implement RecordView API. (#435)
af06c65 is described below
commit af06c65ae41ce7295a03d43d1e08f26dfca092c2
Author: Andrew V. Mashenkov <AM...@users.noreply.github.com>
AuthorDate: Fri Nov 12 17:01:00 2021 +0300
IGNITE-14484 Implement RecordView API. (#435)
---
.../apache/ignite/table/mapper/MapperBuilder.java | 28 +-
.../internal/schema/marshaller/KvMarshaller.java | 5 +
.../schema/marshaller/MarshallerFactory.java | 22 +-
.../schema/marshaller/RecordMarshaller.java} | 40 +-
.../schema/marshaller/SerializerFactory.java | 1 +
.../marshaller/reflection/JavaSerializer.java | 1 +
.../reflection/JavaSerializerFactory.java | 1 +
.../marshaller/reflection/KvMarshallerImpl.java | 12 +-
.../schema/marshaller/reflection/Marshaller.java | 15 +-
...rshallerImpl.java => RecordMarshallerImpl.java} | 87 ++--
.../reflection/ReflectionMarshallerFactory.java | 6 +
.../schema/marshaller/JavaSerializerTest.java | 62 ++-
.../schema/marshaller/KvMarshallerTest.java | 139 ++++--
.../internal/schema/marshaller/MapperTest.java | 75 +++
...rshallerTest.java => RecordMarshallerTest.java} | 539 +++++++++------------
.../TestObjectWithNoDefaultConstructor.java | 15 +-
.../TestObjectWithPrivateConstructor.java | 9 +-
.../ignite/internal/table/KeyValueViewImpl.java | 12 +-
.../ignite/internal/table/RecordViewImpl.java | 237 ++++++---
.../internal/table/KeyValueViewOperationsTest.java | 6 +-
.../internal/table/RecordViewOperationsTest.java | 340 +++++++++++++
21 files changed, 1111 insertions(+), 541 deletions(-)
diff --git a/modules/api/src/main/java/org/apache/ignite/table/mapper/MapperBuilder.java b/modules/api/src/main/java/org/apache/ignite/table/mapper/MapperBuilder.java
index ee290f2..e1357e2 100644
--- a/modules/api/src/main/java/org/apache/ignite/table/mapper/MapperBuilder.java
+++ b/modules/api/src/main/java/org/apache/ignite/table/mapper/MapperBuilder.java
@@ -18,6 +18,7 @@
package org.apache.ignite.table.mapper;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
@@ -34,7 +35,7 @@ public final class MapperBuilder<T> {
private Class<T> targetType;
/** Column-to-field name mapping. */
- private Map<String, String> mapping;
+ private Map<String, String> columnToFields;
/**
* Creates a mapper builder for a type.
@@ -44,7 +45,7 @@ public final class MapperBuilder<T> {
MapperBuilder(@NotNull Class<T> targetType) {
this.targetType = targetType;
- mapping = new HashMap<>(targetType.getDeclaredFields().length);
+ columnToFields = new HashMap<>(targetType.getDeclaredFields().length);
}
/**
@@ -53,13 +54,15 @@ public final class MapperBuilder<T> {
* @param fieldName Field name.
* @param columnName Column name.
* @return {@code this} for chaining.
+ * @throws IllegalArgumentException if a column was already mapped to some field.
+ * @throws IllegalStateException if tries to reuse the builder after a mapping has been built.
*/
public MapperBuilder<T> map(@NotNull String fieldName, @NotNull String columnName) {
- if (mapping == null) {
+ if (columnToFields == null) {
throw new IllegalStateException("Mapper builder can't be reused.");
}
- if (mapping.put(Objects.requireNonNull(columnName), Objects.requireNonNull(fieldName)) != null) {
+ if (columnToFields.put(Objects.requireNonNull(columnName), Objects.requireNonNull(fieldName)) != null) {
throw new IllegalArgumentException("Mapping for a column already exists: " + columnName);
}
@@ -102,11 +105,24 @@ public final class MapperBuilder<T> {
* Builds mapper.
*
* @return Mapper.
+ * @throws IllegalStateException if nothing were mapped or more than one column were mapped to the same field.
*/
public Mapper<T> build() {
- Map<String, String> mapping = this.mapping;
+ if (columnToFields.isEmpty()) {
+ throw new IllegalStateException("Empty mapping isn't allowed.");
+ }
+
+ Map<String, String> mapping = this.columnToFields;
+
+ this.columnToFields = null;
- this.mapping = null;
+ HashSet<String> fields = new HashSet<>(mapping.size());
+
+ for (String f : mapping.values()) {
+ if (!fields.add(f)) {
+ throw new IllegalStateException("More than one column is mapped to the field: field=" + f);
+ }
+ }
return new DefaultColumnMapper<>(targetType, mapping);
}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/KvMarshaller.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/KvMarshaller.java
index c772894..3dc6c81 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/KvMarshaller.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/KvMarshaller.java
@@ -31,6 +31,11 @@ import org.jetbrains.annotations.Nullable;
*/
public interface KvMarshaller<K, V> {
/**
+ * Returns marshaller schema version.
+ */
+ int schemaVersion();
+
+ /**
* Marshal given key and value objects to a table row.
*
* @param key Key object to marshal.
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerFactory.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerFactory.java
index b2ceeac..3c8858e 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerFactory.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerFactory.java
@@ -23,7 +23,6 @@ import org.apache.ignite.table.mapper.Mapper;
/**
* Marshaller factory interface.
*/
-@FunctionalInterface
public interface MarshallerFactory {
/**
* Creates key-value marshaller using provided mappers.
@@ -49,4 +48,25 @@ public interface MarshallerFactory {
Class<V> valueClass) {
return create(schema, Mapper.identity(keyClass), Mapper.identity(valueClass));
}
+
+ /**
+ * Creates record marshaller using provided mapper.
+ *
+ * @param schema Schema descriptor.
+ * @param mapper Record mapper.
+ * @return Record marshaller.
+ */
+ <R> RecordMarshaller<R> create(SchemaDescriptor schema, Mapper<R> mapper);
+
+ /**
+ * Shortcut method creates record marshaller for classes using identity mappers.
+ *
+ * @param schema Schema descriptor.
+ * @param recordClass Record type.
+ * @return Record marshaller.
+ * @see Mapper#identity(Class)
+ */
+ default <R> RecordMarshaller<R> create(SchemaDescriptor schema, Class<R> recordClass) {
+ return create(schema, Mapper.identity(recordClass));
+ }
}
diff --git a/modules/table/src/main/java/org/apache/ignite/internal/schema/marshaller/RecordSerializer.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/RecordMarshaller.java
similarity index 52%
rename from modules/table/src/main/java/org/apache/ignite/internal/schema/marshaller/RecordSerializer.java
rename to modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/RecordMarshaller.java
index 5792f10..a82f97b 100644
--- a/modules/table/src/main/java/org/apache/ignite/internal/schema/marshaller/RecordSerializer.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/RecordMarshaller.java
@@ -17,35 +17,45 @@
package org.apache.ignite.internal.schema.marshaller;
+import org.apache.ignite.internal.schema.BinaryRow;
import org.apache.ignite.internal.schema.row.Row;
import org.jetbrains.annotations.NotNull;
/**
- * Record serializer interface.
+ * Record marshaller interface provides method to marshal/unmarshal record objects to/from a row.
+ *
+ * @param <R> Record type.
*/
-public interface RecordSerializer<R> {
+public interface RecordMarshaller<R> {
+ /**
+ * Returns marshaller schema version.
+ */
+ int schemaVersion();
+
/**
- * Serializes the record.
+ * Marshals given record to a row.
*
- * @param red Record to serialize.
+ * @param rec Record to marshal.
* @return Table row with columns set from given object.
+ * @throws MarshallerException If failed to marshal record.
*/
- Row serialize(@NotNull R red);
-
+ BinaryRow marshal(@NotNull R rec) throws MarshallerException;
+
/**
- * Deserializes the record.
+ * Marshals key part of given record to a row.
*
- * @param row Table row.
- * @return Deserialized record object.
+ * @param keyRec Record to marshal.
+ * @return Table row with key columns set from given object.
+ * @throws MarshallerException If failed to marshal record.
*/
- R deserialize(@NotNull Row row);
-
+ BinaryRow marshalKey(@NotNull R keyRec) throws MarshallerException;
+
/**
- * Deserializes row and fills given record object fields.
+ * Unmarshal given row to a record object.
*
* @param row Table row.
- * @param rec Record object to fill.
- * @return Given record with filled fields from the given row.
+ * @return Record object.
+ * @throws MarshallerException If failed to unmarshal row.
*/
- R deserialize(@NotNull Row row, @NotNull R rec);
+ R unmarshal(@NotNull Row row) throws MarshallerException;
}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializerFactory.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializerFactory.java
index 07fe59e..3d90543 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializerFactory.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializerFactory.java
@@ -26,6 +26,7 @@ import org.apache.ignite.internal.schema.marshaller.reflection.JavaSerializerFac
*
* @deprecated Replaced with {@link MarshallerFactory}
*/
+//TODO: IGNITE-15888 drop
@FunctionalInterface
@Deprecated(forRemoval = true)
public interface SerializerFactory {
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/JavaSerializer.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/JavaSerializer.java
index 1d01416..66e2d12 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/JavaSerializer.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/JavaSerializer.java
@@ -34,6 +34,7 @@ import org.jetbrains.annotations.Nullable;
/**
* Reflection based (de)serializer.
*/
+//TODO: IGNITE-15907 drop
@Deprecated(forRemoval = true)
public class JavaSerializer extends AbstractSerializer {
/** Key class. */
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/JavaSerializerFactory.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/JavaSerializerFactory.java
index c77f6d7..ef32a56 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/JavaSerializerFactory.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/JavaSerializerFactory.java
@@ -24,6 +24,7 @@ import org.apache.ignite.internal.schema.marshaller.SerializerFactory;
/**
* Factory for reflection-based serializer.
*/
+//TODO: IGNITE-15907 drop
@Deprecated(forRemoval = true)
public class JavaSerializerFactory implements SerializerFactory {
/** {@inheritDoc} */
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/KvMarshallerImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/KvMarshallerImpl.java
index e234a3b..54d284a 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/KvMarshallerImpl.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/KvMarshallerImpl.java
@@ -23,6 +23,7 @@ import java.util.Objects;
import org.apache.ignite.internal.schema.BinaryRow;
import org.apache.ignite.internal.schema.ByteBufferRow;
import org.apache.ignite.internal.schema.Columns;
+import org.apache.ignite.internal.schema.NativeType;
import org.apache.ignite.internal.schema.SchemaDescriptor;
import org.apache.ignite.internal.schema.marshaller.KvMarshaller;
import org.apache.ignite.internal.schema.marshaller.MarshallerException;
@@ -63,10 +64,12 @@ public class KvMarshallerImpl<K, V> implements KvMarshaller<K, V> {
keyClass = keyMapper.targetType();
valClass = valueMapper.targetType();
- keyMarsh = Marshaller.createMarshaller(schema.keyColumns(), keyMapper);
- valMarsh = Marshaller.createMarshaller(schema.valueColumns(), valueMapper);
+ keyMarsh = Marshaller.createMarshaller(schema.keyColumns().columns(), keyMapper);
+ valMarsh = Marshaller.createMarshaller(schema.valueColumns().columns(), valueMapper);
}
+ /** {@inheritDoc} */
+ @Override
public int schemaVersion() {
return schema.version();
}
@@ -147,12 +150,13 @@ public class KvMarshallerImpl<K, V> implements KvMarshaller<K, V> {
for (int i = cols.firstVarlengthColumn(); i < cols.length(); i++) {
final Object val = marsh.value(obj, i);
+ final NativeType colType = cols.column(i).type();
- if (val == null || cols.column(i).type().spec().fixedLength()) {
+ if (val == null || colType.spec().fixedLength()) {
continue;
}
- size += getValueSize(val, cols.column(i).type());
+ size += getValueSize(val, colType);
cnt++;
}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/Marshaller.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/Marshaller.java
index c933354..cbe2137 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/Marshaller.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/Marshaller.java
@@ -41,24 +41,24 @@ public abstract class Marshaller {
* @param mapper Mapper.
* @return Marshaller.
*/
- public static <T> Marshaller createMarshaller(Columns cols, Mapper<T> mapper) {
+ public static <T> Marshaller createMarshaller(Column[] cols, Mapper<T> mapper) {
final BinaryMode mode = MarshallerUtil.mode(mapper.targetType());
if (mode != null) {
- final Column col = cols.column(0);
+ final Column col = cols[0];
- assert cols.length() == 1;
+ assert cols.length == 1;
assert mode.typeSpec() == col.type().spec() : "Target type is not compatible.";
assert !mapper.targetType().isPrimitive() : "Non-nullable types are not allowed.";
return new SimpleMarshaller(FieldAccessor.createIdentityAccessor(col, col.schemaIndex(), mode));
}
- FieldAccessor[] fieldAccessors = new FieldAccessor[cols.length()];
+ FieldAccessor[] fieldAccessors = new FieldAccessor[cols.length];
// Build handlers.
- for (int i = 0; i < cols.length(); i++) {
- final Column col = cols.column(i);
+ for (int i = 0; i < cols.length; i++) {
+ final Column col = cols[i];
String fieldName = mapper.columnToField(col.name());
@@ -77,7 +77,8 @@ public abstract class Marshaller {
* @param cls Type.
* @return Marshaller.
*/
- @Deprecated // TODO drop method.
+ //TODO: IGNITE-15907 drop
+ @Deprecated
public static Marshaller createMarshaller(Columns cols, Class<? extends Object> cls) {
final BinaryMode mode = MarshallerUtil.mode(cls);
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/KvMarshallerImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/RecordMarshallerImpl.java
similarity index 69%
copy from modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/KvMarshallerImpl.java
copy to modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/RecordMarshallerImpl.java
index e234a3b..ae2aef9 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/KvMarshallerImpl.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/RecordMarshallerImpl.java
@@ -22,96 +22,90 @@ import static org.apache.ignite.internal.schema.marshaller.MarshallerUtil.getVal
import java.util.Objects;
import org.apache.ignite.internal.schema.BinaryRow;
import org.apache.ignite.internal.schema.ByteBufferRow;
+import org.apache.ignite.internal.schema.Column;
import org.apache.ignite.internal.schema.Columns;
import org.apache.ignite.internal.schema.SchemaDescriptor;
-import org.apache.ignite.internal.schema.marshaller.KvMarshaller;
import org.apache.ignite.internal.schema.marshaller.MarshallerException;
+import org.apache.ignite.internal.schema.marshaller.RecordMarshaller;
import org.apache.ignite.internal.schema.row.Row;
import org.apache.ignite.internal.schema.row.RowAssembler;
+import org.apache.ignite.internal.util.ArrayUtils;
import org.apache.ignite.table.mapper.Mapper;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/**
- * Key-value marshaller for given schema and mappers.
+ * Record marshaller for given schema and mappers.
*
- * @param <K> Key type.
- * @param <V> Value type.
+ * @param <R> Record type.
*/
-public class KvMarshallerImpl<K, V> implements KvMarshaller<K, V> {
+public class RecordMarshallerImpl<R> implements RecordMarshaller<R> {
/** Schema. */
private final SchemaDescriptor schema;
/** Key marshaller. */
private final Marshaller keyMarsh;
- /** Value marshaller. */
- private final Marshaller valMarsh;
+ /** Record marshaller. */
+ private final Marshaller recMarsh;
- /** Key type. */
- private final Class<K> keyClass;
-
- /** Value type. */
- private final Class<V> valClass;
+ /** Record type. */
+ private final Class<R> recClass;
/**
* Creates KV marshaller.
*/
- public KvMarshallerImpl(SchemaDescriptor schema, Mapper<K> keyMapper, Mapper<V> valueMapper) {
+ public RecordMarshallerImpl(SchemaDescriptor schema, Mapper<R> mapper) {
this.schema = schema;
- keyClass = keyMapper.targetType();
- valClass = valueMapper.targetType();
+ recClass = mapper.targetType();
+
+ keyMarsh = Marshaller.createMarshaller(schema.keyColumns().columns(), mapper);
- keyMarsh = Marshaller.createMarshaller(schema.keyColumns(), keyMapper);
- valMarsh = Marshaller.createMarshaller(schema.valueColumns(), valueMapper);
+ recMarsh = Marshaller.createMarshaller(
+ ArrayUtils.concat(schema.keyColumns().columns(), schema.valueColumns().columns()),
+ mapper
+ );
}
+ /** {@inheritDoc} */
+ @Override
public int schemaVersion() {
return schema.version();
}
/** {@inheritDoc} */
@Override
- public BinaryRow marshal(@NotNull K key, V val) throws MarshallerException {
- assert keyClass.isInstance(key);
- assert val == null || valClass.isInstance(val);
-
- final RowAssembler asm = createAssembler(Objects.requireNonNull(key), val);
+ public BinaryRow marshal(@NotNull R rec) throws MarshallerException {
+ assert recClass.isInstance(rec);
- keyMarsh.writeObject(key, asm);
+ final RowAssembler asm = createAssembler(Objects.requireNonNull(rec), rec);
- if (val != null) {
- valMarsh.writeObject(val, asm);
- }
+ recMarsh.writeObject(rec, asm);
return new ByteBufferRow(asm.toBytes());
}
/** {@inheritDoc} */
- @NotNull
@Override
- public K unmarshalKey(@NotNull Row row) throws MarshallerException {
- final Object o = keyMarsh.readObject(row);
+ public BinaryRow marshalKey(@NotNull R rec) throws MarshallerException {
+ assert recClass.isInstance(rec);
+
+ final RowAssembler asm = createAssembler(Objects.requireNonNull(rec), null);
- assert keyClass.isInstance(o);
+ keyMarsh.writeObject(rec, asm);
- return (K) o;
+ return new ByteBufferRow(asm.toBytes());
}
/** {@inheritDoc} */
- @Nullable
+ @NotNull
@Override
- public V unmarshalValue(@NotNull Row row) throws MarshallerException {
- if (!row.hasValue()) {
- return null;
- }
-
- final Object o = valMarsh.readObject(row);
+ public R unmarshal(@NotNull Row row) throws MarshallerException {
+ final Object o = recMarsh.readObject(row);
- assert o == null || valClass.isInstance(o);
+ assert recClass.isInstance(o);
- return (V) o;
+ return (R) o;
}
/**
@@ -122,8 +116,8 @@ public class KvMarshallerImpl<K, V> implements KvMarshaller<K, V> {
* @return Row assembler.
*/
private RowAssembler createAssembler(Object key, Object val) {
- ObjectStatistic keyStat = collectObjectStats(schema.keyColumns(), keyMarsh, key);
- ObjectStatistic valStat = collectObjectStats(schema.valueColumns(), valMarsh, val);
+ ObjectStatistic keyStat = collectObjectStats(schema.keyColumns(), recMarsh, key);
+ ObjectStatistic valStat = collectObjectStats(schema.valueColumns(), recMarsh, val);
return new RowAssembler(schema, keyStat.nonNullColsSize, keyStat.nonNullCols,
valStat.nonNullColsSize, valStat.nonNullCols);
@@ -146,13 +140,14 @@ public class KvMarshallerImpl<K, V> implements KvMarshaller<K, V> {
int size = 0;
for (int i = cols.firstVarlengthColumn(); i < cols.length(); i++) {
- final Object val = marsh.value(obj, i);
+ final Column column = cols.column(i);
+ final Object val = marsh.value(obj, column.schemaIndex());
- if (val == null || cols.column(i).type().spec().fixedLength()) {
+ if (val == null || column.type().spec().fixedLength()) {
continue;
}
- size += getValueSize(val, cols.column(i).type());
+ size += getValueSize(val, column.type());
cnt++;
}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/ReflectionMarshallerFactory.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/ReflectionMarshallerFactory.java
index b3d9a89..654b735 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/ReflectionMarshallerFactory.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/ReflectionMarshallerFactory.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.schema.marshaller.reflection;
import org.apache.ignite.internal.schema.SchemaDescriptor;
import org.apache.ignite.internal.schema.marshaller.KvMarshaller;
import org.apache.ignite.internal.schema.marshaller.MarshallerFactory;
+import org.apache.ignite.internal.schema.marshaller.RecordMarshaller;
import org.apache.ignite.table.mapper.Mapper;
/**
@@ -30,4 +31,9 @@ public class ReflectionMarshallerFactory implements MarshallerFactory {
@Override public <K, V> KvMarshaller<K, V> create(SchemaDescriptor schema, Mapper<K> keyMapper, Mapper<V> valueMapper) {
return new KvMarshallerImpl<>(schema, keyMapper, valueMapper);
}
+
+ /** {@inheritDoc} */
+ @Override public <R> RecordMarshaller<R> create(SchemaDescriptor schema, Mapper<R> mapper) {
+ return new RecordMarshallerImpl<>(schema, mapper);
+ }
}
diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java
index dc34a06..453d9ad 100644
--- a/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java
+++ b/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java
@@ -48,6 +48,7 @@ import com.facebook.presto.bytecode.Variable;
import com.facebook.presto.bytecode.expression.BytecodeExpressions;
import java.util.EnumSet;
import java.util.List;
+import java.util.Objects;
import java.util.Random;
import java.util.stream.Stream;
import javax.annotation.processing.Generated;
@@ -75,6 +76,8 @@ import org.junit.jupiter.params.provider.MethodSource;
/**
* Serializer test.
*/
+//TODO: IGNITE-15888 drop
+@Deprecated(forRemoval = true)
public class JavaSerializerTest {
/**
* Get list of serializers for test.
@@ -176,7 +179,6 @@ public class JavaSerializerTest {
BinaryRow row = serializer.serialize(key, val);
- // Try different order.
Object restoredVal = serializer.deserializeValue(new Row(schema, row));
Object restoredKey = serializer.deserializeKey(new Row(schema, row));
@@ -246,6 +248,7 @@ public class JavaSerializerTest {
public void classWithPrivateConstructor(SerializerFactory factory) throws MarshallerException {
Column[] cols = new Column[]{
new Column("primLongCol", INT64, false),
+ new Column("primIntCol", INT32, false)
};
SchemaDescriptor schema = new SchemaDescriptor(1, cols, cols);
@@ -276,12 +279,14 @@ public class JavaSerializerTest {
public void classWithNoDefaultConstructor(SerializerFactory factory) {
Column[] cols = new Column[]{
new Column("primLongCol", INT64, false),
+ new Column("primIntCol", INT32, false)
};
SchemaDescriptor schema = new SchemaDescriptor(1, cols, cols);
final Object key = TestObjectWithNoDefaultConstructor.randomObject(rnd);
final Object val = TestObjectWithNoDefaultConstructor.randomObject(rnd);
+
assertThrows(IgniteInternalException.class, () -> factory.create(schema, key.getClass(), val.getClass()));
}
@@ -298,10 +303,10 @@ public class JavaSerializerTest {
SchemaDescriptor schema = new SchemaDescriptor(1, cols, cols);
- final Object key = TestObjectWithPrivateConstructor.randomObject(rnd);
- final Object val = TestObjectWithPrivateConstructor.randomObject(rnd);
+ final Object key = PrivateTestObject.randomObject(rnd);
+ final Object val = PrivateTestObject.randomObject(rnd);
- final ObjectFactory<?> objFactory = new ObjectFactory<>(TestObjectWithPrivateConstructor.class);
+ final ObjectFactory<?> objFactory = new ObjectFactory<>(PrivateTestObject.class);
final Serializer serializer = factory.create(schema, key.getClass(), val.getClass());
BinaryRow row = serializer.serialize(key, objFactory.create());
@@ -453,4 +458,53 @@ public class JavaSerializerTest {
.dumpRawBytecode(true)
.defineClass(classDef, Object.class);
}
+
+ /**
+ * Test object without default constructor.
+ */
+ @SuppressWarnings("InstanceVariableMayNotBeInitialized")
+ private static class PrivateTestObject {
+ /**
+ * Get random TestObject.
+ */
+ static PrivateTestObject randomObject(Random rnd) {
+ return new PrivateTestObject(rnd.nextInt());
+ }
+
+ /** Value. */
+ private long primLongCol;
+
+ /** Constructor. */
+ PrivateTestObject() {
+ }
+
+ /**
+ * Private constructor.
+ */
+ PrivateTestObject(long val) {
+ primLongCol = val;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ PrivateTestObject object = (PrivateTestObject) o;
+
+ return primLongCol == object.primLongCol;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return Objects.hash(primLongCol);
+ }
+ }
}
diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/KvMarshallerTest.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/KvMarshallerTest.java
index 87b1c96..0a024ad 100644
--- a/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/KvMarshallerTest.java
+++ b/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/KvMarshallerTest.java
@@ -148,7 +148,6 @@ public class KvMarshallerTest {
BinaryRow row = marshaller.marshal(key, val);
- // Try different order.
TestObjectWithAllTypes restoredVal = marshaller.unmarshalValue(new Row(schema, row));
TestObjectWithAllTypes restoredKey = marshaller.unmarshalKey(new Row(schema, row));
@@ -174,7 +173,6 @@ public class KvMarshallerTest {
BinaryRow row = marshaller.marshal(key, val);
- // Try different order.
Object restoredVal = marshaller.unmarshalValue(new Row(schema, row));
Object restoredKey = marshaller.unmarshalKey(new Row(schema, row));
@@ -204,7 +202,6 @@ public class KvMarshallerTest {
BinaryRow row = marshaller.marshal(key, val);
- // Try different order.
TestObjectWithAllTypes restoredVal = marshaller.unmarshalValue(new Row(schema, row));
TestObjectWithAllTypes restoredKey = marshaller.unmarshalKey(new Row(schema, row));
@@ -224,6 +221,7 @@ public class KvMarshallerTest {
assertEquals(expectedKey, restoredKey);
assertEquals(expectedVal, restoredVal);
+ // Check non-mapped fields has default values.
assertNull(restoredKey.getUuidCol());
assertNull(restoredVal.getUuidCol());
assertEquals(0, restoredKey.getPrimitiveIntCol());
@@ -257,7 +255,6 @@ public class KvMarshallerTest {
BinaryRow row = marshaller.marshal(key, val);
- // Try different order.
Object restoredVal = marshaller.unmarshalValue(new Row(schema, row));
Object restoredKey = marshaller.unmarshalKey(new Row(schema, row));
@@ -321,6 +318,7 @@ public class KvMarshallerTest {
public void classWithPrivateConstructor(MarshallerFactory factory) throws MarshallerException {
Column[] cols = new Column[]{
new Column("primLongCol", INT64, false),
+ new Column("primIntCol", INT32, false),
};
SchemaDescriptor schema = new SchemaDescriptor(1, cols, cols);
@@ -367,12 +365,12 @@ public class KvMarshallerTest {
SchemaDescriptor schema = new SchemaDescriptor(1, cols, cols);
- final ObjectFactory<TestObjectWithPrivateConstructor> objFactory = new ObjectFactory<>(TestObjectWithPrivateConstructor.class);
- final KvMarshaller<TestObjectWithPrivateConstructor, TestObjectWithPrivateConstructor> marshaller =
- factory.create(schema, TestObjectWithPrivateConstructor.class, TestObjectWithPrivateConstructor.class);
+ final ObjectFactory<PrivateTestObject> objFactory = new ObjectFactory<>(PrivateTestObject.class);
+ final KvMarshaller<PrivateTestObject, PrivateTestObject> marshaller =
+ factory.create(schema, PrivateTestObject.class, PrivateTestObject.class);
- final TestObjectWithPrivateConstructor key = TestObjectWithPrivateConstructor.randomObject(rnd);
- final TestObjectWithPrivateConstructor val = TestObjectWithPrivateConstructor.randomObject(rnd);
+ final PrivateTestObject key = PrivateTestObject.randomObject(rnd);
+ final PrivateTestObject val = PrivateTestObject.randomObject(rnd);
BinaryRow row = marshaller.marshal(key, objFactory.create());
@@ -520,6 +518,46 @@ public class KvMarshallerTest {
.defineClass(classDef, Object.class);
}
+ private Column[] columnsAllTypes() {
+ Column[] cols = new Column[]{
+ new Column("primitiveByteCol", INT8, false, () -> (byte) 0x42),
+ new Column("primitiveShortCol", INT16, false, () -> (short) 0x4242),
+ new Column("primitiveIntCol", INT32, false, () -> 0x42424242),
+ new Column("primitiveLongCol", INT64, false),
+ new Column("primitiveFloatCol", FLOAT, false),
+ new Column("primitiveDoubleCol", DOUBLE, false),
+
+ new Column("byteCol", INT8, true),
+ new Column("shortCol", INT16, true),
+ new Column("intCol", INT32, true),
+ new Column("longCol", INT64, true),
+ new Column("nullLongCol", INT64, true),
+ new Column("floatCol", FLOAT, true),
+ new Column("doubleCol", DOUBLE, true),
+
+ new Column("dateCol", DATE, true),
+ new Column("timeCol", time(), true),
+ new Column("dateTimeCol", datetime(), true),
+ new Column("timestampCol", timestamp(), true),
+
+ new Column("uuidCol", UUID, true),
+ new Column("bitmaskCol", NativeTypes.bitmaskOf(42), true),
+ new Column("stringCol", STRING, true),
+ new Column("nullBytesCol", BYTES, true),
+ new Column("bytesCol", BYTES, true),
+ new Column("numberCol", NativeTypes.numberOf(12), true),
+ new Column("decimalCol", NativeTypes.decimalOf(19, 3), true),
+ };
+ // Validate all types are tested.
+ Set<NativeTypeSpec> testedTypes = Arrays.stream(cols).map(c -> c.type().spec())
+ .collect(Collectors.toSet());
+ Set<NativeTypeSpec> missedTypes = Arrays.stream(NativeTypeSpec.values())
+ .filter(t -> !testedTypes.contains(t)).collect(Collectors.toSet());
+
+ assertEquals(Collections.emptySet(), missedTypes);
+ return cols;
+ }
+
/**
* Test object.
*/
@@ -656,43 +694,52 @@ public class KvMarshallerTest {
}
}
- private Column[] columnsAllTypes() {
- Column[] cols = new Column[]{
- new Column("primitiveByteCol", INT8, false, () -> (byte) 0x42),
- new Column("primitiveShortCol", INT16, false, () -> (short) 0x4242),
- new Column("primitiveIntCol", INT32, false, () -> 0x42424242),
- new Column("primitiveLongCol", INT64, false),
- new Column("primitiveFloatCol", FLOAT, false),
- new Column("primitiveDoubleCol", DOUBLE, false),
-
- new Column("byteCol", INT8, true),
- new Column("shortCol", INT16, true),
- new Column("intCol", INT32, true),
- new Column("longCol", INT64, true),
- new Column("nullLongCol", INT64, true),
- new Column("floatCol", FLOAT, true),
- new Column("doubleCol", DOUBLE, true),
-
- new Column("dateCol", DATE, true),
- new Column("timeCol", time(), true),
- new Column("dateTimeCol", datetime(), true),
- new Column("timestampCol", timestamp(), true),
-
- new Column("uuidCol", UUID, true),
- new Column("bitmaskCol", NativeTypes.bitmaskOf(42), true),
- new Column("stringCol", STRING, true),
- new Column("nullBytesCol", BYTES, true),
- new Column("bytesCol", BYTES, true),
- new Column("numberCol", NativeTypes.numberOf(12), true),
- new Column("decimalCol", NativeTypes.decimalOf(19, 3), true),
- };
- // Validate all types are tested.
- Set<NativeTypeSpec> testedTypes = Arrays.stream(cols).map(c -> c.type().spec())
- .collect(Collectors.toSet());
- Set<NativeTypeSpec> missedTypes = Arrays.stream(NativeTypeSpec.values())
- .filter(t -> !testedTypes.contains(t)).collect(Collectors.toSet());
+ /**
+ * Test object without default constructor.
+ */
+ @SuppressWarnings("InstanceVariableMayNotBeInitialized")
+ private static class PrivateTestObject {
+ /**
+ * Get random TestObject.
+ */
+ static PrivateTestObject randomObject(Random rnd) {
+ return new PrivateTestObject(rnd.nextInt());
+ }
- assertEquals(Collections.emptySet(), missedTypes);
- return cols;
+ /** Value. */
+ private long primLongCol;
+
+ /** Constructor. */
+ PrivateTestObject() {
+ }
+
+ /**
+ * Private constructor.
+ */
+ PrivateTestObject(long val) {
+ primLongCol = val;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ PrivateTestObject object = (PrivateTestObject) o;
+
+ return primLongCol == object.primLongCol;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return Objects.hash(primLongCol);
+ }
}
}
diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/MapperTest.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/MapperTest.java
new file mode 100644
index 0000000..1f1e90c
--- /dev/null
+++ b/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/MapperTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.schema.marshaller;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.apache.ignite.table.mapper.Mapper;
+import org.apache.ignite.table.mapper.MapperBuilder;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Columns mappers test.
+ */
+public class MapperTest {
+
+ @Test
+ public void misleadingMapping() {
+ // Empty mapping.
+ assertThrows(IllegalStateException.class, () -> Mapper.builderFor(TestObject.class).build());
+
+ // Many fields to one column.
+ assertThrows(IllegalArgumentException.class, () -> Mapper.builderFor(TestObject.class)
+ .map("id", "key")
+ .map("longCol", "key"));
+
+ // One field to many columns.
+ assertThrows(IllegalStateException.class, () -> Mapper.builderFor(TestObject.class)
+ .map("id", "key")
+ .map("id", "val1")
+ .map("stringCol", "val2")
+ .build());
+
+ // Mapper builder reuse fails.
+ assertThrows(IllegalStateException.class, () -> {
+ MapperBuilder<TestObject> builder = Mapper.builderFor(TestObject.class)
+ .map("id", "key");
+
+ builder.build();
+
+ builder.map("stringCol", "val2");
+ });
+ }
+
+ @Test
+ public void identityMapping() {
+ Mapper.identity(TestObject.class);
+ }
+
+ /**
+ * Test object.
+ */
+ @SuppressWarnings({"InstanceVariableMayNotBeInitialized", "unused"})
+ public static class TestObject {
+ private long id;
+
+ private long longCol;
+
+ private String stringCol;
+ }
+}
diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/KvMarshallerTest.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/RecordMarshallerTest.java
similarity index 50%
copy from modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/KvMarshallerTest.java
copy to modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/RecordMarshallerTest.java
index 87b1c96..c8ea50f 100644
--- a/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/KvMarshallerTest.java
+++ b/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/RecordMarshallerTest.java
@@ -30,13 +30,10 @@ import static org.apache.ignite.internal.schema.NativeTypes.UUID;
import static org.apache.ignite.internal.schema.NativeTypes.datetime;
import static org.apache.ignite.internal.schema.NativeTypes.time;
import static org.apache.ignite.internal.schema.NativeTypes.timestamp;
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.DynamicContainer.dynamicContainer;
-import static org.junit.jupiter.api.DynamicTest.dynamicTest;
import com.facebook.presto.bytecode.Access;
import com.facebook.presto.bytecode.BytecodeBlock;
@@ -47,6 +44,7 @@ import com.facebook.presto.bytecode.MethodDefinition;
import com.facebook.presto.bytecode.ParameterizedType;
import com.facebook.presto.bytecode.Variable;
import com.facebook.presto.bytecode.expression.BytecodeExpressions;
+import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
@@ -59,11 +57,9 @@ import java.util.stream.Stream;
import javax.annotation.processing.Generated;
import org.apache.ignite.internal.schema.BinaryRow;
import org.apache.ignite.internal.schema.Column;
-import org.apache.ignite.internal.schema.NativeType;
import org.apache.ignite.internal.schema.NativeTypeSpec;
import org.apache.ignite.internal.schema.NativeTypes;
import org.apache.ignite.internal.schema.SchemaDescriptor;
-import org.apache.ignite.internal.schema.SchemaTestUtils;
import org.apache.ignite.internal.schema.marshaller.reflection.ReflectionMarshallerFactory;
import org.apache.ignite.internal.schema.row.Row;
import org.apache.ignite.internal.schema.testobjects.TestObjectWithAllTypes;
@@ -74,17 +70,16 @@ import org.apache.ignite.internal.util.ObjectFactory;
import org.apache.ignite.lang.IgniteInternalException;
import org.apache.ignite.table.mapper.Mapper;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.DynamicNode;
-import org.junit.jupiter.api.TestFactory;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
/**
- * KvMarshaller test.
+ * RecordMarshaller test.
*/
-public class KvMarshallerTest {
+public class RecordMarshallerTest {
/**
- * Return list of marshaller factories for test.
+ * Returns list of marshaller factories for the test.
*/
private static List<MarshallerFactory> marshallerFactoryProvider() {
return List.of(new ReflectionMarshallerFactory());
@@ -94,7 +89,7 @@ public class KvMarshallerTest {
private Random rnd;
/**
- * Init test.
+ * Init random.
*/
@BeforeEach
public void initRandom() {
@@ -105,190 +100,129 @@ public class KvMarshallerTest {
rnd = new Random(seed);
}
- @TestFactory
- public Stream<DynamicNode> basicTypes() {
- NativeType[] types = new NativeType[]{INT8, INT16, INT32, INT64, FLOAT, DOUBLE, UUID, STRING, BYTES,
- NativeTypes.bitmaskOf(5), NativeTypes.numberOf(42), NativeTypes.decimalOf(12, 3)};
-
- return marshallerFactoryProvider().stream().map(factory ->
- dynamicContainer(
- factory.getClass().getSimpleName(),
- Stream.concat(
- // Test pure types.
- Stream.of(types).map(type ->
- dynamicTest("testBasicTypes(" + type.spec().name() + ')', () -> checkBasicType(factory, type, type))
- ),
-
- // Test pairs of mixed types.
- Stream.of(
- dynamicTest("testMixTypes 1", () -> checkBasicType(factory, INT64, INT32)),
- dynamicTest("testMixTypes 1", () -> checkBasicType(factory, FLOAT, DOUBLE)),
- dynamicTest("testMixTypes 1", () -> checkBasicType(factory, INT32, BYTES)),
- dynamicTest("testMixTypes 1", () -> checkBasicType(factory, STRING, INT64)),
- dynamicTest("testMixTypes 1", () -> checkBasicType(factory, NativeTypes.bitmaskOf(9), BYTES)),
- dynamicTest("testMixTypes 1", () -> checkBasicType(factory, NativeTypes.numberOf(12), BYTES)),
- dynamicTest("testMixTypes 1", () -> checkBasicType(factory, NativeTypes.decimalOf(12, 3), BYTES))
- )
- )
- ));
- }
-
@ParameterizedTest
@MethodSource("marshallerFactoryProvider")
- public void pojoWithFieldsOfAllTypes(MarshallerFactory factory) throws MarshallerException {
- Column[] cols = columnsAllTypes();
-
- SchemaDescriptor schema = new SchemaDescriptor(1, cols, cols);
+ public void complexType(MarshallerFactory factory) throws MarshallerException {
+ SchemaDescriptor schema = new SchemaDescriptor(1, keyColumns(), valueColumnsAllTypes());
- final TestObjectWithAllTypes key = TestObjectWithAllTypes.randomObject(rnd);
- final TestObjectWithAllTypes val = TestObjectWithAllTypes.randomObject(rnd);
+ final TestObjectWithAllTypes rec = TestObjectWithAllTypes.randomObject(rnd);
- KvMarshaller<TestObjectWithAllTypes, TestObjectWithAllTypes> marshaller =
- factory.create(schema, TestObjectWithAllTypes.class, TestObjectWithAllTypes.class);
+ RecordMarshaller<TestObjectWithAllTypes> marshaller = factory.create(schema, TestObjectWithAllTypes.class);
- BinaryRow row = marshaller.marshal(key, val);
+ BinaryRow row = marshaller.marshal(rec);
- // Try different order.
- TestObjectWithAllTypes restoredVal = marshaller.unmarshalValue(new Row(schema, row));
- TestObjectWithAllTypes restoredKey = marshaller.unmarshalKey(new Row(schema, row));
+ TestObjectWithAllTypes restoredRec = marshaller.unmarshal(new Row(schema, row));
- assertTrue(key.getClass().isInstance(restoredKey));
- assertTrue(val.getClass().isInstance(restoredVal));
+ assertTrue(rec.getClass().isInstance(restoredRec));
- assertEquals(key, restoredKey);
- assertEquals(val, restoredVal);
+ assertEquals(rec, restoredRec);
}
@ParameterizedTest
@MethodSource("marshallerFactoryProvider")
- public void narrowType(MarshallerFactory factory) throws MarshallerException {
- Column[] cols = columnsAllTypes();
+ public void truncatedType(MarshallerFactory factory) throws MarshallerException {
+ SchemaDescriptor schema = new SchemaDescriptor(1, keyColumns(), valueColumnsAllTypes());
- SchemaDescriptor schema = new SchemaDescriptor(1, cols, cols);
+ RecordMarshaller<TestTruncatedObject> marshaller = factory.create(schema, TestTruncatedObject.class);
- KvMarshaller<TestTruncatedObject, TestTruncatedObject> marshaller =
- factory.create(schema, TestTruncatedObject.class, TestTruncatedObject.class);
+ final TestTruncatedObject rec = TestTruncatedObject.randomObject(rnd);
- final TestTruncatedObject key = TestTruncatedObject.randomObject(rnd);
- final TestTruncatedObject val = TestTruncatedObject.randomObject(rnd);
+ BinaryRow row = marshaller.marshal(rec);
- BinaryRow row = marshaller.marshal(key, val);
+ Object restoredRec = marshaller.unmarshal(new Row(schema, row));
- // Try different order.
- Object restoredVal = marshaller.unmarshalValue(new Row(schema, row));
- Object restoredKey = marshaller.unmarshalKey(new Row(schema, row));
+ assertTrue(rec.getClass().isInstance(restoredRec));
- assertTrue(key.getClass().isInstance(restoredKey));
- assertTrue(val.getClass().isInstance(restoredVal));
-
- assertEquals(key, restoredKey);
- assertEquals(val, restoredVal);
+ assertEquals(rec, restoredRec);
}
@ParameterizedTest
@MethodSource("marshallerFactoryProvider")
- public void wideType(MarshallerFactory factory) throws MarshallerException {
- Column[] cols = new Column[]{
- new Column("primitiveLongCol", INT64, false),
- new Column("primitiveDoubleCol", DOUBLE, false),
- new Column("stringCol", STRING, true),
- };
-
- SchemaDescriptor schema = new SchemaDescriptor(1, cols, cols);
+ public void widerType(MarshallerFactory factory) throws MarshallerException {
+ SchemaDescriptor schema = new SchemaDescriptor(
+ 1,
+ keyColumns(),
+ new Column[]{
+ new Column("primitiveDoubleCol", DOUBLE, false),
+ new Column("stringCol", STRING, true),
+ }
+ );
- KvMarshaller<TestObjectWithAllTypes, TestObjectWithAllTypes> marshaller =
- factory.create(schema, TestObjectWithAllTypes.class, TestObjectWithAllTypes.class);
+ RecordMarshaller<TestObjectWithAllTypes> marshaller = factory.create(schema, TestObjectWithAllTypes.class);
- final TestObjectWithAllTypes key = TestObjectWithAllTypes.randomObject(rnd);
- final TestObjectWithAllTypes val = TestObjectWithAllTypes.randomObject(rnd);
+ final TestObjectWithAllTypes rec = TestObjectWithAllTypes.randomObject(rnd);
- BinaryRow row = marshaller.marshal(key, val);
+ BinaryRow row = marshaller.marshal(rec);
- // Try different order.
- TestObjectWithAllTypes restoredVal = marshaller.unmarshalValue(new Row(schema, row));
- TestObjectWithAllTypes restoredKey = marshaller.unmarshalKey(new Row(schema, row));
+ TestObjectWithAllTypes restoredRec = marshaller.unmarshal(new Row(schema, row));
- assertTrue(key.getClass().isInstance(restoredKey));
- assertTrue(val.getClass().isInstance(restoredVal));
+ assertTrue(rec.getClass().isInstance(restoredRec));
- TestObjectWithAllTypes expectedKey = new TestObjectWithAllTypes();
- expectedKey.setPrimitiveLongCol(key.getPrimitiveLongCol());
- expectedKey.setPrimitiveDoubleCol(key.getPrimitiveDoubleCol());
- expectedKey.setStringCol(key.getStringCol());
+ TestObjectWithAllTypes expectedRec = new TestObjectWithAllTypes();
- TestObjectWithAllTypes expectedVal = new TestObjectWithAllTypes();
- expectedVal.setPrimitiveLongCol(val.getPrimitiveLongCol());
- expectedVal.setPrimitiveDoubleCol(val.getPrimitiveDoubleCol());
- expectedVal.setStringCol(val.getStringCol());
+ expectedRec.setPrimitiveLongCol(rec.getPrimitiveLongCol());
+ expectedRec.setIntCol(rec.getIntCol());
+ expectedRec.setPrimitiveDoubleCol(rec.getPrimitiveDoubleCol());
+ expectedRec.setStringCol(rec.getStringCol());
- assertEquals(expectedKey, restoredKey);
- assertEquals(expectedVal, restoredVal);
+ assertEquals(expectedRec, restoredRec);
- assertNull(restoredKey.getUuidCol());
- assertNull(restoredVal.getUuidCol());
- assertEquals(0, restoredKey.getPrimitiveIntCol());
- assertEquals(0, restoredVal.getPrimitiveIntCol());
+ // Check non-mapped fields has default values.
+ assertNull(restoredRec.getUuidCol());
+ assertEquals(0, restoredRec.getPrimitiveIntCol());
}
@ParameterizedTest
@MethodSource("marshallerFactoryProvider")
- public void columnNameMapping(MarshallerFactory factory) throws MarshallerException {
+ public void mapping(MarshallerFactory factory) throws MarshallerException {
SchemaDescriptor schema = new SchemaDescriptor(1,
new Column[]{new Column("key", INT64, false)},
new Column[]{
- new Column("col1", INT64, false),
+ new Column("col1", INT32, false),
new Column("col2", INT64, true),
new Column("col3", STRING, false)
});
- Mapper<TestKeyObject> keyMapper = Mapper.builderFor(TestKeyObject.class)
+ Mapper<TestObject> mapper = Mapper.builderFor(TestObject.class)
.map("id", "key")
- .build();
-
- Mapper<TestObject> valMapper = Mapper.builderFor(TestObject.class)
- .map("longCol", "col1")
+ .map("intCol", "col1")
.map("stringCol", "col3")
.build();
- KvMarshaller<TestKeyObject, TestObject> marshaller = factory.create(schema, keyMapper, valMapper);
+ RecordMarshaller<TestObject> marshaller = factory.create(schema, mapper);
- final TestKeyObject key = TestKeyObject.randomObject(rnd);
- final TestObject val = TestObject.randomObject(rnd);
+ final TestObject rec = TestObject.randomObject(rnd);
- BinaryRow row = marshaller.marshal(key, val);
+ BinaryRow row = marshaller.marshal(rec);
- // Try different order.
- Object restoredVal = marshaller.unmarshalValue(new Row(schema, row));
- Object restoredKey = marshaller.unmarshalKey(new Row(schema, row));
+ Object restoredRec = marshaller.unmarshal(new Row(schema, row));
- assertTrue(key.getClass().isInstance(restoredKey));
- assertTrue(val.getClass().isInstance(restoredVal));
+ assertTrue(rec.getClass().isInstance(restoredRec));
- val.longCol2 = null;
+ rec.longCol2 = null; // Nullify non-mapped field.
- assertEquals(key, restoredKey);
- assertEquals(val, restoredVal);
+ assertEquals(rec, restoredRec);
}
@ParameterizedTest
@MethodSource("marshallerFactoryProvider")
public void classWithWrongFieldType(MarshallerFactory factory) {
- Column[] cols = new Column[]{
- new Column("bitmaskCol", NativeTypes.bitmaskOf(42), true),
- new Column("shortCol", UUID, true)
- };
-
- SchemaDescriptor schema = new SchemaDescriptor(1, cols, cols);
+ SchemaDescriptor schema = new SchemaDescriptor(
+ 1,
+ keyColumns(),
+ new Column[]{
+ new Column("bitmaskCol", NativeTypes.bitmaskOf(42), true),
+ new Column("shortCol", UUID, true)
+ }
+ );
- KvMarshaller<TestObjectWithAllTypes, TestObjectWithAllTypes> marshaller =
- factory.create(schema, TestObjectWithAllTypes.class, TestObjectWithAllTypes.class);
+ RecordMarshaller<TestObjectWithAllTypes> marshaller = factory.create(schema, TestObjectWithAllTypes.class);
- final TestObjectWithAllTypes key = TestObjectWithAllTypes.randomObject(rnd);
- final TestObjectWithAllTypes val = TestObjectWithAllTypes.randomObject(rnd);
+ final TestObjectWithAllTypes rec = TestObjectWithAllTypes.randomObject(rnd);
assertThrows(
MarshallerException.class,
- () -> marshaller.marshal(key, val),
+ () -> marshaller.marshal(rec),
"Failed to write field [name=shortCol]"
);
}
@@ -296,96 +230,85 @@ public class KvMarshallerTest {
@ParameterizedTest
@MethodSource("marshallerFactoryProvider")
public void classWithIncorrectBitmaskSize(MarshallerFactory factory) {
- Column[] cols = new Column[]{
- new Column("primitiveLongCol", INT64, false),
- new Column("bitmaskCol", NativeTypes.bitmaskOf(9), true),
- };
-
- SchemaDescriptor schema = new SchemaDescriptor(1, cols, cols);
+ SchemaDescriptor schema = new SchemaDescriptor(
+ 1,
+ keyColumns(),
+ new Column[]{
+ new Column("primitiveLongCol", INT64, false),
+ new Column("bitmaskCol", NativeTypes.bitmaskOf(9), true),
+ }
+ );
- KvMarshaller<TestObjectWithAllTypes, TestObjectWithAllTypes> marshaller =
- factory.create(schema, TestObjectWithAllTypes.class, TestObjectWithAllTypes.class);
+ RecordMarshaller<TestObjectWithAllTypes> marshaller = factory.create(schema, TestObjectWithAllTypes.class);
- final TestObjectWithAllTypes key = TestObjectWithAllTypes.randomObject(rnd);
- final TestObjectWithAllTypes val = TestObjectWithAllTypes.randomObject(rnd);
+ final TestObjectWithAllTypes rec = TestObjectWithAllTypes.randomObject(rnd);
assertThrows(
MarshallerException.class,
- () -> marshaller.marshal(key, val),
+ () -> marshaller.marshal(rec),
"Failed to write field [name=bitmaskCol]"
);
}
@ParameterizedTest
@MethodSource("marshallerFactoryProvider")
- public void classWithPrivateConstructor(MarshallerFactory factory) throws MarshallerException {
- Column[] cols = new Column[]{
- new Column("primLongCol", INT64, false),
- };
-
- SchemaDescriptor schema = new SchemaDescriptor(1, cols, cols);
-
- KvMarshaller<TestObjectWithPrivateConstructor, TestObjectWithPrivateConstructor> marshaller =
- factory.create(schema, TestObjectWithPrivateConstructor.class, TestObjectWithPrivateConstructor.class);
+ public void classWithPrivateConstructor(MarshallerFactory factory) throws MarshallerException, IllegalAccessException {
+ SchemaDescriptor schema = new SchemaDescriptor(
+ 1,
+ new Column[]{new Column("primLongCol", INT64, false)},
+ new Column[]{new Column("primIntCol", INT32, false)}
+ );
- final TestObjectWithPrivateConstructor key = TestObjectWithPrivateConstructor.randomObject(rnd);
- final TestObjectWithPrivateConstructor val = TestObjectWithPrivateConstructor.randomObject(rnd);
+ RecordMarshaller<TestObjectWithPrivateConstructor> marshaller = factory.create(schema, TestObjectWithPrivateConstructor.class);
- BinaryRow row = marshaller.marshal(key, val);
+ final TestObjectWithPrivateConstructor rec = TestObjectWithPrivateConstructor.randomObject(rnd);
- Object key1 = marshaller.unmarshalKey(new Row(schema, row));
- Object val1 = marshaller.unmarshalValue(new Row(schema, row));
+ BinaryRow row = marshaller.marshal(rec);
- assertTrue(key.getClass().isInstance(key1));
- assertTrue(val.getClass().isInstance(val1));
+ TestObjectWithPrivateConstructor restoredRec = marshaller.unmarshal(new Row(schema, row));
- assertEquals(key, key);
- assertEquals(val, val1);
+ assertDeepEquals(TestObjectWithPrivateConstructor.class, rec, restoredRec);
}
@ParameterizedTest
@MethodSource("marshallerFactoryProvider")
public void classWithNoDefaultConstructor(MarshallerFactory factory) {
- Column[] cols = new Column[]{
- new Column("primLongCol", INT64, false),
- };
-
- SchemaDescriptor schema = new SchemaDescriptor(1, cols, cols);
+ SchemaDescriptor schema = new SchemaDescriptor(
+ 1,
+ new Column[]{new Column("primLongCol", INT64, false)},
+ new Column[]{new Column("primIntCol", INT32, false)}
+ );
- final Object key = TestObjectWithNoDefaultConstructor.randomObject(rnd);
- final Object val = TestObjectWithNoDefaultConstructor.randomObject(rnd);
+ final Object rec = TestObjectWithNoDefaultConstructor.randomObject(rnd);
- assertThrows(IgniteInternalException.class, () -> factory.create(schema, key.getClass(), val.getClass()));
+ assertThrows(IgniteInternalException.class, () -> factory.create(schema, rec.getClass()));
}
-
+
@ParameterizedTest
@MethodSource("marshallerFactoryProvider")
public void privateClass(MarshallerFactory factory) throws MarshallerException {
- Column[] cols = new Column[]{
- new Column("primLongCol", INT64, false),
- };
-
- SchemaDescriptor schema = new SchemaDescriptor(1, cols, cols);
+ SchemaDescriptor schema = new SchemaDescriptor(
+ 1,
+ new Column[]{new Column("primLongCol", INT64, false)},
+ new Column[]{new Column("primIntCol", INT32, false)}
+ );
- final ObjectFactory<TestObjectWithPrivateConstructor> objFactory = new ObjectFactory<>(TestObjectWithPrivateConstructor.class);
- final KvMarshaller<TestObjectWithPrivateConstructor, TestObjectWithPrivateConstructor> marshaller =
- factory.create(schema, TestObjectWithPrivateConstructor.class, TestObjectWithPrivateConstructor.class);
+ final ObjectFactory<PrivateTestObject> objFactory = new ObjectFactory<>(PrivateTestObject.class);
+ final RecordMarshaller<PrivateTestObject> marshaller = factory
+ .create(schema, PrivateTestObject.class);
- final TestObjectWithPrivateConstructor key = TestObjectWithPrivateConstructor.randomObject(rnd);
- final TestObjectWithPrivateConstructor val = TestObjectWithPrivateConstructor.randomObject(rnd);
+ final PrivateTestObject rec = PrivateTestObject.randomObject(rnd);
- BinaryRow row = marshaller.marshal(key, objFactory.create());
+ BinaryRow row = marshaller.marshal(objFactory.create());
- Object key1 = marshaller.unmarshalKey(new Row(schema, row));
- Object val1 = marshaller.unmarshalValue(new Row(schema, row));
+ Object restoredRec = marshaller.unmarshal(new Row(schema, row));
- assertTrue(key.getClass().isInstance(key1));
- assertTrue(val.getClass().isInstance(val1));
+ assertTrue(rec.getClass().isInstance(restoredRec));
}
@ParameterizedTest
@MethodSource("marshallerFactoryProvider")
- public void classLoader(MarshallerFactory factory) throws MarshallerException {
+ public void classLoader(MarshallerFactory factory) throws MarshallerException, IllegalAccessException {
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(new DynamicClassLoader(getClass().getClassLoader()));
@@ -402,80 +325,36 @@ public class KvMarshallerTest {
SchemaDescriptor schema = new SchemaDescriptor(1, keyCols, valCols);
- final Class<?> valClass = createGeneratedObjectClass();
- final ObjectFactory<?> objFactory = new ObjectFactory<>(valClass);
-
- KvMarshaller<Long, Object> marshaller = factory.create(schema, Long.class, (Class<Object>) valClass);
+ final Class<Object> recClass = (Class<Object>) createGeneratedObjectClass();
+ final ObjectFactory<Object> objFactory = new ObjectFactory<>(recClass);
- final Long key = rnd.nextLong();
+ RecordMarshaller<Object> marshaller = factory.create(schema, recClass);
- BinaryRow row = marshaller.marshal(key, objFactory.create());
+ Object rec = objFactory.create();
- Long key1 = marshaller.unmarshalKey(new Row(schema, row));
- Object val1 = marshaller.unmarshalValue(new Row(schema, row));
+ BinaryRow row = marshaller.marshal(rec);
- assertTrue(valClass.isInstance(val1));
+ Object restoredRec = marshaller.unmarshal(new Row(schema, row));
- assertEquals(key, key1);
+ assertDeepEquals(recClass, rec, restoredRec);
} finally {
Thread.currentThread().setContextClassLoader(loader);
}
}
/**
- * Generate random key-value pair of given types and check serialization and deserialization works fine.
- *
- * @param factory KvMarshaller factory.
- * @param keyType Key type.
- * @param valType Value type.
- * @throws MarshallerException If (de)serialization failed.
+ * Validate all types are tested.
*/
- private void checkBasicType(MarshallerFactory factory, NativeType keyType,
- NativeType valType) throws MarshallerException {
- final Object key = generateRandomValue(keyType);
- final Object val = generateRandomValue(valType);
-
- Column[] keyCols = new Column[]{new Column("key", keyType, false)};
- Column[] valCols = new Column[]{new Column("val", valType, false)};
-
- SchemaDescriptor schema = new SchemaDescriptor(1, keyCols, valCols);
-
- KvMarshaller<Object, Object> marshaller = factory.create(schema, (Class<Object>) key.getClass(), (Class<Object>) val.getClass());
-
- BinaryRow row = marshaller.marshal(key, val);
-
- Object key1 = marshaller.unmarshalKey(new Row(schema, row));
- Object val1 = marshaller.unmarshalValue(new Row(schema, row));
+ @Test
+ public void ensureAllTypesChecked() {
+ Set<NativeTypeSpec> testedTypes = Stream.concat(Arrays.stream(keyColumns()), Arrays.stream(valueColumnsAllTypes()))
+ .map(c -> c.type().spec())
+ .collect(Collectors.toSet());
- assertTrue(key.getClass().isInstance(key1));
- assertTrue(val.getClass().isInstance(val1));
+ Set<NativeTypeSpec> missedTypes = Arrays.stream(NativeTypeSpec.values())
+ .filter(t -> !testedTypes.contains(t)).collect(Collectors.toSet());
- compareObjects(keyType, key, key);
- compareObjects(valType, val, val1);
- }
-
- /**
- * Compare object regarding NativeType.
- *
- * @param type Native type.
- * @param exp Expected value.
- * @param act Actual value.
- */
- private void compareObjects(NativeType type, Object exp, Object act) {
- if (type.spec() == NativeTypeSpec.BYTES) {
- assertArrayEquals((byte[]) exp, (byte[]) act);
- } else {
- assertEquals(exp, act);
- }
- }
-
- /**
- * Generates random value of given type.
- *
- * @param type Type.
- */
- private Object generateRandomValue(NativeType type) {
- return SchemaTestUtils.generateRandomValue(rnd, type);
+ assertEquals(Collections.emptySet(), missedTypes);
}
/**
@@ -494,6 +373,8 @@ public class KvMarshallerTest {
);
classDef.declareAnnotation(Generated.class).setValue("value", getClass().getCanonicalName());
+ classDef.declareField(EnumSet.of(Access.PRIVATE), "key", ParameterizedType.type(long.class));
+
for (int i = 0; i < 3; i++) {
classDef.declareField(EnumSet.of(Access.PRIVATE), "col" + i, ParameterizedType.type(long.class));
}
@@ -507,6 +388,8 @@ public class KvMarshallerTest {
.invokeConstructor(classDef.getSuperClass())
.append(rnd.set(BytecodeExpressions.newInstance(Random.class)));
+ body.append(methodDef.getThis().setField("key", rnd.invoke("nextLong", long.class).cast(long.class)));
+
for (int i = 0; i < 3; i++) {
body.append(methodDef.getThis().setField("col" + i, rnd.invoke("nextLong", long.class).cast(long.class)));
}
@@ -520,39 +403,51 @@ public class KvMarshallerTest {
.defineClass(classDef, Object.class);
}
- /**
- * Test object.
- */
- @SuppressWarnings("InstanceVariableMayNotBeInitialized")
- public static class TestKeyObject {
- static TestKeyObject randomObject(Random rnd) {
- final TestKeyObject obj = new TestKeyObject();
-
- obj.id = rnd.nextLong();
-
- return obj;
- }
-
- private long id;
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- TestKeyObject that = (TestKeyObject) o;
- return id == that.id;
- }
+ private <T> void assertDeepEquals(Class<T> recClass, T rec, T restoredRec) throws IllegalAccessException {
+ assertTrue(recClass.isInstance(restoredRec));
- @Override
- public int hashCode() {
- return Objects.hash(id);
+ for (Field fld : recClass.getDeclaredFields()) {
+ fld.setAccessible(true);
+ assertEquals(fld.get(rec), fld.get(restoredRec), fld.getName());
}
}
+ private Column[] keyColumns() {
+ return new Column[]{
+ new Column("primitiveLongCol", INT64, false),
+ new Column("intCol", INT32, true)
+ };
+ }
+
+ private Column[] valueColumnsAllTypes() {
+ return new Column[]{
+ new Column("primitiveByteCol", INT8, false, () -> (byte) 0x42),
+ new Column("primitiveShortCol", INT16, false, () -> (short) 0x4242),
+ new Column("primitiveIntCol", INT32, false, () -> 0x42424242),
+ new Column("primitiveFloatCol", FLOAT, false),
+ new Column("primitiveDoubleCol", DOUBLE, false),
+
+ new Column("byteCol", INT8, true),
+ new Column("shortCol", INT16, true),
+ new Column("longCol", INT64, true),
+ new Column("nullLongCol", INT64, true),
+ new Column("floatCol", FLOAT, true),
+ new Column("doubleCol", DOUBLE, true),
+
+ new Column("dateCol", DATE, true),
+ new Column("timeCol", time(), true),
+ new Column("dateTimeCol", datetime(), true),
+ new Column("timestampCol", timestamp(), true),
+
+ new Column("uuidCol", UUID, true),
+ new Column("bitmaskCol", NativeTypes.bitmaskOf(42), true),
+ new Column("stringCol", STRING, true),
+ new Column("nullBytesCol", BYTES, true),
+ new Column("bytesCol", BYTES, true),
+ new Column("numberCol", NativeTypes.numberOf(12), true),
+ new Column("decimalCol", NativeTypes.decimalOf(19, 3), true),
+ };
+ }
/**
* Test object.
@@ -562,14 +457,17 @@ public class KvMarshallerTest {
static TestObject randomObject(Random rnd) {
final TestObject obj = new TestObject();
- obj.longCol = rnd.nextLong();
+ obj.id = rnd.nextLong();
+ obj.intCol = rnd.nextInt();
obj.longCol2 = rnd.nextLong();
obj.stringCol = IgniteTestUtils.randomString(rnd, 100);
return obj;
}
- private long longCol;
+ private long id;
+
+ private int intCol;
private Long longCol2;
@@ -587,19 +485,20 @@ public class KvMarshallerTest {
TestObject that = (TestObject) o;
- return longCol == that.longCol
+ return id == that.id
+ && intCol == that.intCol
&& Objects.equals(longCol2, that.longCol2)
&& Objects.equals(stringCol, that.stringCol);
}
@Override
public int hashCode() {
- return Objects.hash(longCol, longCol2, stringCol);
+ return Objects.hash(id);
}
}
/**
- * Test object.
+ * Test object with less amount of fields.
*/
@SuppressWarnings("InstanceVariableMayNotBeInitialized")
public static class TestTruncatedObject {
@@ -629,7 +528,6 @@ public class KvMarshallerTest {
private java.util.UUID uuidCol;
- /** {@inheritDoc} */
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -649,50 +547,51 @@ public class KvMarshallerTest {
&& Objects.equals(uuidCol, ((TestTruncatedObject) o).uuidCol);
}
- /** {@inheritDoc} */
@Override
public int hashCode() {
return 42;
}
}
- private Column[] columnsAllTypes() {
- Column[] cols = new Column[]{
- new Column("primitiveByteCol", INT8, false, () -> (byte) 0x42),
- new Column("primitiveShortCol", INT16, false, () -> (short) 0x4242),
- new Column("primitiveIntCol", INT32, false, () -> 0x42424242),
- new Column("primitiveLongCol", INT64, false),
- new Column("primitiveFloatCol", FLOAT, false),
- new Column("primitiveDoubleCol", DOUBLE, false),
-
- new Column("byteCol", INT8, true),
- new Column("shortCol", INT16, true),
- new Column("intCol", INT32, true),
- new Column("longCol", INT64, true),
- new Column("nullLongCol", INT64, true),
- new Column("floatCol", FLOAT, true),
- new Column("doubleCol", DOUBLE, true),
-
- new Column("dateCol", DATE, true),
- new Column("timeCol", time(), true),
- new Column("dateTimeCol", datetime(), true),
- new Column("timestampCol", timestamp(), true),
-
- new Column("uuidCol", UUID, true),
- new Column("bitmaskCol", NativeTypes.bitmaskOf(42), true),
- new Column("stringCol", STRING, true),
- new Column("nullBytesCol", BYTES, true),
- new Column("bytesCol", BYTES, true),
- new Column("numberCol", NativeTypes.numberOf(12), true),
- new Column("decimalCol", NativeTypes.decimalOf(19, 3), true),
- };
- // Validate all types are tested.
- Set<NativeTypeSpec> testedTypes = Arrays.stream(cols).map(c -> c.type().spec())
- .collect(Collectors.toSet());
- Set<NativeTypeSpec> missedTypes = Arrays.stream(NativeTypeSpec.values())
- .filter(t -> !testedTypes.contains(t)).collect(Collectors.toSet());
+ /**
+ * Test object without default constructor.
+ */
+ @SuppressWarnings("InstanceVariableMayNotBeInitialized")
+ private static class PrivateTestObject {
+ static PrivateTestObject randomObject(Random rnd) {
+ return new PrivateTestObject(rnd.nextLong(), rnd.nextInt());
+ }
- assertEquals(Collections.emptySet(), missedTypes);
- return cols;
+ private long primLongCol;
+
+ private int primIntCol;
+
+ PrivateTestObject() {
+ }
+
+ PrivateTestObject(long longVal, int intVal) {
+ primLongCol = longVal;
+ primIntCol = intVal;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ PrivateTestObject object = (PrivateTestObject) o;
+
+ return primLongCol == object.primLongCol && primIntCol == object.primIntCol;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(primLongCol);
+ }
}
}
diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/testobjects/TestObjectWithNoDefaultConstructor.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/testobjects/TestObjectWithNoDefaultConstructor.java
index b26230e..f529940 100644
--- a/modules/schema/src/test/java/org/apache/ignite/internal/schema/testobjects/TestObjectWithNoDefaultConstructor.java
+++ b/modules/schema/src/test/java/org/apache/ignite/internal/schema/testobjects/TestObjectWithNoDefaultConstructor.java
@@ -28,25 +28,28 @@ public class TestObjectWithNoDefaultConstructor {
* Creates an object with random data.
*/
public static TestObjectWithNoDefaultConstructor randomObject(Random rnd) {
- return new TestObjectWithNoDefaultConstructor(rnd.nextLong());
+ return new TestObjectWithNoDefaultConstructor(rnd.nextLong(), rnd.nextInt());
}
- /** Value. */
private final long primLongCol;
+ private final int primIntCol;
+
/**
* Private constructor.
*/
- public TestObjectWithNoDefaultConstructor(long val) {
- primLongCol = val;
+ public TestObjectWithNoDefaultConstructor(long longVal, int intVal) {
+ primLongCol = longVal;
+ primIntCol = intVal;
}
/** {@inheritDoc} */
- @Override public boolean equals(Object o) {
+ @Override
+ public boolean equals(Object o) {
if (this == o) {
return true;
}
-
+
if (o == null || getClass() != o.getClass()) {
return false;
}
diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/testobjects/TestObjectWithPrivateConstructor.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/testobjects/TestObjectWithPrivateConstructor.java
index 291f301..e6c0898 100644
--- a/modules/schema/src/test/java/org/apache/ignite/internal/schema/testobjects/TestObjectWithPrivateConstructor.java
+++ b/modules/schema/src/test/java/org/apache/ignite/internal/schema/testobjects/TestObjectWithPrivateConstructor.java
@@ -32,13 +32,15 @@ public class TestObjectWithPrivateConstructor {
final TestObjectWithPrivateConstructor obj = new TestObjectWithPrivateConstructor();
obj.primLongCol = rnd.nextLong();
+ obj.primIntCol = rnd.nextInt();
return obj;
}
- /** Value. */
private long primLongCol;
+ private int primIntCol;
+
/**
* Private constructor.
*/
@@ -46,11 +48,12 @@ public class TestObjectWithPrivateConstructor {
}
/** {@inheritDoc} */
- @Override public boolean equals(Object o) {
+ @Override
+ public boolean equals(Object o) {
if (this == o) {
return true;
}
-
+
if (o == null || getClass() != o.getClass()) {
return false;
}
diff --git a/modules/table/src/main/java/org/apache/ignite/internal/table/KeyValueViewImpl.java b/modules/table/src/main/java/org/apache/ignite/internal/table/KeyValueViewImpl.java
index 118449b..f9c1f57 100644
--- a/modules/table/src/main/java/org/apache/ignite/internal/table/KeyValueViewImpl.java
+++ b/modules/table/src/main/java/org/apache/ignite/internal/table/KeyValueViewImpl.java
@@ -42,15 +42,11 @@ import org.jetbrains.annotations.Nullable;
* Key-value view implementation.
*/
public class KeyValueViewImpl<K, V> extends AbstractTableView implements KeyValueView<K, V> {
- /**
- * Marshaller factory.
- */
- private final Function<SchemaDescriptor, KvMarshallerImpl<K, V>> marshallerFactory;
+ /** Marshaller factory. */
+ private final Function<SchemaDescriptor, KvMarshaller<K, V>> marshallerFactory;
- /**
- * Marshaller.
- */
- private KvMarshallerImpl<K, V> marsh;
+ /** Key-value marshaller. */
+ private KvMarshaller<K, V> marsh;
/**
* Constructor.
diff --git a/modules/table/src/main/java/org/apache/ignite/internal/table/RecordViewImpl.java b/modules/table/src/main/java/org/apache/ignite/internal/table/RecordViewImpl.java
index 22e410d..9b89a6a 100644
--- a/modules/table/src/main/java/org/apache/ignite/internal/table/RecordViewImpl.java
+++ b/modules/table/src/main/java/org/apache/ignite/internal/table/RecordViewImpl.java
@@ -22,11 +22,15 @@ import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
import org.apache.ignite.internal.schema.BinaryRow;
import org.apache.ignite.internal.schema.SchemaDescriptor;
import org.apache.ignite.internal.schema.SchemaRegistry;
-import org.apache.ignite.internal.schema.marshaller.RecordSerializer;
+import org.apache.ignite.internal.schema.marshaller.MarshallerException;
+import org.apache.ignite.internal.schema.marshaller.RecordMarshaller;
+import org.apache.ignite.internal.schema.marshaller.reflection.RecordMarshallerImpl;
import org.apache.ignite.internal.schema.row.Row;
+import org.apache.ignite.lang.IgniteException;
import org.apache.ignite.table.InvokeProcessor;
import org.apache.ignite.table.RecordView;
import org.apache.ignite.table.mapper.Mapper;
@@ -38,6 +42,12 @@ import org.jetbrains.annotations.Nullable;
* Record view implementation.
*/
public class RecordViewImpl<R> extends AbstractTableView implements RecordView<R> {
+ /** Marshaller factory. */
+ private final Function<SchemaDescriptor, RecordMarshaller<R>> marshallerFactory;
+
+ /** Record marshaller. */
+ private RecordMarshaller<R> marsh;
+
/**
* Constructor.
*
@@ -48,202 +58,222 @@ public class RecordViewImpl<R> extends AbstractTableView implements RecordView<R
*/
public RecordViewImpl(InternalTable tbl, SchemaRegistry schemaReg, Mapper<R> mapper, @Nullable Transaction tx) {
super(tbl, schemaReg, tx);
+
+ marshallerFactory = (schema) -> new RecordMarshallerImpl<>(schema, mapper);
}
-
+
/** {@inheritDoc} */
@Override
public R get(@NotNull R keyRec) {
return sync(getAsync(keyRec));
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull CompletableFuture<R> getAsync(@NotNull R keyRec) {
Objects.requireNonNull(keyRec);
-
- RecordSerializer<R> marsh = serializer();
-
- Row keyRow = marsh.serialize(keyRec); // Convert to portable format to pass TX/storage layer.
-
+
+ BinaryRow keyRow = marshalKey(keyRec); // Convert to portable format to pass TX/storage layer.
+
return tbl.get(keyRow, tx) // Load async.
.thenApply(this::wrap) // Binary -> schema-aware row
- .thenApply(marsh::deserialize); // Deserialize.
+ .thenApply(this::unmarshal); // Deserialize.
}
-
+
/** {@inheritDoc} */
@Override
public Collection<R> getAll(@NotNull Collection<R> keyRecs) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ return sync(getAllAsync(keyRecs));
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull CompletableFuture<Collection<R>> getAllAsync(@NotNull Collection<R> keyRecs) {
throw new UnsupportedOperationException("Not implemented yet.");
}
-
+
/** {@inheritDoc} */
@Override
public void upsert(@NotNull R rec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ sync(upsertAsync(rec));
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull CompletableFuture<Void> upsertAsync(@NotNull R rec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ BinaryRow keyRow = marshal(Objects.requireNonNull(rec));
+
+ return tbl.upsert(keyRow, tx).thenAccept(ignore -> {
+ });
}
-
+
/** {@inheritDoc} */
@Override
public void upsertAll(@NotNull Collection<R> recs) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ sync(upsertAllAsync(recs));
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull CompletableFuture<Void> upsertAllAsync(@NotNull Collection<R> recs) {
throw new UnsupportedOperationException("Not implemented yet.");
}
-
+
/** {@inheritDoc} */
@Override
public R getAndUpsert(@NotNull R rec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ return sync(getAndUpsertAsync(rec));
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull CompletableFuture<R> getAndUpsertAsync(@NotNull R rec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ BinaryRow keyRow = marshal(Objects.requireNonNull(rec));
+
+ return tbl.getAndUpsert(keyRow, tx).thenApply(this::unmarshal);
}
-
+
/** {@inheritDoc} */
@Override
public boolean insert(@NotNull R rec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ return sync(insertAsync(rec));
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull CompletableFuture<Boolean> insertAsync(@NotNull R rec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ BinaryRow keyRow = marshal(Objects.requireNonNull(rec));
+
+ return tbl.insert(keyRow, tx);
}
-
+
/** {@inheritDoc} */
@Override
public Collection<R> insertAll(@NotNull Collection<R> recs) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ return sync(insertAllAsync(recs));
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull CompletableFuture<Collection<R>> insertAllAsync(@NotNull Collection<R> recs) {
throw new UnsupportedOperationException("Not implemented yet.");
}
-
+
/** {@inheritDoc} */
@Override
public boolean replace(@NotNull R rec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ return sync(replaceAsync(rec));
}
-
+
/** {@inheritDoc} */
@Override
public boolean replace(@NotNull R oldRec, @NotNull R newRec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ return sync(replaceAsync(oldRec, newRec));
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull CompletableFuture<Boolean> replaceAsync(@NotNull R rec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ BinaryRow newRow = marshal(rec);
+
+ return tbl.replace(newRow, tx);
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull CompletableFuture<Boolean> replaceAsync(@NotNull R oldRec, @NotNull R newRec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ BinaryRow oldRow = marshal(oldRec);
+ BinaryRow newRow = marshal(newRec);
+
+ return tbl.replace(oldRow, newRow, tx);
}
-
+
/** {@inheritDoc} */
@Override
public R getAndReplace(@NotNull R rec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ return sync(getAndReplaceAsync(rec));
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull CompletableFuture<R> getAndReplaceAsync(@NotNull R rec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ BinaryRow row = marshal(rec);
+
+ return tbl.getAndReplace(row, tx).thenApply(this::unmarshal);
}
-
+
/** {@inheritDoc} */
@Override
public boolean delete(@NotNull R keyRec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ return sync(deleteAsync(keyRec));
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull CompletableFuture<Boolean> deleteAsync(@NotNull R keyRec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ BinaryRow row = marshalKey(keyRec);
+
+ return tbl.delete(row, tx);
}
-
+
/** {@inheritDoc} */
@Override
public boolean deleteExact(@NotNull R rec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ return sync(deleteExactAsync(rec));
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull CompletableFuture<Boolean> deleteExactAsync(@NotNull R rec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ BinaryRow row = marshal(rec);
+
+ return tbl.deleteExact(row, tx);
}
-
+
/** {@inheritDoc} */
@Override
public R getAndDelete(@NotNull R rec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ return sync(getAndDeleteAsync(rec));
}
-
+
/** {@inheritDoc} */
@Override
- public @NotNull CompletableFuture<R> getAndDeleteAsync(@NotNull R rec) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ public @NotNull CompletableFuture<R> getAndDeleteAsync(@NotNull R keyRec) {
+ BinaryRow row = marshalKey(keyRec);
+
+ return tbl.getAndDelete(row, tx).thenApply(this::unmarshal);
}
-
+
/** {@inheritDoc} */
@Override
public Collection<R> deleteAll(@NotNull Collection<R> recs) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ return sync(deleteAllAsync(recs));
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull CompletableFuture<Collection<R>> deleteAllAsync(@NotNull Collection<R> recs) {
throw new UnsupportedOperationException("Not implemented yet.");
}
-
+
/** {@inheritDoc} */
@Override
public Collection<R> deleteAllExact(@NotNull Collection<R> recs) {
- throw new UnsupportedOperationException("Not implemented yet.");
+ return sync(deleteAllExactAsync(recs));
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull CompletableFuture<Collection<R>> deleteAllExactAsync(@NotNull Collection<R> recs) {
throw new UnsupportedOperationException("Not implemented yet.");
}
-
+
/** {@inheritDoc} */
@Override
public <T extends Serializable> T invoke(@NotNull R keyRec, InvokeProcessor<R, R, T> proc) {
throw new UnsupportedOperationException("Not implemented yet.");
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull <T extends Serializable> CompletableFuture<T> invokeAsync(
@@ -252,7 +282,7 @@ public class RecordViewImpl<R> extends AbstractTableView implements RecordView<R
) {
throw new UnsupportedOperationException("Not implemented yet.");
}
-
+
/** {@inheritDoc} */
@Override
public <T extends Serializable> Map<R, T> invokeAll(
@@ -261,7 +291,7 @@ public class RecordViewImpl<R> extends AbstractTableView implements RecordView<R
) {
throw new UnsupportedOperationException("Not implemented yet.");
}
-
+
/** {@inheritDoc} */
@Override
public @NotNull <T extends Serializable> CompletableFuture<Map<R, T>> invokeAllAsync(
@@ -270,20 +300,83 @@ public class RecordViewImpl<R> extends AbstractTableView implements RecordView<R
) {
throw new UnsupportedOperationException("Not implemented yet.");
}
-
+
/** {@inheritDoc} */
@Override
public RecordViewImpl<R> withTransaction(Transaction tx) {
throw new UnsupportedOperationException("Not implemented yet.");
}
-
+
+ /**
/**
* Returns marshaller.
+ *
+ * @param schemaVersion Schema version.
+ * @return Marshaller.
*/
- private RecordSerializer<R> serializer() {
- throw new UnsupportedOperationException("Not implemented yet.");
+ private RecordMarshaller<R> marshaller(int schemaVersion) {
+ if (marsh == null || marsh.schemaVersion() == schemaVersion) {
+ // TODO: Cache marshaller for schema version or upgrade row?
+ marsh = marshallerFactory.apply(schemaReg.schema(schemaVersion));
+ }
+
+ return marsh;
}
-
+
+ /**
+ * Marshals given record to a row.
+ *
+ * @param rec Record object.
+ * @return Binary row.
+ */
+ private BinaryRow marshal(@NotNull R rec) {
+ final RecordMarshaller<R> marsh = marshaller(schemaReg.lastSchemaVersion());
+
+ try {
+ return marsh.marshal(rec);
+ } catch (MarshallerException e) {
+ throw new IgniteException(e);
+ }
+ }
+
+ /**
+ * Marshals given key record to a row.
+ *
+ * @param rec Record key object.
+ * @return Binary row.
+ */
+ private BinaryRow marshalKey(@NotNull R rec) {
+ final RecordMarshaller<R> marsh = marshaller(schemaReg.lastSchemaVersion());
+
+ try {
+ return marsh.marshalKey(rec);
+ } catch (MarshallerException e) {
+ throw new IgniteException(e);
+ }
+ }
+
+ /**
+ * Unmarshal value object from given binary row.
+ *
+ * @param binaryRow Binary row.
+ * @return Value object.
+ */
+ private R unmarshal(BinaryRow binaryRow) {
+ if (binaryRow == null || !binaryRow.hasValue()) {
+ return null;
+ }
+
+ Row row = schemaReg.resolve(binaryRow);
+
+ RecordMarshaller<R> marshaller = marshaller(row.schemaVersion());
+
+ try {
+ return marshaller.unmarshal(row);
+ } catch (MarshallerException e) {
+ throw new IgniteException(e);
+ }
+ }
+
/**
* Returns schema-aware row.
*
@@ -293,9 +386,9 @@ public class RecordViewImpl<R> extends AbstractTableView implements RecordView<R
if (row == null) {
return null;
}
-
+
final SchemaDescriptor rowSchema = schemaReg.schema(row.schemaVersion()); // Get a schema for row.
-
+
return new Row(rowSchema, row);
}
}
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/KeyValueViewOperationsTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/KeyValueViewOperationsTest.java
index 9416953..3f9b361 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/KeyValueViewOperationsTest.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/KeyValueViewOperationsTest.java
@@ -126,11 +126,11 @@ public class KeyValueViewOperationsTest {
assertNull(tbl.get(key));
- // Insert new tuple.
+ // Insert new KV pair.
assertNull(tbl.getAndPut(key, obj));
-
assertEquals(obj, tbl.get(key));
-
+
+ // Update KV pair.
assertEquals(obj, tbl.getAndPut(key, obj2));
assertEquals(obj2, tbl.getAndPut(key, obj3));
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/RecordViewOperationsTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/RecordViewOperationsTest.java
new file mode 100644
index 0000000..602a849
--- /dev/null
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/RecordViewOperationsTest.java
@@ -0,0 +1,340 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.table;
+
+import static org.apache.ignite.internal.schema.NativeTypes.BYTES;
+import static org.apache.ignite.internal.schema.NativeTypes.DATE;
+import static org.apache.ignite.internal.schema.NativeTypes.DOUBLE;
+import static org.apache.ignite.internal.schema.NativeTypes.FLOAT;
+import static org.apache.ignite.internal.schema.NativeTypes.INT16;
+import static org.apache.ignite.internal.schema.NativeTypes.INT32;
+import static org.apache.ignite.internal.schema.NativeTypes.INT64;
+import static org.apache.ignite.internal.schema.NativeTypes.INT8;
+import static org.apache.ignite.internal.schema.NativeTypes.STRING;
+import static org.apache.ignite.internal.schema.NativeTypes.datetime;
+import static org.apache.ignite.internal.schema.NativeTypes.time;
+import static org.apache.ignite.internal.schema.NativeTypes.timestamp;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Random;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.ignite.internal.schema.Column;
+import org.apache.ignite.internal.schema.NativeTypeSpec;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.schema.SchemaDescriptor;
+import org.apache.ignite.internal.schema.testobjects.TestObjectWithAllTypes;
+import org.apache.ignite.internal.table.impl.DummyInternalTableImpl;
+import org.apache.ignite.internal.table.impl.DummySchemaManagerImpl;
+import org.apache.ignite.table.RecordView;
+import org.apache.ignite.table.mapper.Mapper;
+import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Basic table operations test.
+ */
+//TODO: IGNITE-14487 Add bulk operations tests.
+//TODO: IGNITE-14487 Add async operations tests.
+public class RecordViewOperationsTest {
+
+ private final Random rnd = new Random();
+
+ @Test
+ public void upsert() {
+ final TestObjectWithAllTypes key = key(rnd);
+
+ final TestObjectWithAllTypes obj = randomObject(rnd, key);
+ final TestObjectWithAllTypes obj2 = randomObject(rnd, key);
+ final TestObjectWithAllTypes obj3 = randomObject(rnd, key);
+
+ RecordView<TestObjectWithAllTypes> tbl = recordView();
+
+ assertNull(tbl.get(key));
+
+ // Insert new row.
+ tbl.upsert(obj);
+ assertEquals(obj, tbl.get(key));
+
+ // Upsert row.
+ tbl.upsert(obj2);
+ assertEquals(obj2, tbl.get(key));
+
+ // Remove row.
+ tbl.delete(key);
+ assertNull(tbl.get(key));
+
+ // Insert new row.
+ tbl.upsert(obj3);
+ assertEquals(obj3, tbl.get(key));
+ }
+
+ @Test
+ public void insert() {
+ final TestObjectWithAllTypes key = key(rnd);
+ final TestObjectWithAllTypes obj = randomObject(rnd, key);
+ final TestObjectWithAllTypes obj2 = randomObject(rnd, key);
+
+ RecordView<TestObjectWithAllTypes> tbl = recordView();
+
+ assertNull(tbl.get(key));
+
+ // Insert new row.
+ assertTrue(tbl.insert(obj));
+ assertEquals(obj, tbl.get(key));
+
+ // Ignore existed row pair.
+ assertFalse(tbl.insert(obj2));
+ assertEquals(obj, tbl.get(key));
+ }
+
+ @Test
+ public void getAndUpsert() {
+ final TestObjectWithAllTypes key = key(rnd);
+ final TestObjectWithAllTypes obj = randomObject(rnd, key);
+ final TestObjectWithAllTypes obj2 = randomObject(rnd, key);
+ final TestObjectWithAllTypes obj3 = randomObject(rnd, key);
+
+ RecordView<TestObjectWithAllTypes> tbl = recordView();
+
+ assertNull(tbl.get(key));
+
+ // Insert new row.
+ assertNull(tbl.getAndUpsert(obj));
+ assertEquals(obj, tbl.get(key));
+
+ // Update exited row.
+ assertEquals(obj, tbl.getAndUpsert(obj2));
+ assertEquals(obj2, tbl.getAndUpsert(obj3));
+
+ assertEquals(obj3, tbl.get(key));
+ }
+
+ @Test
+ public void remove() {
+ final TestObjectWithAllTypes key = key(rnd);
+ final TestObjectWithAllTypes obj = randomObject(rnd, key);
+ final TestObjectWithAllTypes obj2 = randomObject(rnd, key);
+
+ RecordView<TestObjectWithAllTypes> tbl = recordView();
+
+ // Delete not existed key.
+ assertNull(tbl.get(key));
+ assertFalse(tbl.delete(key));
+
+ // Insert a new row.
+ tbl.upsert(obj);
+
+ // Delete existed row.
+ assertEquals(obj, tbl.get(key));
+ assertTrue(tbl.delete(key));
+ assertNull(tbl.get(key));
+
+ // Delete already deleted row.
+ assertFalse(tbl.delete(key));
+
+ // Insert a new row.
+ tbl.upsert(obj2);
+ assertEquals(obj2, tbl.get(key));
+ }
+
+ @Test
+ public void removeExact() {
+ final TestObjectWithAllTypes key = key(rnd);
+ final TestObjectWithAllTypes obj = randomObject(rnd, key);
+ final TestObjectWithAllTypes obj2 = randomObject(rnd, key);
+
+ RecordView<TestObjectWithAllTypes> tbl = recordView();
+
+ // Insert a new row.
+ tbl.upsert(obj);
+ assertEquals(obj, tbl.get(key));
+
+ // Fails to delete row with unexpected value.
+ assertFalse(tbl.deleteExact(obj2));
+ assertEquals(obj, tbl.get(key));
+
+ // Delete row with expected value.
+ assertTrue(tbl.deleteExact(obj));
+ assertNull(tbl.get(key));
+
+ // Try to remove non-existed key.
+ assertFalse(tbl.deleteExact(obj));
+ assertNull(tbl.get(key));
+
+ // Insert a new row.
+ tbl.upsert(obj2);
+ assertEquals(obj2, tbl.get(key));
+
+ // Delete row with expected value.
+ assertTrue(tbl.delete(obj2));
+ assertNull(tbl.get(key));
+
+ assertFalse(tbl.delete(obj2));
+ assertNull(tbl.get(obj2));
+ }
+
+ @Test
+ public void replace() {
+ final TestObjectWithAllTypes key = key(rnd);
+ final TestObjectWithAllTypes obj = randomObject(rnd, key);
+ final TestObjectWithAllTypes obj2 = randomObject(rnd, key);
+ final TestObjectWithAllTypes obj3 = randomObject(rnd, key);
+
+ RecordView<TestObjectWithAllTypes> tbl = recordView();
+
+ // Ignore replace operation for non-existed row.
+ assertFalse(tbl.replace(obj));
+ assertNull(tbl.get(key));
+
+ // Insert new row.
+ tbl.upsert(obj);
+
+ // Replace existed row.
+ assertTrue(tbl.replace(obj2));
+ assertEquals(obj2, tbl.get(key));
+
+ // Replace existed row.
+ assertTrue(tbl.replace(obj3));
+ assertEquals(obj3, tbl.get(key));
+
+ // Remove existed row.
+ assertTrue(tbl.delete(key));
+ assertNull(tbl.get(key));
+
+ tbl.upsert(obj);
+ assertEquals(obj, tbl.get(key));
+ }
+
+ @Test
+ public void replaceExact() {
+ final TestObjectWithAllTypes key = key(rnd);
+ final TestObjectWithAllTypes obj = randomObject(rnd, key);
+ final TestObjectWithAllTypes obj2 = randomObject(rnd, key);
+ final TestObjectWithAllTypes obj3 = randomObject(rnd, key);
+ final TestObjectWithAllTypes obj4 = randomObject(rnd, key);
+
+ RecordView<TestObjectWithAllTypes> tbl = recordView();
+
+ // Ignore replace operation for non-existed row.
+ assertFalse(tbl.replace(obj, obj2));
+ assertNull(tbl.get(key));
+
+ // Insert new row.
+ tbl.upsert(obj);
+
+ // Ignore un-exepected row replacement.
+ assertFalse(tbl.replace(obj2, obj3));
+ assertEquals(obj, tbl.get(key));
+
+ // Replace existed row.
+ assertTrue(tbl.replace(obj, obj2));
+ assertEquals(obj2, tbl.get(key));
+
+ // Replace existed KV pair.
+ assertTrue(tbl.replace(obj2, obj3));
+ assertEquals(obj3, tbl.get(key));
+
+ // Remove existed row.
+ assertTrue(tbl.delete(key));
+ assertNull(tbl.get(key));
+
+ assertFalse(tbl.replace(key, obj4));
+ assertNull(tbl.get(key));
+ }
+
+ /**
+ * Creates RecordView.
+ */
+ private RecordViewImpl<TestObjectWithAllTypes> recordView() {
+ Mapper<TestObjectWithAllTypes> recMapper = Mapper.identity(TestObjectWithAllTypes.class);
+
+ Column[] valCols = {
+ new Column("primitiveByteCol", INT8, false),
+ new Column("primitiveShortCol", INT16, false),
+ new Column("primitiveIntCol", INT32, false),
+ new Column("primitiveFloatCol", FLOAT, false),
+ new Column("primitiveDoubleCol", DOUBLE, false),
+
+ new Column("byteCol", INT8, true),
+ new Column("shortCol", INT16, true),
+ new Column("intCol", INT32, true),
+ new Column("longCol", INT64, true),
+ new Column("nullLongCol", INT64, true),
+ new Column("floatCol", FLOAT, true),
+ new Column("doubleCol", DOUBLE, true),
+
+ new Column("dateCol", DATE, true),
+ new Column("timeCol", time(), true),
+ new Column("dateTimeCol", datetime(), true),
+ new Column("timestampCol", timestamp(), true),
+
+ new Column("uuidCol", NativeTypes.UUID, true),
+ new Column("bitmaskCol", NativeTypes.bitmaskOf(42), true),
+ new Column("stringCol", STRING, true),
+ new Column("nullBytesCol", BYTES, true),
+ new Column("bytesCol", BYTES, true),
+ new Column("numberCol", NativeTypes.numberOf(12), true),
+ new Column("decimalCol", NativeTypes.decimalOf(19, 3), true),
+ };
+
+ SchemaDescriptor schema = new SchemaDescriptor(
+ 1,
+ new Column[]{new Column("primitiveLongCol", NativeTypes.INT64, false)},
+ valCols
+ );
+
+ // Validate all types are tested.
+ Set<NativeTypeSpec> testedTypes = Arrays.stream(valCols).map(c -> c.type().spec())
+ .collect(Collectors.toSet());
+ Set<NativeTypeSpec> missedTypes = Arrays.stream(NativeTypeSpec.values())
+ .filter(t -> !testedTypes.contains(t)).collect(Collectors.toSet());
+
+ assertEquals(Collections.emptySet(), missedTypes);
+
+ return new RecordViewImpl<>(
+ new DummyInternalTableImpl(),
+ new DummySchemaManagerImpl(schema),
+ recMapper,
+ null
+ );
+ }
+
+ @NotNull
+ private TestObjectWithAllTypes randomObject(Random rnd, TestObjectWithAllTypes key) {
+ TestObjectWithAllTypes obj = TestObjectWithAllTypes.randomObject(rnd);
+
+ obj.setPrimitiveLongCol(key.getPrimitiveLongCol());
+
+ return obj;
+ }
+
+ @NotNull
+ private static TestObjectWithAllTypes key(Random rnd) {
+ TestObjectWithAllTypes key = new TestObjectWithAllTypes();
+
+ key.setPrimitiveLongCol(rnd.nextLong());
+
+ return key;
+ }
+}