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 84592c229f IGNITE-15889 Add 'contains' method to Record API (#3118) 84592c229f is described below commit 84592c229f38302a21b49a2a50bc3322c47f1068 Author: Mikhail Efremov <jakuten...@gmail.com> AuthorDate: Thu Feb 29 18:49:36 2024 +0400 IGNITE-15889 Add 'contains' method to Record API (#3118) --- .../java/org/apache/ignite/table/RecordView.java | 21 +++++++++++++++++ .../client/table/ClientRecordBinaryView.java | 18 +++++++++++++++ .../internal/client/table/ClientRecordView.java | 18 +++++++++++++++ .../apache/ignite/client/ClientRecordViewTest.java | 12 ++++++++++ .../internal/table/RecordBinaryViewImpl.java | 18 +++++++++++++++ .../ignite/internal/table/RecordViewImpl.java | 18 +++++++++++++++ .../table/RecordBinaryViewOperationsTest.java | 26 +++++++++++++++++++++- .../internal/table/RecordViewOperationsTest.java | 19 ++++++++++++++-- 8 files changed, 147 insertions(+), 3 deletions(-) diff --git a/modules/api/src/main/java/org/apache/ignite/table/RecordView.java b/modules/api/src/main/java/org/apache/ignite/table/RecordView.java index 2ab3a35cda..8ab6e3eabe 100644 --- a/modules/api/src/main/java/org/apache/ignite/table/RecordView.java +++ b/modules/api/src/main/java/org/apache/ignite/table/RecordView.java @@ -20,6 +20,7 @@ package org.apache.ignite.table; import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; +import org.apache.ignite.lang.MarshallerException; import org.apache.ignite.table.criteria.CriteriaQuerySource; import org.apache.ignite.tx.Transaction; import org.jetbrains.annotations.Nullable; @@ -71,6 +72,26 @@ public interface RecordView<R> extends DataStreamerTarget<R>, CriteriaQuerySourc */ CompletableFuture<List<R>> getAllAsync(@Nullable Transaction tx, Collection<R> keyRecs); + /** + * Determines whether a table contains an entry for the specified key. + * + * @param tx Transaction or {@code null} to auto-commit. + * @param keyRec A record with key columns set. The key cannot be {@code null}. + * @return {@code True} if a value exists for the specified key, {@code false} otherwise. + * @throws MarshallerException if the key doesn't match the schema. + */ + boolean contains(@Nullable Transaction tx, R keyRec); + + /** + * Determines whether a table contains an entry for the specified key. + * + * @param tx Transaction or {@code null} to auto-commit. + * @param keyRec A record with key columns set. The key cannot be {@code null}. + * @return Future that represents the pending completion of the operation. + * @throws MarshallerException if the key doesn't match the schema. + */ + CompletableFuture<Boolean> containsAsync(@Nullable Transaction tx, R keyRec); + /** * Inserts a record into a table, if it does not exist, or replaces an existing one. * diff --git a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientRecordBinaryView.java b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientRecordBinaryView.java index c99a6fca79..caada4fee7 100644 --- a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientRecordBinaryView.java +++ b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientRecordBinaryView.java @@ -96,6 +96,24 @@ public class ClientRecordBinaryView extends AbstractClientView<Tuple> implements ); } + /** {@inheritDoc} */ + @Override + public boolean contains(@Nullable Transaction tx, Tuple key) { + return sync(containsAsync(tx, key)); + } + + /** {@inheritDoc} */ + @Override + public CompletableFuture<Boolean> containsAsync(@Nullable Transaction tx, Tuple key) { + Objects.requireNonNull(key); + + return tbl.doSchemaOutOpAsync( + ClientOp.TUPLE_CONTAINS_KEY, + (s, w) -> ser.writeTuple(tx, key, s, w, true), + r -> r.in().unpackBoolean(), + ClientTupleSerializer.getPartitionAwarenessProvider(tx, key)); + } + /** {@inheritDoc} */ @Override public void upsert(@Nullable Transaction tx, Tuple rec) { diff --git a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientRecordView.java b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientRecordView.java index 2746a906d9..08d733e326 100644 --- a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientRecordView.java +++ b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientRecordView.java @@ -105,6 +105,24 @@ public class ClientRecordView<R> extends AbstractClientView<R> implements Record ); } + /** {@inheritDoc} */ + @Override + public boolean contains(@Nullable Transaction tx, R key) { + return sync(containsAsync(tx, key)); + } + + /** {@inheritDoc} */ + @Override + public CompletableFuture<Boolean> containsAsync(@Nullable Transaction tx, R key) { + Objects.requireNonNull(key); + + return tbl.doSchemaOutOpAsync( + ClientOp.TUPLE_CONTAINS_KEY, + (s, w) -> ser.writeRec(tx, key, s, w, TuplePart.KEY), + r -> r.in().unpackBoolean(), + ClientTupleSerializer.getPartitionAwarenessProvider(tx, ser.mapper(), key)); + } + /** {@inheritDoc} */ @Override public void upsert(@Nullable Transaction tx, R rec) { diff --git a/modules/client/src/test/java/org/apache/ignite/client/ClientRecordViewTest.java b/modules/client/src/test/java/org/apache/ignite/client/ClientRecordViewTest.java index 2a906efd40..0e78078e71 100644 --- a/modules/client/src/test/java/org/apache/ignite/client/ClientRecordViewTest.java +++ b/modules/client/src/test/java/org/apache/ignite/client/ClientRecordViewTest.java @@ -278,6 +278,18 @@ public class ClientRecordViewTest extends AbstractClientTableTest { assertEquals("c", res[2]); } + @Test + public void testContains() { + RecordView<PersonPojo> recordView = defaultTable().recordView(PersonPojo.class); + PersonPojo pojo = new PersonPojo(DEFAULT_ID, DEFAULT_NAME); + + recordView.insert(null, pojo); + + assertTrue(recordView.contains(null, pojo)); + assertTrue(recordView.contains(null, new PersonPojo(DEFAULT_ID, ""))); + assertFalse(recordView.contains(null, new PersonPojo(DEFAULT_ID - 1, DEFAULT_NAME))); + } + @Test public void testUpsertAll() { RecordView<PersonPojo> pojoView = defaultTable().recordView(Mapper.of(PersonPojo.class)); diff --git a/modules/table/src/main/java/org/apache/ignite/internal/table/RecordBinaryViewImpl.java b/modules/table/src/main/java/org/apache/ignite/internal/table/RecordBinaryViewImpl.java index 5efd34ec76..d62cce9023 100644 --- a/modules/table/src/main/java/org/apache/ignite/internal/table/RecordBinaryViewImpl.java +++ b/modules/table/src/main/java/org/apache/ignite/internal/table/RecordBinaryViewImpl.java @@ -114,6 +114,24 @@ public class RecordBinaryViewImpl extends AbstractTableView<Tuple> implements Re }); } + /** {@inheritDoc} */ + @Override + public boolean contains(@Nullable Transaction tx, Tuple keyRec) { + return sync(containsAsync(tx, keyRec)); + } + + /** {@inheritDoc} */ + @Override + public CompletableFuture<Boolean> containsAsync(@Nullable Transaction tx, Tuple keyRec) { + Objects.requireNonNull(keyRec); + + return withSchemaSync(tx, (schemaVersion) -> { + Row keyRow = marshal(keyRec, schemaVersion, true); // Convert to portable format to pass TX/storage layer. + + return tbl.get(keyRow, (InternalTransaction) tx).thenApply(Objects::nonNull); + }); + } + /** {@inheritDoc} */ @Override public void upsert(@Nullable Transaction tx, Tuple rec) { 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 c533cfb6a7..cf7ec8df18 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 @@ -124,6 +124,24 @@ public class RecordViewImpl<R> extends AbstractTableView<R> implements RecordVie }); } + /** {@inheritDoc} */ + @Override + public boolean contains(@Nullable Transaction tx, R keyRec) { + return sync(containsAsync(tx, keyRec)); + } + + /** {@inheritDoc} */ + @Override + public CompletableFuture<Boolean> containsAsync(@Nullable Transaction tx, R keyRec) { + Objects.requireNonNull(keyRec); + + return withSchemaSync(tx, (schemaVersion) -> { + BinaryRowEx keyRow = marshalKey(keyRec, schemaVersion); + + return tbl.get(keyRow, (InternalTransaction) tx).thenApply(Objects::nonNull); + }); + } + /** {@inheritDoc} */ @Override public void upsert(@Nullable Transaction tx, R rec) { diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/RecordBinaryViewOperationsTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/RecordBinaryViewOperationsTest.java index 68f8f36742..cb8fe29c2c 100644 --- a/modules/table/src/test/java/org/apache/ignite/internal/table/RecordBinaryViewOperationsTest.java +++ b/modules/table/src/test/java/org/apache/ignite/internal/table/RecordBinaryViewOperationsTest.java @@ -92,7 +92,7 @@ public class RecordBinaryViewOperationsTest extends TableKvOperationsTestBase { return new SchemaDescriptor( SCHEMA_VERSION, new Column[]{new Column("id".toUpperCase(), NativeTypes.INT64, false)}, - new Column[]{new Column("val".toUpperCase(), NativeTypes.INT64, false)} + new Column[]{new Column("val".toUpperCase(), NativeTypes.INT64, true)} ); } @@ -343,6 +343,30 @@ public class RecordBinaryViewOperationsTest extends TableKvOperationsTestBase { assertThat(res, contains(rec1, null, rec3)); } + @Test + public void testContains() { + SchemaDescriptor schema = schemaDescriptor(); + RecordView<Tuple> tbl = createTable(schema).recordView(); + + final long keyId = 1L; + Tuple rec = Tuple.create() + .set("id", keyId) + .set("val", 11L); + Tuple keyRec = Tuple.create() + .set("id", keyId); + + tbl.insert(null, rec); + assertTrue(tbl.contains(null, keyRec)); + assertFalse(tbl.contains(null, Tuple.create().set("id", -1L))); + + tbl.delete(null, keyRec); + assertFalse(tbl.contains(null, keyRec)); + + Tuple nullValRec = Tuple.create().set("id", 1L).set("val", null); + tbl.insert(null, nullValRec); + assertTrue(tbl.contains(null, keyRec)); + } + @Test public void upsertAllAfterInsertAll() { SchemaDescriptor schema = schemaDescriptor(); 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 index 19299fac82..64a80bb584 100644 --- 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 @@ -33,7 +33,6 @@ import static org.apache.ignite.internal.type.NativeTypes.datetime; import static org.apache.ignite.internal.type.NativeTypes.time; import static org.apache.ignite.internal.type.NativeTypes.timestamp; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -73,6 +72,7 @@ import org.apache.ignite.internal.type.NativeTypes; import org.apache.ignite.sql.IgniteSql; import org.apache.ignite.table.RecordView; import org.apache.ignite.table.mapper.Mapper; +import org.hamcrest.Matchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -346,7 +346,22 @@ public class RecordViewOperationsTest extends TableKvOperationsTestBase { Collection<TestObjectWithAllTypes> res = tbl.getAll(null, List.of(key1, key2, key3)); - assertThat(res, contains(val1, null, val3)); + assertThat(res, Matchers.contains(val1, null, val3)); + } + + @Test + public void contains() { + final TestObjectWithAllTypes key = key(rnd); + final TestObjectWithAllTypes wrongKey = key(rnd); + final TestObjectWithAllTypes val = randomObject(rnd, key); + final RecordView<TestObjectWithAllTypes> tbl = recordView(); + + tbl.insert(null, val); + + assertTrue(tbl.contains(null, key)); + assertTrue(tbl.contains(null, val)); + assertFalse(tbl.contains(null, wrongKey)); + assertFalse(tbl.contains(null, randomObject(rnd, wrongKey))); } @Test