/** * Copyright (c) 2016, All Contributors (see CONTRIBUTORS file) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.eventsourcing.postgresql.index; import com.eventsourcing.Entity; import com.eventsourcing.EntityHandle; import com.eventsourcing.StandardEntity; import com.eventsourcing.hlc.HybridTimestamp; import com.eventsourcing.index.Attribute; import com.eventsourcing.index.NavigableIndexTest; import com.eventsourcing.index.SimpleAttribute; import com.eventsourcing.layout.Layout; import com.google.common.io.BaseEncoding; import com.googlecode.cqengine.index.Index; import com.googlecode.cqengine.quantizer.Quantizer; import com.googlecode.cqengine.query.option.QueryOptions; import lombok.SneakyThrows; import org.testng.annotations.Test; import javax.sql.DataSource; import java.security.MessageDigest; import java.sql.Connection; import java.sql.PreparedStatement; import static com.eventsourcing.postgresql.PostgreSQLTest.createDataSource; import static org.testng.Assert.fail; @Test public class PostgreSQLNavigableIndexTest extends NavigableIndexTest<NavigableIndex> { private DataSource dataSource; @Override public <A extends Comparable<A>, O extends Entity> NavigableIndex onAttribute(Attribute<O, A> attribute) { if (dataSource == null) { this.dataSource = createDataSource(); } return NavigableIndex.onAttribute(dataSource, attribute); } @Override public <A extends Comparable<A>, O extends Entity> Index<EntityHandle<O>> withQuantizerOnAttribute(Quantizer<A> quantizer, com.eventsourcing.index.Attribute<O, A> attribute) { if (dataSource == null) { this.dataSource = createDataSource(); } return NavigableIndex.withQuantizerOnAttribute(dataSource, quantizer, attribute); } public static class TestEntity extends StandardEntity { public static final SimpleAttribute<TestEntity, HybridTimestamp> TIMESTAMP = new SimpleAttribute<TestEntity, HybridTimestamp>("ts") { @Override public HybridTimestamp getValue(TestEntity object, QueryOptions queryOptions) { return object.timestamp(); } }; } // Because of the bug fixed in https://github.com/eventsourcing/es4j/pull/197 (commit a4d6771) // serializable comparable for timestamp wasn't correct and such indices have to be rebuilt @Test @SneakyThrows public void test_a4d6711_drop() { if (dataSource == null) { this.dataSource = createDataSource(); } try (Connection c = dataSource.getConnection()) { Layout<TestEntity> layout = Layout.forClass(TestEntity.class); MessageDigest digest = MessageDigest.getInstance("SHA-1"); digest.update(layout.getHash()); digest.update("ts".getBytes()); String encodedHash = BaseEncoding.base16().encode(digest.digest()); String tableName = "index_v1_" + encodedHash + "_navigable"; // this is how this index looked before a4d6771 String create = "CREATE TABLE IF NOT EXISTS " + tableName + " (" + "\"key\" BIGINT,\n" + "\"object\" UUID," + "PRIMARY KEY(\"key\", \"object\")" + ")"; try (PreparedStatement s = c.prepareStatement(create)) { s.executeUpdate(); } onAttribute(TestEntity.TIMESTAMP); try (PreparedStatement s = c.prepareStatement("SELECT count(column_name) from information_schema.columns where " + "lower(table_name) = lower(?) AND lower(column_name) = " + "'key' AND lower(data_type) = 'numeric'")) { s.setString(1, tableName); try (java.sql.ResultSet rs = s.executeQuery()) { if (rs.next()) { if (rs.getInt(1) != 1) { fail("key data_type is still not numeric"); } } } } } } }