package org.vertexium.sql.collections;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterators;
import org.h2.jdbcx.JdbcConnectionPool;
import org.junit.*;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.util.IntegerMapper;
import org.skife.jdbi.v2.util.StringMapper;
import org.vertexium.VertexiumSerializer;
import org.vertexium.serializer.xstream.XStreamVertexiumSerializer;
import javax.sql.DataSource;
import java.util.*;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
@RunWith(JUnit4.class)
public class SqlMapTest {
private static Handle handle;
private static DataSource dataSource;
private SqlMap<SerializableThing> sqlMap;
private static final SerializableThing THING_1 = new SerializableThing(1);
private static final SerializableThing THING_2 = new SerializableThing(2);
private static final SerializableThing THING_3 = new SerializableThing(3);
private static final SerializableThing THING_4 = new SerializableThing(4);
private XStreamVertexiumSerializer serializer = new XStreamVertexiumSerializer();
@BeforeClass
public static void beforeClass() {
dataSource = JdbcConnectionPool.create("jdbc:h2:mem:test", "username", "password");
handle = new DBI(dataSource).open();
createTable(handle, "map");
}
@Before
public void before() {
handle.execute("insert into map (key, value) values (?, ?)", "key1", serializer.objectToBytes(THING_1));
handle.execute("insert into map (key, value) values (?, ?)", "key2", serializer.objectToBytes(THING_2));
sqlMap = new SqlMap<>("map", "key", "value", dataSource, serializer);
}
@After
public void after() {
handle.execute("delete from map");
}
@AfterClass
public static void afterClass() {
dropTable(handle, "map");
handle.close();
}
static void createTable(Handle handle, String tableName) {
handle.execute(String.format(
"create table %s (key varchar(100) primary key not null, value clob not null, num int, str varchar(100))",
tableName));
}
static void dropTable(Handle handle, String tableName) {
handle.execute(String.format("drop table %s", tableName));
}
@Test
public void getReturnsStoredValue() {
assertThat(sqlMap.get("key1"), equalTo((Object) THING_1));
assertThat(sqlMap.get("key2"), equalTo((Object) THING_2));
}
@Test
public void putStoresKeyAndValue() {
SerializableThing previous = sqlMap.put("key3", THING_3);
assertThat(previous, nullValue());
assertThat(sqlMap.get("key3"), equalTo(THING_3));
previous = sqlMap.put("key3", THING_4);
assertThat(previous, equalTo(THING_3));
assertThat(sqlMap.get("key3"), equalTo(THING_4));
}
@Test
public void removeDeletesKeyAndValue() {
SerializableThing previous = sqlMap.remove("key1");
assertThat(previous, equalTo(THING_1));
assertThat(sqlMap.get("key1"), nullValue());
assertThat(sqlMap.size(), equalTo(1));
}
@Test
public void sizeReturnsCount() {
assertThat(sqlMap.size(), equalTo(2));
}
@Test
public void clearRemovesAll() {
sqlMap.clear();
int count = handle.createQuery("select count (*) from map").map(IntegerMapper.FIRST).first();
assertThat(count, equalTo(0));
}
@Test
public void containsKeyReturnsTrueIfKeyIsPresent() {
assertThat(sqlMap.containsKey("key1"), equalTo(true));
}
@Test
public void containsKeyReturnsFalseIfKeyIsNotPresent() {
assertThat(sqlMap.containsKey("nope"), equalTo(false));
}
@Test
public void containsValueReturnsTrueIfValueIsPresent() {
assertThat(sqlMap.containsValue(THING_1), equalTo(true));
}
@Test
public void containsValueReturnsFalseIfValueIsNotPresent() {
assertThat(sqlMap.containsValue(THING_3), equalTo(false));
}
@Test
public void valuesReturnsAllValues() {
Collection<SerializableThing> expected = ImmutableSet.of(THING_1, THING_2);
assertThat(new HashSet<>(sqlMap.values()), equalTo((Object) expected));
}
@Test
public void keySetReturnsAllKeys() {
Set<String> expected = ImmutableSet.of("key1", "key2");
assertThat(new HashSet<>(sqlMap.keySet()), equalTo(expected));
}
@Test
public void entrySetReturnsAllEntries() {
Set<Map.Entry<String, SerializableThing>> expected = ImmutableSet.<Map.Entry<String, SerializableThing>>of(
new MapEntry<>("key1", THING_1),
new MapEntry<>("key2", THING_2)
);
assertThat(new HashSet<>(sqlMap.entrySet()), equalTo(expected));
}
@Test
public void putStoresExtraColumns() {
ExtraColumnsJdbcMap extraMap = new ExtraColumnsJdbcMap("map", "key", "value", serializer);
SerializableThing thing = new SerializableThing(42);
extraMap.put("thing", thing);
int num = handle.createQuery("select num from map where key = ?")
.bind(0, "thing")
.map(IntegerMapper.FIRST).first();
assertThat(num, equalTo(42));
String str = handle.createQuery("select str from map where key = ?")
.bind(0, "thing")
.map(StringMapper.FIRST).first();
assertThat(str, equalTo("value42"));
assertThat(extraMap.get("thing"), equalTo(thing));
}
@Test
public void queryFindsByWhereClauseWithPositionalParams() {
ExtraColumnsJdbcMap extraMap = new ExtraColumnsJdbcMap("map", "key", "value", serializer);
SerializableThing thing1 = new SerializableThing(21);
SerializableThing thing2 = new SerializableThing(42);
SerializableThing thing3 = new SerializableThing(84);
extraMap.put("thing1", thing1);
extraMap.put("thing2", thing2);
extraMap.put("thing3", thing3);
Iterator<SerializableThing> thingIterator = extraMap.query("num > ? and str like 'value%'", 21);
SerializableThing[] things = Iterators.toArray(thingIterator, SerializableThing.class);
assertThat(things.length, equalTo(2));
assertThat(things[0], equalTo(thing2));
assertThat(things[1], equalTo(thing3));
}
@Test
public void queryFindsByWhereClauseWithNamedParams() {
ExtraColumnsJdbcMap extraMap = new ExtraColumnsJdbcMap("map", "key", "value", serializer);
SerializableThing thing1 = new SerializableThing(21);
SerializableThing thing2 = new SerializableThing(42);
SerializableThing thing3 = new SerializableThing(84);
extraMap.put("thing1", thing1);
extraMap.put("thing2", thing2);
extraMap.put("thing3", thing3);
Iterator<SerializableThing> thingIterator = extraMap.query("num > :n and str like :s",
ImmutableMap.<String, Object>of(
"n", 21,
"s", "value%"));
SerializableThing[] things = Iterators.toArray(thingIterator, SerializableThing.class);
assertThat(things.length, equalTo(2));
assertThat(things[0], equalTo(thing2));
assertThat(things[1], equalTo(thing3));
}
private static class ExtraColumnsJdbcMap extends SqlMap<SerializableThing> {
public ExtraColumnsJdbcMap(String tableName, String keyColumnName, String valueColumnName, VertexiumSerializer serializer) {
super(tableName, keyColumnName, valueColumnName, dataSource, serializer);
}
@Override
protected Map<String, Object> additionalColumns(String key, SerializableThing value) {
return ImmutableMap.<String, Object>of(
"num", value.i,
"str", value.s
);
}
}
}