package io.smartcat.migration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.datastax.driver.core.ConsistencyLevel; import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.Row; import com.datastax.driver.core.Session; import com.datastax.driver.core.Statement; import com.datastax.driver.core.querybuilder.QueryBuilder; /** * Class responsible for version management. */ public class CassandraVersioner { private static final Logger LOGGER = LoggerFactory.getLogger(CassandraVersioner.class); private static final String SCHEMA_VERSION_CF = "schema_version"; private static final String TYPE = "type"; private static final String VERSION = "version"; private static final String TIMESTAMP = "ts"; private static final String DESCRIPTION = "description"; private static final String CREATE_SCHEMA_VERSION_CQL = String.format("CREATE TABLE IF NOT EXISTS %s (", SCHEMA_VERSION_CF) + String.format("%s text,", TYPE) + String.format("%s int,", VERSION) + String.format("%s bigint,", TIMESTAMP) + String.format("%s text,", DESCRIPTION) + String.format("PRIMARY KEY (%s, %s)", TYPE, VERSION) + String.format(") WITH CLUSTERING ORDER BY (%s DESC)", VERSION) + " AND COMMENT='Schema version';"; private final Session session; /** * Create Cassandra versioner for active session. * @param session Active Cassandra session */ public CassandraVersioner(final Session session) { this.session = session; createSchemaVersion(); } private void createSchemaVersion() { LOGGER.debug("Try to create schema version column family"); this.session.execute(CREATE_SCHEMA_VERSION_CQL); } /** * Get current database version for given migration type with ALL consistency. Select one row since * migration history is saved ordered descending by timestamp. If there are no rows in the schema_version table, * return 0 as default database version. Data version is changed by executing migrations. * * @param type Migration type * @return Database version for given type */ public int getCurrentVersion(final MigrationType type) { final Statement select = QueryBuilder.select().all().from(SCHEMA_VERSION_CF) .where(QueryBuilder.eq(TYPE, type.name())).limit(1).setConsistencyLevel(ConsistencyLevel.ALL); final ResultSet result = session.execute(select); final Row row = result.one(); return row == null ? 0 : row.getInt(VERSION); } /** * Update current database version to the migration version. This is executed after migration success. * * @param migration Migration that updated the database version * @return Success of version update */ public boolean updateVersion(final Migration migration) { final Statement insert = QueryBuilder.insertInto(SCHEMA_VERSION_CF).value(TYPE, migration.getType().name()) .value(VERSION, migration.getVersion()).value(TIMESTAMP, System.currentTimeMillis()) .value(DESCRIPTION, migration.getDescription()).setConsistencyLevel(ConsistencyLevel.ALL); try { session.execute(insert); return true; } catch (final Exception e) { LOGGER.error("Failed to execute update version statement", e); return false; } } }