You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2021/07/27 12:18:12 UTC
[ignite-3] branch main updated: IGNITE-14342 Extend Tuple interface
with ordered field access
This is an automated email from the ASF dual-hosted git repository.
ptupitsyn 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 a007259 IGNITE-14342 Extend Tuple interface with ordered field access
a007259 is described below
commit a00725987cdf49bb54246c552e000b4ad6832b8e
Author: Pavel Tupitsyn <pt...@apache.org>
AuthorDate: Tue Jul 27 15:17:44 2021 +0300
IGNITE-14342 Extend Tuple interface with ordered field access
To enable efficient data access, extend `Tuple` interface with:
* `int columnCount()`
* `String columnName(int columnIndex)`
* `Integer columnIndex(String columnName)`
* `T value(int columnIndex)` and typed overloads
* `extends Iterable<Object>`
Inspired by standard APIs like JDBC, ODBC, ADO.NET:
* https://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
* https://docs.microsoft.com/en-us/dotnet/api/system.data.common.dbdatareader?view=net-5.0
---
.../main/java/org/apache/ignite/table/Tuple.java | 164 +++++++++++++---
.../java/org/apache/ignite/table/TupleBuilder.java | 4 +-
.../handler/ClientInboundMessageHandler.java | 6 +-
.../ignite/internal/client/table/ClientSchema.java | 12 ++
.../ignite/internal/client/table/ClientTable.java | 20 +-
.../internal/client/table/ClientTupleBuilder.java | 209 +++++++++++++++++----
.../apache/ignite/client/AbstractClientTest.java | 8 +-
.../org/apache/ignite/client/ClientTableTest.java | 27 ++-
.../ignite/client/ClientTupleBuilderTest.java | 196 +++++++++++++++++++
.../ignite/internal/schema/SchemaDescriptor.java | 15 ++
.../internal/table/LiveSchemaTupleBuilderImpl.java | 8 +-
.../ignite/internal/table/RowChunkAdapter.java | 160 +++++++++++++---
.../ignite/internal/table/TupleBuilderImpl.java | 171 +++++++++++++----
.../org/apache/ignite/internal/table/Example.java | 8 +-
.../internal/table/TupleBuilderImplTest.java | 133 +++++++++++++
.../internal/table/impl/TestTupleBuilder.java | 129 ++++++++++---
16 files changed, 1100 insertions(+), 170 deletions(-)
diff --git a/modules/api/src/main/java/org/apache/ignite/table/Tuple.java b/modules/api/src/main/java/org/apache/ignite/table/Tuple.java
index 2b63d01..adc38e4 100644
--- a/modules/api/src/main/java/org/apache/ignite/table/Tuple.java
+++ b/modules/api/src/main/java/org/apache/ignite/table/Tuple.java
@@ -26,103 +26,215 @@ import org.apache.ignite.binary.BinaryObject;
* <p>
* Provides specialized method for some value-types to avoid boxing/unboxing.
*/
-public interface Tuple {
+public interface Tuple extends Iterable<Object> {
/**
- * Returns {@code true} if this tuple contains a column with the specified name.
+ * Gets the number of columns in this tuple.
*
- * @param colName Column name.
+ * @return Number of columns.
+ */
+ int columnCount();
+
+ /**
+ * Gets the name of the column with the specified index.
+ *
+ * @param columnIndex Column index.
+ * @return Column name.
+ */
+ String columnName(int columnIndex);
+
+ /**
+ * Gets the index of the column with the specified name.
+ *
+ * @param columnName Column name.
+ * @return Column index, or null when a column with given name is not present.
+ */
+ Integer columnIndex(String columnName);
+
+ /**
+ * Gets column value when a column with specified name is present in this tuple; returns default value otherwise.
+ *
+ * @param columnName Column name.
* @param def Default value.
* @param <T> Column default value type.
* @return Column value if this tuple contains a column with the specified name. Otherwise returns {@code default}.
*/
- <T> T valueOrDefault(String colName, T def);
+ <T> T valueOrDefault(String columnName, T def);
/**
* Gets column value for given column name.
*
- * @param colName Column name.
+ * @param columnName Column name.
+ * @param <T> Value type.
+ * @return Column value.
+ */
+ <T> T value(String columnName);
+
+ /**
+ * Gets column value for given column index.
+ *
+ * @param columnIndex Column index.
* @param <T> Value type.
* @return Column value.
*/
- <T> T value(String colName);
+ <T> T value(int columnIndex);
/**
* Gets binary object column.
*
- * @param colName Column name.
+ * @param columnName Column name.
* @return Column value.
*/
- BinaryObject binaryObjectField(String colName);
+ BinaryObject binaryObjectValue(String columnName);
+
+ /**
+ * Gets binary object column.
+ *
+ * @param columnIndex Column index.
+ * @return Column value.
+ */
+ BinaryObject binaryObjectValue(int columnIndex);
+
+ /**
+ * Gets {@code byte} column value.
+ *
+ * @param columnName Column name.
+ * @return Column value.
+ */
+ byte byteValue(String columnName);
/**
* Gets {@code byte} column value.
*
- * @param colName Column name.
+ * @param columnIndex Column index.
* @return Column value.
*/
- byte byteValue(String colName);
+ byte byteValue(int columnIndex);
/**
* Gets {@code short} column value.
*
- * @param colName Column name.
+ * @param columnName Column name.
+ * @return Column value.
+ */
+ short shortValue(String columnName);
+
+ /**
+ * Gets {@code short} column value.
+ *
+ * @param columnIndex Column index.
+ * @return Column value.
+ */
+ short shortValue(int columnIndex);
+
+ /**
+ * Gets {@code int} column value.
+ *
+ * @param columnName Column name.
* @return Column value.
*/
- short shortValue(String colName);
+ int intValue(String columnName);
/**
* Gets {@code int} column value.
*
- * @param colName Column name.
+ * @param columnIndex Column index.
+ * @return Column value.
+ */
+ int intValue(int columnIndex);
+
+ /**
+ * Gets {@code long} column value.
+ *
+ * @param columnName Column name.
* @return Column value.
*/
- int intValue(String colName);
+ long longValue(String columnName);
/**
* Gets {@code long} column value.
*
- * @param colName Column name.
+ * @param columnIndex Column index.
+ * @return Column value.
+ */
+ long longValue(int columnIndex);
+
+ /**
+ * Gets {@code float} column value.
+ *
+ * @param columnName Column name.
* @return Column value.
*/
- long longValue(String colName);
+ float floatValue(String columnName);
/**
* Gets {@code float} column value.
*
- * @param colName Column name.
+ * @param columnIndex Column index.
* @return Column value.
*/
- float floatValue(String colName);
+ float floatValue(int columnIndex);
/**
* Gets {@code double} column value.
*
- * @param colName Column name.
+ * @param columnName Column name.
* @return Column value.
*/
- double doubleValue(String colName);
+ double doubleValue(String columnName);
+
+ /**
+ * Gets {@code double} column value.
+ *
+ * @param columnIndex Column index.
+ * @return Column value.
+ */
+ double doubleValue(int columnIndex);
+
+ /**
+ * Gets {@code String} column value.
+ *
+ * @param columnName Column name.
+ * @return Column value.
+ */
+ String stringValue(String columnName);
/**
* Gets {@code String} column value.
*
- * @param colName Column name.
+ * @param columnIndex Column index.
* @return Column value.
*/
- String stringValue(String colName);
+ String stringValue(int columnIndex);
/**
* Gets {@code UUID} column value.
*
- * @param colName Column name.
+ * @param columnName Column name.
+ * @return Column value.
+ */
+ UUID uuidValue(String columnName);
+
+ /**
+ * Gets {@code UUID} column value.
+ *
+ * @param columnIndex Column index.
+ * @return Column value.
+ */
+ UUID uuidValue(int columnIndex);
+
+ /**
+ * Gets {@code BitSet} column value.
+ *
+ * @param columnName Column name.
* @return Column value.
*/
- UUID uuidValue(String colName);
+ BitSet bitmaskValue(String columnName);
/**
* Gets {@code BitSet} column value.
*
- * @param colName Column name.
+ * @param columnIndex Column index.
* @return Column value.
*/
- BitSet bitmaskValue(String colName);
+ BitSet bitmaskValue(int columnIndex);
}
diff --git a/modules/api/src/main/java/org/apache/ignite/table/TupleBuilder.java b/modules/api/src/main/java/org/apache/ignite/table/TupleBuilder.java
index db3e527..6ab4766 100644
--- a/modules/api/src/main/java/org/apache/ignite/table/TupleBuilder.java
+++ b/modules/api/src/main/java/org/apache/ignite/table/TupleBuilder.java
@@ -24,11 +24,11 @@ public interface TupleBuilder {
/**
* Sets column value.
*
- * @param colName Column name.
+ * @param columnName Column name.
* @param value Value to set.
* @return {@code this} for chaining.
*/
- TupleBuilder set(String colName, Object value);
+ TupleBuilder set(String columnName, Object value);
/**
* Builds tuple.
diff --git a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/ClientInboundMessageHandler.java b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/ClientInboundMessageHandler.java
index be18616..1510691 100644
--- a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/ClientInboundMessageHandler.java
+++ b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/ClientInboundMessageHandler.java
@@ -41,10 +41,10 @@ import org.apache.ignite.internal.schema.SchemaAware;
import org.apache.ignite.internal.schema.SchemaDescriptor;
import org.apache.ignite.internal.table.IgniteTablesInternal;
import org.apache.ignite.internal.table.TableImpl;
-import org.apache.ignite.internal.table.TupleBuilderImpl;
import org.apache.ignite.lang.IgniteException;
import org.apache.ignite.table.Table;
import org.apache.ignite.table.Tuple;
+import org.apache.ignite.table.TupleBuilder;
import org.msgpack.core.MessageFormat;
import org.msgpack.core.buffer.ByteBufferInput;
import org.slf4j.Logger;
@@ -340,7 +340,7 @@ public class ClientInboundMessageHandler extends ChannelInboundHandlerAdapter {
private Tuple readTuple(ClientMessageUnpacker unpacker, TableImpl table, boolean keyOnly) throws IOException {
var schemaId = unpacker.unpackInt();
var schema = table.schemaView().schema(schemaId);
- var builder = (TupleBuilderImpl) table.tupleBuilder();
+ var builder = table.tupleBuilder();
var cnt = keyOnly ? schema.keyColumns().length() : schema.length();
@@ -375,7 +375,7 @@ public class ClientInboundMessageHandler extends ChannelInboundHandlerAdapter {
return ((IgniteTablesInternal)ignite.tables()).table(tableId);
}
- private void readAndSetColumnValue(ClientMessageUnpacker unpacker, TupleBuilderImpl builder, Column col)
+ private void readAndSetColumnValue(ClientMessageUnpacker unpacker, TupleBuilder builder, Column col)
throws IOException {
builder.set(col.name(), unpacker.unpackObject(getClientDataType(col.type().spec())));
}
diff --git a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientSchema.java b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientSchema.java
index d3b3a8c..c4bcb11 100644
--- a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientSchema.java
+++ b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientSchema.java
@@ -22,6 +22,7 @@ import java.util.Map;
import org.apache.ignite.lang.IgniteException;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
/**
* Client schema.
@@ -83,6 +84,7 @@ public class ClientSchema {
*
* @param name Column name.
* @return Column by name.
+ * @throws IgniteException When a column with the specified name does not exist.
*/
public @NotNull ClientColumn column(String name) {
var column = map.get(name);
@@ -94,6 +96,16 @@ public class ClientSchema {
}
/**
+ * Gets a column by name.
+ *
+ * @param name Column name.
+ * @return Column by name.
+ */
+ public @Nullable ClientColumn columnSafe(String name) {
+ return map.get(name);
+ }
+
+ /**
* @return Key column count.
*/
public int keyColumnCount() {
diff --git a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTable.java b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTable.java
index c766206..071f26b 100644
--- a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTable.java
+++ b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTable.java
@@ -124,7 +124,7 @@ public class ClientTable implements Table {
/** {@inheritDoc} */
@Override public TupleBuilder tupleBuilder() {
- return new ClientTupleBuilder();
+ return new ClientTupleBuilder(getLatestSchema().join());
}
/** {@inheritDoc} */
@@ -181,7 +181,7 @@ public class ClientTable implements Table {
/** {@inheritDoc} */
@Override public @NotNull CompletableFuture<Void> upsertAllAsync(@NotNull Collection<Tuple> recs) {
- return null;
+ throw new UnsupportedOperationException();
}
/** {@inheritDoc} */
@@ -402,19 +402,17 @@ public class ClientTable implements Table {
}
private void writeTuple(@NotNull Tuple tuple, ClientSchema schema, PayloadOutputChannel w, boolean keyOnly) throws IOException {
- // TODO: We should accept any Tuple implementation, but this requires extending the Tuple interface
- // with methods to retrieve column list.
- var rec = (ClientTupleBuilder) tuple;
-
var vals = new Object[keyOnly ? schema.keyColumnCount() : schema.columns().length];
+ var tupleSize = tuple.columnCount();
- for (var entry : rec.map().entrySet()) {
- var col = schema.column(entry.getKey());
+ for (var i = 0; i < tupleSize; i++) {
+ var colName = tuple.columnName(i);
+ var col = schema.column(colName);
if (keyOnly && !col.key())
continue;
- vals[col.schemaIndex()] = entry.getValue();
+ vals[col.schemaIndex()] = tuple.value(i);
}
w.out().packUuid(id);
@@ -425,11 +423,11 @@ public class ClientTable implements Table {
}
private Tuple readTuple(ClientSchema schema, PayloadInputChannel r) {
- var builder = new ClientTupleBuilder();
+ var builder = new ClientTupleBuilder(schema);
try {
for (var col : schema.columns())
- builder.set(col.name(), r.in().unpackObject(col.type()));
+ builder.setInternal(col.schemaIndex(), r.in().unpackObject(col.type()));
} catch (IOException e) {
throw new CompletionException(e);
}
diff --git a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTupleBuilder.java b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTupleBuilder.java
index 4aa7266..4079248 100644
--- a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTupleBuilder.java
+++ b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTupleBuilder.java
@@ -18,33 +18,46 @@
package org.apache.ignite.internal.client.table;
import java.util.BitSet;
-import java.util.HashMap;
+import java.util.Iterator;
import java.util.UUID;
import org.apache.ignite.binary.BinaryObject;
-import org.apache.ignite.lang.IgniteException;
import org.apache.ignite.table.Tuple;
import org.apache.ignite.table.TupleBuilder;
+import org.jetbrains.annotations.NotNull;
/**
* Client tuple builder.
*/
public final class ClientTupleBuilder implements TupleBuilder, Tuple {
+ /** Null object to differentiate unset values and null values. */
+ private static final Object NULL_OBJ = new Object();
+
/** Columns values. */
- private final HashMap<String, Object> map = new HashMap<>();
+ private final Object[] vals;
+
+ /** Schema. */
+ private final ClientSchema schema;
/**
- * Gets the underlying map.
+ * Constructor.
*
- * @return Underlying map
+ * @param schema Schema.
*/
- public HashMap<String, Object> map() {
- return map;
+ public ClientTupleBuilder(ClientSchema schema) {
+ assert schema != null : "Schema can't be null.";
+ assert schema.columns().length > 0 : "Schema can't be empty.";
+
+ this.schema = schema;
+ this.vals = new Object[schema.columns().length];
}
/** {@inheritDoc} */
- @Override public TupleBuilder set(String colName, Object value) {
- map.put(colName, value);
+ @Override public TupleBuilder set(String columnName, Object value) {
+ // TODO: Live schema support IGNITE-15194
+ var col = schema.column(columnName);
+
+ vals[col.schemaIndex()] = value == null ? NULL_OBJ : value;
return this;
}
@@ -55,62 +68,192 @@ public final class ClientTupleBuilder implements TupleBuilder, Tuple {
}
/** {@inheritDoc} */
- @Override public <T> T valueOrDefault(String colName, T def) {
- return (T)map.getOrDefault(colName, def);
+ @Override public <T> T valueOrDefault(String columnName, T def) {
+ var col = schema.columnSafe(columnName);
+
+ if (col == null)
+ return def;
+
+ var val = (T)vals[col.schemaIndex()];
+
+ return val == null ? def : convertValue(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T> T value(String columnName) {
+ var col = schema.column(columnName);
+
+ return getValue(col.schemaIndex());
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T> T value(int columnIndex) {
+ validateColumnIndex(columnIndex);
+
+ return getValue(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int columnCount() {
+ return vals.length;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String columnName(int columnIndex) {
+ validateColumnIndex(columnIndex);
+
+ return schema.columns()[columnIndex].name();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Integer columnIndex(String columnName) {
+ var col = schema.columnSafe(columnName);
+
+ return col == null ? null : col.schemaIndex();
+ }
+
+ /** {@inheritDoc} */
+ @Override public BinaryObject binaryObjectValue(String columnName) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override public BinaryObject binaryObjectValue(int columnIndex) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override public byte byteValue(String columnName) {
+ return value(columnName);
}
/** {@inheritDoc} */
- @Override public <T> T value(String colName) {
- return (T)map.get(colName);
+ @Override public byte byteValue(int columnIndex) {
+ return value(columnIndex);
}
/** {@inheritDoc} */
- @Override public BinaryObject binaryObjectField(String colName) {
- throw new IgniteException("Not supported");
+ @Override public short shortValue(String columnName) {
+ return value(columnName);
}
/** {@inheritDoc} */
- @Override public byte byteValue(String colName) {
- return value(colName);
+ @Override public short shortValue(int columnIndex) {
+ return value(columnIndex);
}
/** {@inheritDoc} */
- @Override public short shortValue(String colName) {
- return value(colName);
+ @Override public int intValue(String columnName) {
+ return value(columnName);
}
/** {@inheritDoc} */
- @Override public int intValue(String colName) {
- return value(colName);
+ @Override public int intValue(int columnIndex) {
+ return value(columnIndex);
}
/** {@inheritDoc} */
- @Override public long longValue(String colName) {
- return value(colName);
+ @Override public long longValue(String columnName) {
+ return value(columnName);
}
/** {@inheritDoc} */
- @Override public float floatValue(String colName) {
- return value(colName);
+ @Override public long longValue(int columnIndex) {
+ return value(columnIndex);
}
/** {@inheritDoc} */
- @Override public double doubleValue(String colName) {
- return value(colName);
+ @Override public float floatValue(String columnName) {
+ return value(columnName);
}
/** {@inheritDoc} */
- @Override public String stringValue(String colName) {
- return value(colName);
+ @Override public float floatValue(int columnIndex) {
+ return value(columnIndex);
}
/** {@inheritDoc} */
- @Override public UUID uuidValue(String colName) {
- return value(colName);
+ @Override public double doubleValue(String columnName) {
+ return value(columnName);
}
/** {@inheritDoc} */
- @Override public BitSet bitmaskValue(String colName) {
- return value(colName);
+ @Override public double doubleValue(int columnIndex) {
+ return value(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String stringValue(String columnName) {
+ return value(columnName);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String stringValue(int columnIndex) {
+ return value(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public UUID uuidValue(String columnName) {
+ return value(columnName);
+ }
+
+ /** {@inheritDoc} */
+ @Override public UUID uuidValue(int columnIndex) {
+ return value(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public BitSet bitmaskValue(String columnName) {
+ return value(columnName);
+ }
+
+ /** {@inheritDoc} */
+ @Override public BitSet bitmaskValue(int columnIndex) {
+ return value(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @NotNull @Override public Iterator<Object> iterator() {
+ return new Iterator<>() {
+ /** Current column index. */
+ private int cur;
+
+ /** {@inheritDoc} */
+ @Override public boolean hasNext() {
+ return cur < vals.length;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object next() {
+ return cur < vals.length ? vals[cur++] : null;
+ }
+ };
+ }
+
+ /**
+ * Sets column value by index.
+ *
+ * @param columnIndex Column index.
+ * @param value Value to set.
+ */
+ public void setInternal(int columnIndex, Object value) {
+ // Do not validate column index for internal needs.
+ vals[columnIndex] = value;
+ }
+
+ private void validateColumnIndex(int columnIndex) {
+ if (columnIndex < 0)
+ throw new IllegalArgumentException("Column index can't be negative");
+
+ if (columnIndex >= vals.length)
+ throw new IllegalArgumentException("Column index can't be greater than " + (vals.length - 1));
+ }
+
+ private <T> T getValue(int columnIndex) {
+ return convertValue((T)vals[columnIndex]);
+ }
+
+ private static <T> T convertValue(T val) {
+ return val == NULL_OBJ ? null : val;
}
}
diff --git a/modules/client/src/test/java/org/apache/ignite/client/AbstractClientTest.java b/modules/client/src/test/java/org/apache/ignite/client/AbstractClientTest.java
index 8177a61..f1a562f 100644
--- a/modules/client/src/test/java/org/apache/ignite/client/AbstractClientTest.java
+++ b/modules/client/src/test/java/org/apache/ignite/client/AbstractClientTest.java
@@ -102,9 +102,11 @@ public abstract class AbstractClientTest {
var a = (ClientTupleBuilder) x;
var b = (ClientTupleBuilder) y;
- assertEquals(a.map().size(), b.map().size());
+ assertEquals(a.columnCount(), b.columnCount());
- for (var kv : a.map().entrySet())
- assertEquals(kv.getValue(), b.map().get(kv.getKey()), kv.getKey());
+ for (var i = 0; i < a.columnCount(); i++) {
+ assertEquals(a.columnName(i), b.columnName(i));
+ assertEquals((Object)a.value(i), b.value(i));
+ }
}
}
diff --git a/modules/client/src/test/java/org/apache/ignite/client/ClientTableTest.java b/modules/client/src/test/java/org/apache/ignite/client/ClientTableTest.java
index 1d4a39a..11e184a 100644
--- a/modules/client/src/test/java/org/apache/ignite/client/ClientTableTest.java
+++ b/modules/client/src/test/java/org/apache/ignite/client/ClientTableTest.java
@@ -24,6 +24,8 @@ import org.apache.ignite.table.Tuple;
import org.junit.jupiter.api.Test;
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.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -35,11 +37,12 @@ public class ClientTableTest extends AbstractClientTest {
public void testGetWithNullInNotNullableKeyColumnThrowsException() {
Table table = getDefaultTable();
- var key = table.tupleBuilder().set("foo", "123").build();
+ var key = table.tupleBuilder().set("name", "123").build();
var ex = assertThrows(CompletionException.class, () -> table.get(key));
- assertTrue(ex.getMessage().contains("Column is not present in schema: foo"), ex.getMessage());
+ assertTrue(ex.getMessage().contains("Failed to set column (null was passed, but column is not nullable)"),
+ ex.getMessage());
}
@Test
@@ -58,6 +61,26 @@ public class ClientTableTest extends AbstractClientTest {
assertEquals("John", resTuple.stringValue("name"));
assertEquals(123L, resTuple.longValue("id"));
+ assertEquals("foo", resTuple.valueOrDefault("bar", "foo"));
+
+ assertEquals("John", resTuple.value(1));
+ assertEquals(123L, (Long) resTuple.value(0));
+
+ assertEquals(2, resTuple.columnCount());
+ assertEquals("id", resTuple.columnName(0));
+ assertEquals("name", resTuple.columnName(1));
+
+ var iter = tuple.iterator();
+
+ assertTrue(iter.hasNext());
+ assertEquals(123L, iter.next());
+
+ assertTrue(iter.hasNext());
+ assertEquals("John", iter.next());
+
+ assertFalse(iter.hasNext());
+ assertNull(iter.next());
+
assertTupleEquals(tuple, resTuple);
}
diff --git a/modules/client/src/test/java/org/apache/ignite/client/ClientTupleBuilderTest.java b/modules/client/src/test/java/org/apache/ignite/client/ClientTupleBuilderTest.java
new file mode 100644
index 0000000..592988f
--- /dev/null
+++ b/modules/client/src/test/java/org/apache/ignite/client/ClientTupleBuilderTest.java
@@ -0,0 +1,196 @@
+/*
+ * 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.client;
+
+import java.util.BitSet;
+import java.util.UUID;
+
+import org.apache.ignite.client.proto.ClientDataType;
+import org.apache.ignite.internal.client.table.ClientColumn;
+import org.apache.ignite.internal.client.table.ClientSchema;
+import org.apache.ignite.internal.client.table.ClientTupleBuilder;
+import org.apache.ignite.lang.IgniteException;
+import org.apache.ignite.table.Tuple;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * Tests client tuple builder implementation.
+ *
+ * Should be in sync with org.apache.ignite.internal.table.TupleBuilderImplTest.
+ */
+public class ClientTupleBuilderTest {
+ private static final ClientSchema SCHEMA = new ClientSchema(1, new ClientColumn[] {
+ new ClientColumn("id", ClientDataType.INT64, false, true, 0),
+ new ClientColumn("name", ClientDataType.STRING, false, false, 1)
+ });
+
+ @Test
+ public void testValueReturnsValueByName() {
+ assertEquals(3L, (Long) getTuple().value("id"));
+ assertEquals("Shirt", getTuple().value("name"));
+ }
+
+ @Test
+ public void testValueReturnsValueByIndex() {
+ assertEquals(3L, (Long) getTuple().value(0));
+ assertEquals("Shirt", getTuple().value(1));
+ }
+
+ @Test
+ public void testValueOrDefaultReturnsValueByName() {
+ assertEquals(3L, getTuple().valueOrDefault("id", -1L));
+ assertEquals("Shirt", getTuple().valueOrDefault("name", "y"));
+ }
+
+ @Test
+ public void testValueOrDefaultReturnsDefaultWhenColumnIsNotPresent() {
+ assertEquals("foo", getBuilder().valueOrDefault("x", "foo"));
+ }
+
+ @Test
+ public void testValueOrDefaultReturnsDefaultWhenColumnIsPresentButNotSet() {
+ assertEquals("foo", getBuilder().valueOrDefault("name", "foo"));
+ }
+
+ @Test
+ public void testValueOrDefaultReturnsNullWhenColumnIsSetToNull() {
+ var tuple = getBuilder().set("name", null).build();
+
+ assertNull(tuple.valueOrDefault("name", "foo"));
+ }
+
+ @Test
+ public void testEmptySchemaThrows() {
+ assertThrows(AssertionError.class, () -> new ClientTupleBuilder(new ClientSchema(1, new ClientColumn[0])));
+ }
+
+ @Test
+ public void testSetThrowsWhenColumnIsNotPresent() {
+ var ex = assertThrows(IgniteException.class, () -> getBuilder().set("x", "y"));
+ assertEquals("Column is not present in schema: x", ex.getMessage());
+ }
+
+ @Test
+ public void testValueThrowsWhenColumnIsNotPresent() {
+ var ex = assertThrows(IgniteException.class, () -> getBuilder().value("x"));
+ assertEquals("Column is not present in schema: x", ex.getMessage());
+
+ var ex2 = assertThrows(IllegalArgumentException.class, () -> getBuilder().value(100));
+ assertEquals("Column index can't be greater than 1", ex2.getMessage());
+ }
+
+ @Test
+ public void testColumnCountReturnsSchemaSize() {
+ assertEquals(SCHEMA.columns().length, getTuple().columnCount());
+ }
+
+ @Test
+ public void testColumnNameReturnsNameByIndex() {
+ assertEquals("id", getTuple().columnName(0));
+ assertEquals("name", getTuple().columnName(1));
+ }
+
+ @Test
+ public void testColumnNameThrowsOnInvalidIndex() {
+ var ex = assertThrows(IllegalArgumentException.class, () -> getTuple().columnName(-1));
+ assertEquals("Column index can't be negative", ex.getMessage());
+ }
+
+ @Test
+ public void testColumnIndexReturnsIndexByName() {
+ assertEquals(0, getTuple().columnIndex("id"));
+ assertEquals(1, getTuple().columnIndex("name"));
+ }
+
+ @Test
+ public void testColumnIndexReturnsNullForMissingColumns() {
+ assertNull(getTuple().columnIndex("foo"));
+ }
+
+ @Test
+ public void testTypedGetters() {
+ var schema = new ClientSchema(100, new ClientColumn[] {
+ new ClientColumn("i8", ClientDataType.INT8, false, false, 0),
+ new ClientColumn("i16", ClientDataType.INT16, false, false, 1),
+ new ClientColumn("i32", ClientDataType.INT32, false, false, 2),
+ new ClientColumn("i64", ClientDataType.INT64, false, false, 3),
+ new ClientColumn("float", ClientDataType.FLOAT, false, false, 4),
+ new ClientColumn("double", ClientDataType.DOUBLE, false, false, 5),
+ new ClientColumn("uuid", ClientDataType.UUID, false, false, 6),
+ new ClientColumn("str", ClientDataType.STRING, false, false, 7),
+ new ClientColumn("bits", ClientDataType.BITMASK, false, false, 8),
+ });
+
+ var uuid = UUID.randomUUID();
+
+ var builder = new ClientTupleBuilder(schema)
+ .set("i8", (byte)1)
+ .set("i16", (short)2)
+ .set("i32", (int)3)
+ .set("i64", (long)4)
+ .set("float", (float)5.5)
+ .set("double", (double)6.6)
+ .set("uuid", uuid)
+ .set("str", "8")
+ .set("bits", new BitSet(3));
+
+ var tuple = builder.build();
+
+ assertEquals(1, tuple.byteValue(0));
+ assertEquals(1, tuple.byteValue("i8"));
+
+ assertEquals(2, tuple.shortValue(1));
+ assertEquals(2, tuple.shortValue("i16"));
+
+ assertEquals(3, tuple.intValue(2));
+ assertEquals(3, tuple.intValue("i32"));
+
+ assertEquals(4, tuple.longValue(3));
+ assertEquals(4, tuple.longValue("i64"));
+
+ assertEquals(5.5, tuple.floatValue(4));
+ assertEquals(5.5, tuple.floatValue("float"));
+
+ assertEquals(6.6, tuple.doubleValue(5));
+ assertEquals(6.6, tuple.doubleValue("double"));
+
+ assertEquals(uuid, tuple.uuidValue(6));
+ assertEquals(uuid, tuple.uuidValue("uuid"));
+
+ assertEquals("8", tuple.stringValue(7));
+ assertEquals("8", tuple.stringValue("str"));
+
+ assertEquals(0, tuple.bitmaskValue(8).length());
+ assertEquals(0, tuple.bitmaskValue("bits").length());
+ }
+
+ private static ClientTupleBuilder getBuilder() {
+ return new ClientTupleBuilder(SCHEMA);
+ }
+
+ private static Tuple getTuple() {
+ return new ClientTupleBuilder(SCHEMA)
+ .set("id", 3L)
+ .set("name", "Shirt")
+ .build();
+ }
+}
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaDescriptor.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaDescriptor.java
index 35144bb..db18506 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaDescriptor.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaDescriptor.java
@@ -119,10 +119,25 @@ public class SchemaDescriptor implements Serializable {
* @return Column instance.
*/
public Column column(int colIdx) {
+ validateColumnIndex(colIdx);
+
return colIdx < keyCols.length() ? keyCols.column(colIdx) : valCols.column(colIdx - keyCols.length());
}
/**
+ * Validates the column index.
+ *
+ * @param colIdx Column index.
+ */
+ public void validateColumnIndex(int colIdx) {
+ if (colIdx < 0)
+ throw new IllegalArgumentException("Column index can't be negative");
+
+ if (colIdx >= length())
+ throw new IllegalArgumentException("Column index can't be greater than " + (length() - 1));
+ }
+
+ /**
* Gets columns names.
*
* @return Columns names.
diff --git a/modules/table/src/main/java/org/apache/ignite/internal/table/LiveSchemaTupleBuilderImpl.java b/modules/table/src/main/java/org/apache/ignite/internal/table/LiveSchemaTupleBuilderImpl.java
index 4f8ed1f..4cca5ff 100644
--- a/modules/table/src/main/java/org/apache/ignite/internal/table/LiveSchemaTupleBuilderImpl.java
+++ b/modules/table/src/main/java/org/apache/ignite/internal/table/LiveSchemaTupleBuilderImpl.java
@@ -69,8 +69,8 @@ public class LiveSchemaTupleBuilderImpl extends TupleBuilderImpl {
}
/** {@inheritDoc} */
- @Override public TupleBuilder set(String colName, Object val) {
- Column col = schema().column(colName);
+ @Override public TupleBuilder set(String columnName, Object val) {
+ Column col = schema().column(columnName);
if (col == null) {
if (val == null)
@@ -79,11 +79,11 @@ public class LiveSchemaTupleBuilderImpl extends TupleBuilderImpl {
if (extraColumnsMap == null)
extraColumnsMap = new HashMap<>();
- extraColumnsMap.put(colName, val);
+ extraColumnsMap.put(columnName, val);
return this;
}
- super.set(colName, val);
+ super.set(columnName, val);
return this;
}
diff --git a/modules/table/src/main/java/org/apache/ignite/internal/table/RowChunkAdapter.java b/modules/table/src/main/java/org/apache/ignite/internal/table/RowChunkAdapter.java
index dc57d67..d1cddd7 100644
--- a/modules/table/src/main/java/org/apache/ignite/internal/table/RowChunkAdapter.java
+++ b/modules/table/src/main/java/org/apache/ignite/internal/table/RowChunkAdapter.java
@@ -18,6 +18,7 @@
package org.apache.ignite.internal.table;
import java.util.BitSet;
+import java.util.Iterator;
import java.util.UUID;
import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.binary.BinaryObjects;
@@ -44,9 +45,26 @@ public abstract class RowChunkAdapter implements Tuple, SchemaAware {
protected abstract Row row();
/** {@inheritDoc} */
- @Override public <T> T valueOrDefault(String colName, T def) {
+ @Override public int columnCount() {
+ return schema().length();
+ }
+
+ /** {@inheritDoc} */
+ @Override public String columnName(int columnIndex) {
+ return schema().column(columnIndex).name();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Integer columnIndex(String columnName) {
+ var col = schema().column(columnName);
+
+ return col == null ? null : col.schemaIndex();
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T> T valueOrDefault(String columnName, T def) {
try {
- return value(colName);
+ return value(columnName);
}
catch (ColumnNotFoundException ex) {
return def;
@@ -54,79 +72,173 @@ public abstract class RowChunkAdapter implements Tuple, SchemaAware {
}
/** {@inheritDoc} */
- @Override public <T> T value(String colName) {
- final Column col = columnByName(colName);
+ @Override public <T> T value(String columnName) {
+ final Column col = columnByName(columnName);
+
+ return (T)col.type().spec().objectValue(row(), col.schemaIndex());
+ }
+
+ @Override public <T> T value(int columnIndex) {
+ final Column col = schema().column(columnIndex);
return (T)col.type().spec().objectValue(row(), col.schemaIndex());
}
/** {@inheritDoc} */
- @Override public BinaryObject binaryObjectField(String colName) {
- Column col = columnByName(colName);
+ @Override public BinaryObject binaryObjectValue(String columnName) {
+ Column col = columnByName(columnName);
return BinaryObjects.wrap(row().bytesValue(col.schemaIndex()));
}
/** {@inheritDoc} */
- @Override public byte byteValue(String colName) {
- Column col = columnByName(colName);
+ @Override public BinaryObject binaryObjectValue(int columnIndex) {
+ schema().validateColumnIndex(columnIndex);
+
+ return BinaryObjects.wrap(row().bytesValue(columnIndex));
+ }
+
+ /** {@inheritDoc} */
+ @Override public byte byteValue(String columnName) {
+ Column col = columnByName(columnName);
return row().byteValue(col.schemaIndex());
}
/** {@inheritDoc} */
- @Override public short shortValue(String colName) {
- Column col = columnByName(colName);
+ @Override public byte byteValue(int columnIndex) {
+ schema().validateColumnIndex(columnIndex);
+
+ return row().byteValue(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public short shortValue(String columnName) {
+ Column col = columnByName(columnName);
return row().shortValue(col.schemaIndex());
}
/** {@inheritDoc} */
- @Override public int intValue(String colName) {
- Column col = columnByName(colName);
+ @Override public short shortValue(int columnIndex) {
+ schema().validateColumnIndex(columnIndex);
+
+ return row().shortValue(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int intValue(String columnName) {
+ Column col = columnByName(columnName);
return row().intValue(col.schemaIndex());
}
/** {@inheritDoc} */
- @Override public long longValue(String colName) {
- Column col = columnByName(colName);
+ @Override public int intValue(int columnIndex) {
+ schema().validateColumnIndex(columnIndex);
+
+ return row().intValue(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public long longValue(String columnName) {
+ Column col = columnByName(columnName);
return row().longValue(col.schemaIndex());
}
/** {@inheritDoc} */
- @Override public float floatValue(String colName) {
- Column col = columnByName(colName);
+ @Override public long longValue(int columnIndex) {
+ schema().validateColumnIndex(columnIndex);
+
+ return row().longValue(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public float floatValue(String columnName) {
+ Column col = columnByName(columnName);
return row().floatValue(col.schemaIndex());
}
/** {@inheritDoc} */
- @Override public double doubleValue(String colName) {
- Column col = columnByName(colName);
+ @Override public float floatValue(int columnIndex) {
+ schema().validateColumnIndex(columnIndex);
+
+ return row().floatValue(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public double doubleValue(String columnName) {
+ Column col = columnByName(columnName);
return row().doubleValue(col.schemaIndex());
}
/** {@inheritDoc} */
- @Override public String stringValue(String colName) {
- Column col = columnByName(colName);
+ @Override public double doubleValue(int columnIndex) {
+ schema().validateColumnIndex(columnIndex);
+
+ return row().doubleValue(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String stringValue(String columnName) {
+ Column col = columnByName(columnName);
return row().stringValue(col.schemaIndex());
}
/** {@inheritDoc} */
- @Override public UUID uuidValue(String colName) {
- Column col = columnByName(colName);
+ @Override public String stringValue(int columnIndex) {
+ schema().validateColumnIndex(columnIndex);
+
+ return row().stringValue(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public UUID uuidValue(String columnName) {
+ Column col = columnByName(columnName);
return row().uuidValue(col.schemaIndex());
}
/** {@inheritDoc} */
- @Override public BitSet bitmaskValue(String colName) {
- Column col = columnByName(colName);
+ @Override public UUID uuidValue(int columnIndex) {
+ schema().validateColumnIndex(columnIndex);
+
+ return row().uuidValue(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public BitSet bitmaskValue(String columnName) {
+ Column col = columnByName(columnName);
return row().bitmaskValue(col.schemaIndex());
}
+
+ /** {@inheritDoc} */
+ @Override public BitSet bitmaskValue(int columnIndex) {
+ schema().validateColumnIndex(columnIndex);
+
+ return row().bitmaskValue(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @NotNull @Override public Iterator<Object> iterator() {
+ return new Iterator<>() {
+ /** Current column index. */
+ private int cur;
+
+ /** {@inheritDoc} */
+ @Override public boolean hasNext() {
+ return cur < schema().length();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object next() {
+ return hasNext() ? value(cur++) : null;
+ }
+ };
+ }
}
diff --git a/modules/table/src/main/java/org/apache/ignite/internal/table/TupleBuilderImpl.java b/modules/table/src/main/java/org/apache/ignite/internal/table/TupleBuilderImpl.java
index 5f3fa08..6f5554d 100644
--- a/modules/table/src/main/java/org/apache/ignite/internal/table/TupleBuilderImpl.java
+++ b/modules/table/src/main/java/org/apache/ignite/internal/table/TupleBuilderImpl.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.table;
import java.util.BitSet;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import java.util.Objects;
@@ -29,6 +30,7 @@ import org.apache.ignite.internal.schema.SchemaAware;
import org.apache.ignite.internal.schema.SchemaDescriptor;
import org.apache.ignite.table.Tuple;
import org.apache.ignite.table.TupleBuilder;
+import org.jetbrains.annotations.NotNull;
/**
* Buildable tuple.
@@ -53,15 +55,10 @@ public class TupleBuilderImpl implements TupleBuilder, Tuple, SchemaAware {
}
/** {@inheritDoc} */
- @Override public TupleBuilder set(String colName, Object val) {
- Column col = schema().column(colName);
+ @Override public TupleBuilder set(String columnName, Object val) {
+ getColumnOrThrow(columnName).validate(val);
- if (col == null)
- throw new ColumnNotFoundException("Column not found [col=" + colName + "schema=" + schemaDesc + ']');
-
- col.validate(val);
-
- map.put(colName, val);
+ map.put(columnName, val);
return this;
}
@@ -89,65 +86,141 @@ public class TupleBuilderImpl implements TupleBuilder, Tuple, SchemaAware {
}
/** {@inheritDoc} */
- @Override public <T> T valueOrDefault(String colName, T def) {
- return (T)map.getOrDefault(colName, def);
+ @Override public String columnName(int columnIndex) {
+ return schemaDesc.column(columnIndex).name();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Integer columnIndex(String columnName) {
+ var col = schemaDesc.column(columnName);
+
+ return col == null ? null : col.schemaIndex();
+ }
+
+ /** {@inheritDoc} */
+ @Override public int columnCount() {
+ return schemaDesc.length();
+ }
+
+ /** {@inheritDoc} */
+ @Override public <T> T valueOrDefault(String columnName, T def) {
+ return (T)map.getOrDefault(columnName, def);
}
/** {@inheritDoc} */
- @Override public <T> T value(String colName) {
- return (T)map.get(colName);
+ @Override public <T> T value(String columnName) {
+ getColumnOrThrow(columnName);
+
+ return (T)map.get(columnName);
}
/** {@inheritDoc} */
- @Override public BinaryObject binaryObjectField(String colName) {
- byte[] data = value(colName);
+ @Override public <T> T value(int columnIndex) {
+ Column col = schemaDesc.column(columnIndex);
+
+ return (T)map.get(col.name());
+ }
+
+ /** {@inheritDoc} */
+ @Override public BinaryObject binaryObjectValue(String columnName) {
+ byte[] data = value(columnName);
return BinaryObjects.wrap(data);
}
/** {@inheritDoc} */
- @Override public byte byteValue(String colName) {
- return value(colName);
+ @Override public BinaryObject binaryObjectValue(int columnIndex) {
+ return value(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public byte byteValue(String columnName) {
+ return value(columnName);
+ }
+
+ /** {@inheritDoc} */
+ @Override public byte byteValue(int columnIndex) {
+ return value(columnIndex);
}
/** {@inheritDoc} */
- @Override public short shortValue(String colName) {
- return value(colName);
+ @Override public short shortValue(String columnName) {
+ return value(columnName);
}
/** {@inheritDoc} */
- @Override public int intValue(String colName) {
- return value(colName);
+ @Override public short shortValue(int columnIndex) {
+ return value(columnIndex);
}
/** {@inheritDoc} */
- @Override public long longValue(String colName) {
- return value(colName);
+ @Override public int intValue(String columnName) {
+ return value(columnName);
}
/** {@inheritDoc} */
- @Override public float floatValue(String colName) {
- return value(colName);
+ @Override public int intValue(int columnIndex) {
+ return value(columnIndex);
}
/** {@inheritDoc} */
- @Override public double doubleValue(String colName) {
- return value(colName);
+ @Override public long longValue(String columnName) {
+ return value(columnName);
}
/** {@inheritDoc} */
- @Override public String stringValue(String colName) {
- return value(colName);
+ @Override public long longValue(int columnIndex) {
+ return value(columnIndex);
}
/** {@inheritDoc} */
- @Override public UUID uuidValue(String colName) {
- return value(colName);
+ @Override public float floatValue(String columnName) {
+ return value(columnName);
}
/** {@inheritDoc} */
- @Override public BitSet bitmaskValue(String colName) {
- return value(colName);
+ @Override public float floatValue(int columnIndex) {
+ return value(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public double doubleValue(String columnName) {
+ return value(columnName);
+ }
+
+ /** {@inheritDoc} */
+ @Override public double doubleValue(int columnIndex) {
+ return value(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String stringValue(String columnName) {
+ return value(columnName);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String stringValue(int columnIndex) {
+ return value(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public UUID uuidValue(String columnName) {
+ return value(columnName);
+ }
+
+ /** {@inheritDoc} */
+ @Override public UUID uuidValue(int columnIndex) {
+ return value(columnIndex);
+ }
+
+ /** {@inheritDoc} */
+ @Override public BitSet bitmaskValue(String columnName) {
+ return value(columnName);
+ }
+
+ /** {@inheritDoc} */
+ @Override public BitSet bitmaskValue(int columnIndex) {
+ return value(columnIndex);
}
/** {@inheritDoc} */
@@ -155,10 +228,44 @@ public class TupleBuilderImpl implements TupleBuilder, Tuple, SchemaAware {
return schemaDesc;
}
+ /** {@inheritDoc} */
+ @NotNull @Override public Iterator<Object> iterator() {
+ return new Iterator<>() {
+ /** Current column index. */
+ private int cur;
+
+ /** {@inheritDoc} */
+ @Override public boolean hasNext() {
+ return cur < schemaDesc.length();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object next() {
+ return hasNext() ? value(cur++) : null;
+ }
+ };
+ }
+
/**
* @param schemaDesc New current schema descriptor.
*/
protected void schema(SchemaDescriptor schemaDesc) {
this.schemaDesc = schemaDesc;
}
+
+ /**
+ * Gets column by name or throws an exception when not found.
+ *
+ * @param columnName Column name.
+ * @return Column.
+ * @throws ColumnNotFoundException when not found.
+ */
+ @NotNull private Column getColumnOrThrow(String columnName) {
+ Column col = schema().column(columnName);
+
+ if (col == null)
+ throw new ColumnNotFoundException("Column not found [col=" + columnName + "schema=" + schemaDesc + ']');
+
+ return col;
+ }
}
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/Example.java b/modules/table/src/test/java/org/apache/ignite/internal/table/Example.java
index 38dabb4..2f0ad09 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/Example.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/Example.java
@@ -258,7 +258,7 @@ public class Example {
KeyValueView<OrderKey, OrderValue> orderKvView = t.kvView(Mappers.ofKeyClass(OrderKey.class),
Mappers.ofValueClassBuilder(OrderValue.class)
.map("billingDetails", (row) -> {
- BinaryObject bObj = row.binaryObjectField("conditionalDetails");
+ BinaryObject bObj = row.binaryObjectValue("conditionalDetails");
int type = row.intValue("type");
return type == 0 ?
@@ -276,7 +276,7 @@ public class Example {
// Work with the binary object as in Ignite 2.x
// Additionally, we may have a shortcut similar to primitive methods.
- binObj = res.binaryObjectField("billingDetails");
+ binObj = res.binaryObjectValue("billingDetails");
// Same with RecordAPI.
class OrderRecord {
@@ -325,7 +325,7 @@ public class Example {
// Work with the binary object as in Ignite 2.x
// Additionally, we may have a shortcut similar to primitive methods.
- binObj = res.binaryObjectField("upgradedObject");
+ binObj = res.binaryObjectValue("upgradedObject");
// Plain byte[] and BinaryObject fields in a class are straightforward.
class Record {
@@ -380,7 +380,7 @@ public class Example {
RecordView<TruncatedRecord> truncatedView2 = t.recordView(
Mappers.ofRecordClassBuilder(TruncatedRecord.class)
.map("upgradedObject", (row) -> {
- BinaryObject bObj = row.binaryObjectField("upgradedObject");
+ BinaryObject bObj = row.binaryObjectValue("upgradedObject");
int dept = row.intValue("department");
return dept == 0 ?
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/TupleBuilderImplTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/TupleBuilderImplTest.java
new file mode 100644
index 0000000..a387f2c
--- /dev/null
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/TupleBuilderImplTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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 java.util.UUID;
+
+import org.apache.ignite.internal.schema.Column;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.schema.SchemaDescriptor;
+import org.apache.ignite.lang.IgniteException;
+import org.apache.ignite.table.Tuple;
+import org.junit.jupiter.api.Test;
+
+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;
+
+/**
+ * Tests server tuple builder implementation.
+ *
+ * Should be in sync with org.apache.ignite.client.ClientTupleBuilderTest.
+ */
+public class TupleBuilderImplTest {
+ private static final SchemaDescriptor SCHEMA = new SchemaDescriptor(UUID.randomUUID(), 1,
+ new Column[] {new Column("id", NativeTypes.INT64, false)},
+ new Column[] {new Column("name", NativeTypes.STRING, true)
+ });
+
+ @Test
+ public void testValueReturnsValueByName() {
+ assertEquals(3L, (Long) getTuple().value("id"));
+ assertEquals("Shirt", getTuple().value("name"));
+ }
+
+ @Test
+ public void testValueReturnsValueByIndex() {
+ assertEquals(3L, (Long) getTuple().value(0));
+ assertEquals("Shirt", getTuple().value(1));
+ }
+
+ @Test
+ public void testValueOrDefaultReturnsValueByName() {
+ assertEquals(3L, getTuple().valueOrDefault("id", -1L));
+ assertEquals("Shirt", getTuple().valueOrDefault("name", "y"));
+ }
+
+ @Test
+ public void testValueOrDefaultReturnsDefaultWhenColumnIsNotPresent() {
+ assertEquals("foo", getBuilder().valueOrDefault("x", "foo"));
+ }
+
+ @Test
+ public void testValueOrDefaultReturnsDefaultWhenColumnIsPresentButNotSet() {
+ assertEquals("foo", getBuilder().valueOrDefault("name", "foo"));
+ }
+
+ @Test
+ public void testValueOrDefaultReturnsNullWhenColumnIsSetToNull() {
+ var tuple = getBuilder().set("name", null).build();
+
+ assertNull(tuple.valueOrDefault("name", "foo"));
+ }
+
+ @Test
+ public void testSetThrowsWhenColumnIsNotPresent() {
+ var ex = assertThrows(IgniteException.class, () -> getBuilder().set("x", "y"));
+ assertTrue(ex.getMessage().startsWith("Column not found"), ex.getMessage());
+ }
+
+ @Test
+ public void testValueThrowsWhenColumnIsNotPresent() {
+ var ex = assertThrows(IgniteException.class, () -> getBuilder().value("x"));
+ assertTrue(ex.getMessage().startsWith("Column not found"), ex.getMessage());
+
+ var ex2 = assertThrows(IllegalArgumentException.class, () -> getBuilder().value(100));
+ assertTrue(ex2.getMessage().startsWith("Column index can't be greater than 1"), ex2.getMessage());
+ }
+
+ @Test
+ public void testColumnCountReturnsSchemaSize() {
+ assertEquals(SCHEMA.length(), getTuple().columnCount());
+ }
+
+ @Test
+ public void testColumnNameReturnsNameByIndex() {
+ assertEquals("id", getTuple().columnName(0));
+ assertEquals("name", getTuple().columnName(1));
+ }
+
+ @Test
+ public void testColumnNameThrowsOnInvalidIndex() {
+ var ex = assertThrows(IllegalArgumentException.class, () -> getTuple().columnName(-1));
+ assertEquals("Column index can't be negative", ex.getMessage());
+ }
+
+ @Test
+ public void testColumnIndexReturnsIndexByName() {
+ assertEquals(0, getTuple().columnIndex("id"));
+ assertEquals(1, getTuple().columnIndex("name"));
+ }
+
+ @Test
+ public void testColumnIndexReturnsNullForMissingColumns() {
+ assertNull(getTuple().columnIndex("foo"));
+ }
+
+ private static TupleBuilderImpl getBuilder() {
+ return new TupleBuilderImpl(SCHEMA);
+ }
+
+ private static Tuple getTuple() {
+ return new TupleBuilderImpl(SCHEMA)
+ .set("id", 3L)
+ .set("name", "Shirt")
+ .build();
+ }
+}
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/impl/TestTupleBuilder.java b/modules/table/src/test/java/org/apache/ignite/internal/table/impl/TestTupleBuilder.java
index f8520dc..440d7b7 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/impl/TestTupleBuilder.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/impl/TestTupleBuilder.java
@@ -19,12 +19,14 @@ package org.apache.ignite.internal.table.impl;
import java.util.BitSet;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.binary.BinaryObjects;
import org.apache.ignite.table.Tuple;
import org.apache.ignite.table.TupleBuilder;
+import org.jetbrains.annotations.NotNull;
/**
* Dummy table storage implementation.
@@ -34,8 +36,8 @@ public class TestTupleBuilder implements TupleBuilder, Tuple {
private final Map<String, Object> map = new HashMap<>();
/** {@inheritDoc} */
- @Override public TestTupleBuilder set(String colName, Object value) {
- map.put(colName, value);
+ @Override public TestTupleBuilder set(String columnName, Object value) {
+ map.put(columnName, value);
return this;
}
@@ -46,64 +48,139 @@ public class TestTupleBuilder implements TupleBuilder, Tuple {
}
/** {@inheritDoc} */
- @Override public <T> T valueOrDefault(String colName, T def) {
- return (T)map.getOrDefault(colName, def);
+ @Override public <T> T valueOrDefault(String columnName, T def) {
+ return (T)map.getOrDefault(columnName, def);
}
/** {@inheritDoc} */
- @Override public <T> T value(String colName) {
- return (T)map.get(colName);
+ @Override public <T> T value(String columnName) {
+ return (T)map.get(columnName);
}
/** {@inheritDoc} */
- @Override public BinaryObject binaryObjectField(String colName) {
- byte[] data = value(colName);
+ @Override public <T> T value(int columnIndex) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override public int columnCount() {
+ return map.size();
+ }
+
+ /** {@inheritDoc} */
+ @Override public String columnName(int columnIndex) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Integer columnIndex(String columnName) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override public BinaryObject binaryObjectValue(String columnName) {
+ byte[] data = value(columnName);
return BinaryObjects.wrap(data);
}
/** {@inheritDoc} */
- @Override public byte byteValue(String colName) {
- return value(colName);
+ @Override public BinaryObject binaryObjectValue(int columnIndex) {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public byte byteValue(String columnName) {
+ return value(columnName);
+ }
+
+ /** {@inheritDoc} */
+ @Override public byte byteValue(int columnIndex) {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override public short shortValue(String columnName) {
+ return value(columnName);
+ }
+
+ /** {@inheritDoc} */
+ @Override public short shortValue(int columnIndex) {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override public int intValue(String columnName) {
+ return value(columnName);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int intValue(int columnIndex) {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override public long longValue(String columnName) {
+ return value(columnName);
+ }
+
+ /** {@inheritDoc} */
+ @Override public long longValue(int columnIndex) {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override public float floatValue(String columnName) {
+ return value(columnName);
+ }
+
+ /** {@inheritDoc} */
+ @Override public float floatValue(int columnIndex) {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override public double doubleValue(String columnName) {
+ return value(columnName);
}
/** {@inheritDoc} */
- @Override public short shortValue(String colName) {
- return value(colName);
+ @Override public double doubleValue(int columnIndex) {
+ return 0;
}
/** {@inheritDoc} */
- @Override public int intValue(String colName) {
- return value(colName);
+ @Override public String stringValue(String columnName) {
+ return value(columnName);
}
/** {@inheritDoc} */
- @Override public long longValue(String colName) {
- return value(colName);
+ @Override public String stringValue(int columnIndex) {
+ return null;
}
/** {@inheritDoc} */
- @Override public float floatValue(String colName) {
- return value(colName);
+ @Override public UUID uuidValue(String columnName) {
+ return value(columnName);
}
/** {@inheritDoc} */
- @Override public double doubleValue(String colName) {
- return value(colName);
+ @Override public UUID uuidValue(int columnIndex) {
+ return null;
}
/** {@inheritDoc} */
- @Override public String stringValue(String colName) {
- return value(colName);
+ @Override public BitSet bitmaskValue(String columnName) {
+ return value(columnName);
}
/** {@inheritDoc} */
- @Override public UUID uuidValue(String colName) {
- return value(colName);
+ @Override public BitSet bitmaskValue(int columnIndex) {
+ return null;
}
/** {@inheritDoc} */
- @Override public BitSet bitmaskValue(String colName) {
- return value(colName);
+ @NotNull @Override public Iterator<Object> iterator() {
+ throw new UnsupportedOperationException();
}
}