blob: 0c9243feaef6a6cdcebdf0a467b4f648ea8216e0 [file] [log] [blame]
/*
* 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 static java.time.temporal.ChronoField.NANO_OF_SECOND;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasToString;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
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 java.math.BigDecimal;
import java.math.BigInteger;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.List;
import org.apache.ignite.lang.IgniteException;
import org.apache.ignite.table.KeyValueView;
import org.apache.ignite.table.RecordView;
import org.apache.ignite.table.Table;
import org.apache.ignite.table.Tuple;
import org.apache.ignite.table.mapper.Mapper;
import org.junit.jupiter.api.Test;
/**
* Record view tests.
*/
public class ClientRecordViewTest extends AbstractClientTableTest {
@Test
public void testBinaryPutPojoGet() {
Table table = defaultTable();
RecordView<PersonPojo> pojoView = table.recordView(Mapper.of(PersonPojo.class));
table.recordView().upsert(null, tuple());
var key = new PersonPojo();
key.id = DEFAULT_ID;
PersonPojo val = pojoView.get(null, key);
PersonPojo missingVal = pojoView.get(null, new PersonPojo());
assertEquals(DEFAULT_NAME, val.name);
assertEquals(DEFAULT_ID, val.id);
assertNull(missingVal);
}
@Test
public void testBinaryPutPrimitiveGet() {
Table table = defaultTable();
RecordView<Long> primitiveView = table.recordView(Mapper.of(Long.class));
table.recordView().upsert(null, tuple());
Long val = primitiveView.get(null, DEFAULT_ID);
Long missingVal = primitiveView.get(null, -1L);
assertEquals(DEFAULT_ID, val);
assertNull(missingVal);
}
@Test
public void testPrimitivePutBinaryGet() {
Table table = oneColumnTable();
RecordView<String> primitiveView = table.recordView(Mapper.of(String.class));
primitiveView.upsert(null, "abc");
Tuple tuple = table.recordView().get(null, oneColumnTableKey("abc"));
assertEquals("abc", tuple.stringValue(0));
}
@Test
public void testMissingValueColumnsThrowException() {
Table table = fullTable();
KeyValueView<Tuple, Tuple> kvView = table.keyValueView();
RecordView<IncompletePojo> pojoView = table.recordView(IncompletePojo.class);
kvView.put(null, allColumnsTableKey(1), allColumnsTableVal("x", true));
var key = new IncompletePojo();
key.id = "1";
key.gid = 1;
// This POJO does not have fields for all table columns, which is not allowed (to avoid unexpected data loss).
IgniteException ex = assertThrows(IgniteException.class, () -> pojoView.get(null, key));
assertEquals("Failed to deserialize server response: No mapped object field found for column 'ZBOOLEAN'", ex.getMessage());
assertThat(Arrays.asList(ex.getStackTrace()), anyOf(hasToString(containsString("ClientRecordView"))));
}
@Test
public void testAllColumnsBinaryPutPojoGet() {
Table table = fullTable();
RecordView<AllColumnsPojo> pojoView = table.recordView(Mapper.of(AllColumnsPojo.class));
table.recordView().upsert(null, allColumnsTableVal("foo", false));
var key = new AllColumnsPojo();
key.gid = DEFAULT_ID;
key.id = String.valueOf(DEFAULT_ID);
AllColumnsPojo res = pojoView.get(null, key);
assertEquals(11, res.zbyte);
assertEquals(12, res.zshort);
assertEquals(13, res.zint);
assertEquals(14, res.zlong);
assertEquals(1.5f, res.zfloat);
assertEquals(1.6, res.zdouble);
assertEquals(localDate, res.zdate);
assertEquals(localTime.truncatedTo(ChronoUnit.SECONDS), res.ztime);
assertEquals(instant.with(NANO_OF_SECOND, truncateNanosToMicros(instant.getNano())), res.ztimestamp);
assertEquals("foo", res.zstring);
assertArrayEquals(new byte[]{1, 2}, res.zbytes);
assertEquals(BitSet.valueOf(new byte[]{32}), res.zbitmask);
assertEquals(21, res.zdecimal.longValue());
assertEquals(22, res.znumber.longValue());
assertEquals(uuid, res.zuuid);
}
private int truncateNanosToMicros(int nanos) {
return nanos / 1000 * 1000;
}
@Test
public void testAllColumnsPojoPutBinaryGet() {
Table table = fullTable();
RecordView<AllColumnsPojo> pojoView = table.recordView(Mapper.of(AllColumnsPojo.class));
var val = new AllColumnsPojo();
val.gid = 111;
val.id = "112";
val.zbyte = 113;
val.zshort = 114;
val.zint = 115;
val.zlong = 116;
val.zfloat = 1.17f;
val.zdouble = 1.18;
val.zdate = localDate;
val.ztime = localTime;
val.ztimestamp = instant;
val.zstring = "119";
val.zbytes = new byte[]{120};
val.zbitmask = BitSet.valueOf(new byte[]{121});
val.zdecimal = BigDecimal.valueOf(122);
val.znumber = BigInteger.valueOf(123);
val.zuuid = uuid;
pojoView.upsert(null, val);
Tuple res = table.recordView().get(null, Tuple.create().set("id", "112").set("gid", 111L));
assertNotNull(res);
assertEquals(111, res.longValue("gid"));
assertEquals("112", res.stringValue("id"));
assertEquals(113, res.byteValue("zbyte"));
assertEquals(114, res.shortValue("zshort"));
assertEquals(115, res.intValue("zint"));
assertEquals(116, res.longValue("zlong"));
assertEquals(1.17f, res.floatValue("zfloat"));
assertEquals(1.18, res.doubleValue("zdouble"));
assertEquals(localDate, res.dateValue("zdate"));
assertEquals(localTime.truncatedTo(ChronoUnit.SECONDS), res.timeValue("ztime"));
assertEquals(instant.with(NANO_OF_SECOND, truncateNanosToMicros(instant.getNano())), res.timestampValue("ztimestamp"));
assertEquals("119", res.stringValue("zstring"));
assertEquals(120, ((byte[]) res.value("zbytes"))[0]);
assertEquals(BitSet.valueOf(new byte[]{121}), res.bitmaskValue("zbitmask"));
assertEquals(122, ((BigDecimal) res.value("zdecimal")).longValue());
assertEquals(BigInteger.valueOf(123), res.value("znumber"));
assertEquals(uuid, res.uuidValue("zuuid"));
}
@Test
public void testMissingKeyColumnThrowsException() {
RecordView<NamePojo> recordView = defaultTable().recordView(NamePojo.class);
IgniteException e = assertThrows(IgniteException.class, () -> recordView.get(null, new NamePojo()));
assertThat(e.getMessage(), containsString("No mapped object field found for column 'ID'"));
assertThat(Arrays.asList(e.getStackTrace()), anyOf(hasToString(containsString("ClientRecordView"))));
}
@Test
public void testNullablePrimitiveFields() {
RecordView<AllColumnsPojoNullable> pojoView = fullTable().recordView(AllColumnsPojoNullable.class);
RecordView<Tuple> tupleView = fullTable().recordView();
var rec = new AllColumnsPojoNullable();
rec.id = "1";
rec.gid = 1L;
pojoView.upsert(null, rec);
AllColumnsPojoNullable res = pojoView.get(null, rec);
Tuple binRes = tupleView.get(null, Tuple.create().set("id", "1").set("gid", 1L));
assertNotNull(res);
assertNotNull(binRes);
assertNull(res.zboolean);
assertNull(res.zbyte);
assertNull(res.zshort);
assertNull(res.zint);
assertNull(res.zlong);
assertNull(res.zfloat);
assertNull(res.zdouble);
for (int i = 0; i < binRes.columnCount(); i++) {
if (binRes.columnName(i).endsWith("ID")) {
continue;
}
assertNull(binRes.value(i));
}
}
@Test
public void testGetAll() {
Table table = defaultTable();
RecordView<PersonPojo> pojoView = table.recordView(Mapper.of(PersonPojo.class));
table.recordView().upsert(null, tuple());
table.recordView().upsert(null, tuple(100L, "100"));
Collection<PersonPojo> keys = List.of(
new PersonPojo(DEFAULT_ID, "blabla"),
new PersonPojo(101L, "1234"),
new PersonPojo(100L, "qwerty"));
PersonPojo[] res = pojoView.getAll(null, keys).toArray(new PersonPojo[0]);
assertEquals(3, res.length);
assertNotNull(res[0]);
assertNull(res[1]);
assertNotNull(res[2]);
assertEquals(DEFAULT_ID, res[0].id);
assertEquals(DEFAULT_NAME, res[0].name);
assertEquals(100L, res[2].id);
assertEquals("100", res[2].name);
}
@Test
public void testGetAllPrimitive() {
Table table = oneColumnTable();
RecordView<String> primitiveView = table.recordView(Mapper.of(String.class));
primitiveView.upsertAll(null, List.of("a", "c"));
String[] res = primitiveView.getAll(null, List.of("a", "b", "c")).toArray(new String[0]);
assertEquals("a", res[0]);
assertNull(res[1]);
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));
Collection<PersonPojo> pojos = List.of(
new PersonPojo(DEFAULT_ID, DEFAULT_NAME),
new PersonPojo(100L, "100"),
new PersonPojo(101L, "101"));
pojoView.upsertAll(null, pojos);
assertEquals(DEFAULT_NAME, pojoView.get(null, new PersonPojo(DEFAULT_ID)).name);
assertEquals("100", pojoView.get(null, new PersonPojo(100L)).name);
assertEquals("101", pojoView.get(null, new PersonPojo(101L)).name);
}
@Test
public void testGetAndUpsert() {
RecordView<PersonPojo> pojoView = defaultTable().recordView(Mapper.of(PersonPojo.class));
pojoView.upsert(null, new PersonPojo(DEFAULT_ID, DEFAULT_NAME));
PersonPojo res1 = pojoView.getAndUpsert(null, new PersonPojo(DEFAULT_ID, "new_name"));
PersonPojo res2 = pojoView.getAndUpsert(null, new PersonPojo(100L, "name"));
assertEquals(DEFAULT_NAME, res1.name);
assertEquals("new_name", pojoView.get(null, new PersonPojo(DEFAULT_ID)).name);
assertNull(res2);
assertEquals("name", pojoView.get(null, new PersonPojo(100L)).name);
}
@Test
public void testInsert() {
RecordView<PersonPojo> pojoView = defaultTable().recordView(Mapper.of(PersonPojo.class));
pojoView.upsert(null, new PersonPojo(DEFAULT_ID, DEFAULT_NAME));
boolean res1 = pojoView.insert(null, new PersonPojo(DEFAULT_ID, "foobar"));
boolean res2 = pojoView.insert(null, new PersonPojo(100L, "100"));
assertFalse(res1);
assertTrue(res2);
assertEquals("100", pojoView.get(null, new PersonPojo(100L)).name);
}
@Test
public void testInsertAll() {
RecordView<PersonPojo> pojoView = defaultTable().recordView(Mapper.of(PersonPojo.class));
pojoView.upsert(null, new PersonPojo(DEFAULT_ID, DEFAULT_NAME));
Collection<PersonPojo> res1 = pojoView.insertAll(null, List.of(new PersonPojo(10L, "10"), new PersonPojo(20L)));
Collection<PersonPojo> res2 = pojoView.insertAll(null, List.of(new PersonPojo(DEFAULT_ID), new PersonPojo(10L)));
Collection<PersonPojo> res3 = pojoView.insertAll(
null,
List.of(new PersonPojo(DEFAULT_ID, "new_name"), new PersonPojo(30L))
);
assertEquals(0, res1.size());
assertEquals(2, res2.size());
assertEquals(1, res3.size());
assertEquals("10", pojoView.get(null, new PersonPojo(10L)).name);
assertNull(pojoView.get(null, new PersonPojo(20L)).name);
assertEquals("new_name", res3.iterator().next().name);
}
@Test
public void testReplace() {
RecordView<PersonPojo> pojoView = defaultTable().recordView(Mapper.of(PersonPojo.class));
pojoView.upsert(null, new PersonPojo(DEFAULT_ID, DEFAULT_NAME));
assertFalse(pojoView.replace(null, new PersonPojo(-1L)));
assertTrue(pojoView.replace(null, new PersonPojo(DEFAULT_ID, "new_name")));
assertNull(pojoView.get(null, new PersonPojo(-1L)));
assertEquals("new_name", pojoView.get(null, new PersonPojo(DEFAULT_ID)).name);
}
@Test
public void testReplaceExact() {
RecordView<PersonPojo> pojoView = defaultTable().recordView(Mapper.of(PersonPojo.class));
pojoView.upsert(null, new PersonPojo(DEFAULT_ID, DEFAULT_NAME));
assertFalse(pojoView.replace(null, new PersonPojo(DEFAULT_ID, "x"), new PersonPojo(DEFAULT_ID, "new_name")));
assertFalse(pojoView.replace(null, new PersonPojo(-1L, "x"), new PersonPojo(DEFAULT_ID, "new_name")));
assertTrue(pojoView.replace(null, new PersonPojo(DEFAULT_ID, DEFAULT_NAME), new PersonPojo(DEFAULT_ID, "new_name2")));
assertNull(pojoView.get(null, new PersonPojo(-1L)));
assertEquals("new_name2", pojoView.get(null, new PersonPojo(DEFAULT_ID)).name);
}
@Test
public void testGetAndReplace() {
RecordView<PersonPojo> pojoView = defaultTable().recordView(Mapper.of(PersonPojo.class));
pojoView.upsert(null, new PersonPojo(DEFAULT_ID, DEFAULT_NAME));
PersonPojo res1 = pojoView.getAndReplace(null, new PersonPojo(DEFAULT_ID, "new_name"));
PersonPojo res2 = pojoView.getAndReplace(null, new PersonPojo(100L, "name"));
assertEquals(DEFAULT_NAME, res1.name);
assertEquals("new_name", pojoView.get(null, new PersonPojo(DEFAULT_ID)).name);
assertNull(res2);
assertNull(pojoView.get(null, new PersonPojo(100L)));
}
@Test
public void testDelete() {
RecordView<PersonPojo> pojoView = defaultTable().recordView(Mapper.of(PersonPojo.class));
pojoView.upsert(null, new PersonPojo(DEFAULT_ID, DEFAULT_NAME));
boolean res1 = pojoView.delete(null, new PersonPojo(DEFAULT_ID));
boolean res2 = pojoView.delete(null, new PersonPojo(100L, "name"));
assertTrue(res1);
assertFalse(res2);
assertNull(pojoView.get(null, new PersonPojo(DEFAULT_ID)));
}
@Test
public void testDeleteExact() {
RecordView<PersonPojo> pojoView = defaultTable().recordView(Mapper.of(PersonPojo.class));
pojoView.upsert(null, new PersonPojo(DEFAULT_ID, DEFAULT_NAME));
pojoView.upsert(null, new PersonPojo(100L, "100"));
boolean res1 = pojoView.deleteExact(null, new PersonPojo(DEFAULT_ID));
boolean res2 = pojoView.deleteExact(null, new PersonPojo(100L));
boolean res3 = pojoView.deleteExact(null, new PersonPojo(100L, "100"));
assertFalse(res1);
assertFalse(res2);
assertTrue(res3);
assertNotNull(pojoView.get(null, new PersonPojo(DEFAULT_ID)));
assertNull(pojoView.get(null, new PersonPojo(100L)));
}
@Test
public void testGetAndDelete() {
RecordView<PersonPojo> pojoView = defaultTable().recordView(Mapper.of(PersonPojo.class));
pojoView.upsert(null, new PersonPojo(DEFAULT_ID, DEFAULT_NAME));
PersonPojo res1 = pojoView.getAndDelete(null, new PersonPojo(DEFAULT_ID));
PersonPojo res2 = pojoView.getAndDelete(null, new PersonPojo(100L));
assertEquals(DEFAULT_NAME, res1.name);
assertNull(pojoView.get(null, new PersonPojo(DEFAULT_ID)));
assertNull(res2);
}
@Test
public void testDeleteAll() {
RecordView<PersonPojo> pojoView = defaultTable().recordView(Mapper.of(PersonPojo.class));
pojoView.upsertAll(
null,
List.of(new PersonPojo(1L, "1"), new PersonPojo(2L, "2"), new PersonPojo(3L, "3"))
);
Collection<PersonPojo> res1 = pojoView.deleteAll(null, List.of(new PersonPojo(10L), new PersonPojo(20L)));
Collection<PersonPojo> res2 = pojoView.deleteAll(null, List.of(new PersonPojo(1L), new PersonPojo(3L)));
assertEquals(2, res1.size());
assertEquals(0, res2.size());
assertNull(pojoView.get(null, new PersonPojo(1L)));
assertEquals("2", pojoView.get(null, new PersonPojo(2L)).name);
assertNull(pojoView.get(null, new PersonPojo(3L)));
}
@Test
public void testDeleteAllExact() {
RecordView<PersonPojo> pojoView = defaultTable().recordView(Mapper.of(PersonPojo.class));
pojoView.upsertAll(
null,
List.of(new PersonPojo(1L, "1"), new PersonPojo(2L, "2"), new PersonPojo(3L, "3"))
);
Collection<PersonPojo> res1 = pojoView.deleteAllExact(
null,
List.of(new PersonPojo(1L, "a"), new PersonPojo(3L, "b"))
);
Collection<PersonPojo> res2 = pojoView.deleteAllExact(
null,
List.of(new PersonPojo(1L, "1"), new PersonPojo(3L, "3"))
);
assertEquals(2, res1.size());
assertEquals(0, res2.size());
assertNull(pojoView.get(null, new PersonPojo(1L)));
assertEquals("2", pojoView.get(null, new PersonPojo(2L)).name);
assertNull(pojoView.get(null, new PersonPojo(3L)));
}
@Test
public void testNullableColumnWithDefaultValueSetNullReturnsNull() {
Table table = tableWithDefaultValues();
RecordView<Tuple> recordView = table.recordView();
RecordView<DefaultValuesPojo> pojoView = table.recordView(DefaultValuesPojo.class);
var pojo = new DefaultValuesPojo();
pojo.id = 1;
pojo.str = null;
pojo.strNonNull = "s";
pojoView.upsert(null, pojo);
var res = recordView.get(null, Tuple.create().set("id", 1));
assertNull(res.stringValue("str"));
}
@Test
public void testNonNullableColumnWithDefaultValueSetNullThrowsException() {
Table table = tableWithDefaultValues();
RecordView<DefaultValuesPojo> pojoView = table.recordView(DefaultValuesPojo.class);
var pojo = new DefaultValuesPojo();
pojo.id = 1;
pojo.strNonNull = null;
var ex = assertThrows(IgniteException.class, () -> pojoView.upsert(null, pojo));
assertThat(ex.getMessage(), containsString("Column 'STRNONNULL' does not allow NULLs"));
assertThat(Arrays.asList(ex.getStackTrace()), anyOf(hasToString(containsString("ClientRecordView"))));
}
}