package org.javers.repository.sql.schema;
import org.polyjdbc.core.dialect.Dialect;
import org.polyjdbc.core.dialect.OracleDialect;
import org.polyjdbc.core.dialect.MysqlDialect;
import org.polyjdbc.core.schema.model.RelationBuilder;
import org.polyjdbc.core.schema.model.Schema;
import org.polyjdbc.core.util.StringUtils;
import java.util.Map;
import java.util.TreeMap;
/**
* non-configurable schema factory, gives you schema with default table names
*
* @author bartosz walacik
*/
public class FixedSchemaFactory extends SchemaNameAware {
public static final String GLOBAL_ID_TABLE_NAME = "jv_global_id";
public static final String GLOBAL_ID_PK = "global_id_pk";
public static final String GLOBAL_ID_LOCAL_ID = "local_id";
public static final String GLOBAL_ID_FRAGMENT = "fragment"; //since 1.2
public static final String GLOBAL_ID_TYPE_NAME = "type_name"; //since 2.0
public static final String GLOBAL_ID_OWNER_ID_FK ="owner_id_fk"; //since 1.2
public static final String GLOBAL_ID_PK_SEQ = "jv_global_id_pk_seq";
public static final String COMMIT_TABLE_NAME = "jv_commit";
public static final String COMMIT_PK = "commit_pk";
public static final String COMMIT_AUTHOR = "author";
public static final String COMMIT_COMMIT_DATE = "commit_date";
public static final String COMMIT_COMMIT_ID = "commit_id";
public static final String COMMIT_PK_SEQ = "jv_commit_pk_seq";
public static final String COMMIT_PROPERTY_TABLE_NAME = "jv_commit_property";
public static final String COMMIT_PROPERTY_COMMIT_FK = "commit_fk";
public static final String COMMIT_PROPERTY_NAME = "property_name";
public static final String COMMIT_PROPERTY_VALUE = "property_value";
public static final String SNAPSHOT_TABLE_NAME = "jv_snapshot";
public static final String SNAPSHOT_PK = "snapshot_pk";
public static final String SNAPSHOT_COMMIT_FK = "commit_fk";
public static final String SNAPSHOT_GLOBAL_ID_FK = "global_id_fk";
public static final String SNAPSHOT_TYPE = "type";
public static final String SNAPSHOT_VERSION = "version";
public static final String SNAPSHOT_TABLE_PK_SEQ = "jv_snapshot_pk_seq";
public static final String SNAPSHOT_STATE = "state";
public static final String SNAPSHOT_CHANGED = "changed_properties"; //since v 1.2
public static final String SNAPSHOT_MANAGED_TYPE = "managed_type"; //since 2.0
private final static int ORACLE_MAX_NAME_LEN = 30;
private final Dialect dialect;
public FixedSchemaFactory(Dialect dialect, TableNameProvider tableNameProvider) {
super(tableNameProvider);
this.dialect = dialect;
}
Map<String, Schema> allTablesSchema(Dialect dialect) {
Map<String, Schema> schema = new TreeMap<>();
schema.put(GLOBAL_ID_TABLE_NAME, globalIdTableSchema(dialect));
schema.put(COMMIT_TABLE_NAME, commitTableSchema(dialect));
schema.put(COMMIT_PROPERTY_TABLE_NAME, commitPropertiesTableSchema(dialect));
schema.put(SNAPSHOT_TABLE_NAME, snapshotTableSchema(dialect));
return schema;
}
private Schema snapshotTableSchema(Dialect dialect){
DBObjectName tableName = getSnapshotTableName();
Schema schema = new Schema(dialect);
RelationBuilder relationBuilder = schema.addRelation(tableName.nameWithSchema());
primaryKey(SNAPSHOT_PK, schema, relationBuilder);
relationBuilder.withAttribute().string(SNAPSHOT_TYPE).withMaxLength(200).and()
.withAttribute().longAttr(SNAPSHOT_VERSION).and()
.withAttribute().text(SNAPSHOT_STATE).and()
.withAttribute().text(SNAPSHOT_CHANGED).and()
.withAttribute().string(SNAPSHOT_MANAGED_TYPE).withMaxLength(200).and();
foreignKey(tableName, SNAPSHOT_GLOBAL_ID_FK, getGlobalIdTableNameWithSchema(), GLOBAL_ID_PK, relationBuilder);
foreignKey(tableName, SNAPSHOT_COMMIT_FK, getCommitTableNameWithSchema(), COMMIT_PK, relationBuilder);
relationBuilder.build();
columnsIndex(tableName, schema, SNAPSHOT_GLOBAL_ID_FK);
columnsIndex(tableName, schema, SNAPSHOT_COMMIT_FK);
return schema;
}
private Schema commitTableSchema(Dialect dialect) {
DBObjectName tableName = getCommitTableName();
Schema schema = new Schema(dialect);
RelationBuilder relationBuilder = schema.addRelation(tableName.nameWithSchema());
primaryKey(COMMIT_PK,schema,relationBuilder);
relationBuilder
.withAttribute().string(COMMIT_AUTHOR).withMaxLength(200).and()
.withAttribute().timestamp(COMMIT_COMMIT_DATE).and()
.withAttribute().number(COMMIT_COMMIT_ID).withIntegerPrecision(22).withDecimalPrecision(2).and()
.build();
columnsIndex(tableName, schema, COMMIT_COMMIT_ID);
return schema;
}
private Schema commitPropertiesTableSchema(Dialect dialect) {
DBObjectName tableName = getCommitPropertyTableName();
Schema schema = new Schema(dialect);
RelationBuilder relationBuilder = schema.addRelation(tableName.nameWithSchema());
relationBuilder
.primaryKey(tableName.localName() + "_pk").using(COMMIT_PROPERTY_COMMIT_FK, COMMIT_PROPERTY_NAME).and()
.withAttribute().string(COMMIT_PROPERTY_NAME).withMaxLength(190).and()
.withAttribute().string(COMMIT_PROPERTY_VALUE).withMaxLength(600).and();
foreignKey(tableName, COMMIT_PROPERTY_COMMIT_FK, getCommitTableNameWithSchema(), COMMIT_PK, relationBuilder);
relationBuilder.build();
columnsIndex(tableName, schema, COMMIT_PROPERTY_COMMIT_FK);
// Add index prefix length for MySql
if (dialect instanceof MysqlDialect) {
columnsIndex(tableName, schema, new IndexedCols(
new String[]{COMMIT_PROPERTY_NAME, COMMIT_PROPERTY_VALUE},
new int[]{0, 200}));
}
else {
columnsIndex(tableName, schema, COMMIT_PROPERTY_NAME, COMMIT_PROPERTY_VALUE);
}
return schema;
}
private Schema globalIdTableSchema(Dialect dialect){
DBObjectName tableName = getGlobalIdTableName();
Schema schema = new Schema(dialect);
RelationBuilder relationBuilder = schema.addRelation(tableName.nameWithSchema());
primaryKey(GLOBAL_ID_PK, schema,relationBuilder);
relationBuilder
.withAttribute().string(GLOBAL_ID_LOCAL_ID).withMaxLength(190).and()
.withAttribute().string(GLOBAL_ID_FRAGMENT).withMaxLength(200).and()
.withAttribute().string(GLOBAL_ID_TYPE_NAME).withMaxLength(200).and();
foreignKey(tableName, GLOBAL_ID_OWNER_ID_FK, getGlobalIdTableNameWithSchema(), GLOBAL_ID_PK, relationBuilder);
relationBuilder.build();
columnsIndex(tableName, schema, GLOBAL_ID_LOCAL_ID);
return schema;
}
private void foreignKey(DBObjectName tableName, String fkColName, String targetTableName, String targetPkColName, RelationBuilder relationBuilder){
relationBuilder
.withAttribute().longAttr(fkColName).and()
.foreignKey(tableName.localName() + "_" + fkColName).on(fkColName).references(targetTableName, targetPkColName).and();
}
private void columnsIndex(DBObjectName tableName, Schema schema, String... colNames){
columnsIndex(tableName, schema, new IndexedCols(colNames));
}
private void columnsIndex(DBObjectName tableName, Schema schema, IndexedCols indexedCols){
String indexName = tableName.localName() + "_" + indexedCols.concatenatedColNames() + "_idx";
if (dialect instanceof OracleDialect &&
indexName.length() > ORACLE_MAX_NAME_LEN)
{
indexName = indexName.substring(0, ORACLE_MAX_NAME_LEN);
}
schema.addIndex(indexName)
.indexing(indexedCols.indexedColNames())
.on(tableName.nameWithSchema())
.build();
}
private void primaryKey(String pkColName, Schema schema, RelationBuilder relationBuilder) {
relationBuilder.withAttribute().longAttr(pkColName).withAdditionalModifiers("AUTO_INCREMENT").notNull().and()
.primaryKey("jv_"+pkColName).using(pkColName).and();
schema.addSequence(getSequenceNameWithSchema(pkColName)).build();
}
private static class IndexedCols {
private final String[] colNames;
private final int[] prefixLengths;
IndexedCols(String... colNames) {
this.colNames = colNames;
this.prefixLengths = new int[colNames.length];
}
IndexedCols(String[] colNames, int[] prefixLengths) {
this.colNames = colNames;
this.prefixLengths = prefixLengths;
}
String concatenatedColNames() {
return StringUtils.concatenate('_', (Object[]) colNames);
}
String[] indexedColNames() {
String[] indexedNames = new String[colNames.length];
for (int i=0; i<colNames.length; i++) {
indexedNames[i] = colNames[i];
if (prefixLengths[i] > 0) {
indexedNames[i] += "("+prefixLengths[i]+")";
}
}
return indexedNames;
}
}
}