package io.ebeaninternal.dbmigration.model.build;
import io.ebean.config.DbConstraintNaming;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.config.dbplatform.DbPlatformTypeMapping;
import io.ebeaninternal.dbmigration.model.MColumn;
import io.ebeaninternal.dbmigration.model.MCompoundForeignKey;
import io.ebeaninternal.dbmigration.model.MTable;
import io.ebeaninternal.dbmigration.model.ModelContainer;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.TableJoin;
import io.ebeaninternal.server.deploy.TableJoinColumn;
import io.ebeaninternal.server.type.ScalarType;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class ModelBuildContext {
private final DbPlatformTypeMapping dbTypeMap = DbPlatformTypeMapping.logicalTypes();
private final ModelContainer model;
private final DbConstraintNaming constraintNaming;
private final DbConstraintNaming.MaxLength maxLength;
private final boolean platformTypes;
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength, boolean platformTypes) {
this.model = model;
this.constraintNaming = naming;
this.maxLength = maxLength;
this.platformTypes = platformTypes;
}
public void adjustDraftReferences() {
model.adjustDraftReferences();
}
public String normaliseTable(String baseTable) {
return constraintNaming.normaliseTable(baseTable);
}
public String primaryKeyName(String tableName) {
return maxLength(constraintNaming.primaryKeyName(tableName), 0);
}
public String foreignKeyConstraintName(String tableName, String columnName, int foreignKeyCount) {
return maxLength(constraintNaming.foreignKeyConstraintName(tableName, columnName), foreignKeyCount);
}
public String foreignKeyIndexName(String tableName, String[] columns, int indexCount) {
return maxLength(constraintNaming.foreignKeyIndexName(tableName, columns), indexCount);
}
public String foreignKeyIndexName(String tableName, String column, int indexCount) {
return maxLength(constraintNaming.foreignKeyIndexName(tableName, column), indexCount);
}
public String indexName(String tableName, String column, int indexCount) {
return maxLength(constraintNaming.indexName(tableName, column), indexCount);
}
public String indexName(String tableName, String[] columns, int indexCount) {
return maxLength(constraintNaming.indexName(tableName, columns), indexCount);
}
public String uniqueConstraintName(String tableName, String columnName, int indexCount) {
return maxLength(constraintNaming.uniqueConstraintName(tableName, columnName), indexCount);
}
public String uniqueConstraintName(String tableName, String[] columnNames, int indexCount) {
return maxLength(constraintNaming.uniqueConstraintName(tableName, columnNames), indexCount);
}
public String checkConstraintName(String tableName, String columnName, int checkCount) {
return maxLength(constraintNaming.checkConstraintName(tableName, columnName), checkCount);
}
public MTable addTable(MTable table) {
return model.addTable(table);
}
public void addIndex(String indexName, String tableName, String columnName) {
model.addIndex(indexName, tableName, columnName);
}
public void addIndex(String indexName, String tableName, String[] columnNames) {
model.addIndex(indexName, tableName, columnNames);
}
private String maxLength(String constraintName, int indexCount) {
return maxLength.maxLength(constraintName, indexCount);
}
public DbPlatformTypeMapping getDbTypeMap() {
return dbTypeMap;
}
public String getColumnDefn(BeanProperty p, boolean strict) {
DbPlatformType dbType = getDbType(p);
if (dbType == null) {
throw new IllegalStateException("Unknown DbType mapping for " + p.getFullBeanName());
}
return p.renderDbType(dbType, strict);
}
private DbPlatformType getDbType(BeanProperty p) {
if (p.isDbEncrypted()) {
return dbTypeMap.get(p.getDbEncryptedType());
}
if (p.isLocalEncrypted()) {
ScalarType<Object> scalarType = p.getScalarType();
int jdbcType = scalarType.getJdbcType();
return dbTypeMap.get(jdbcType);
}
int dbType = p.getDbType(platformTypes);
if (dbType == 0) {
throw new RuntimeException("No scalarType defined for " + p.getFullBeanName());
}
return dbTypeMap.get(dbType);
}
public void createDraft(MTable table, boolean draftable) {
MTable draftTable = table.createDraftTable();
draftTable.setPkName(primaryKeyName(draftTable.getName()));
if (draftable) {
List<MColumn> pkCols = table.primaryKeyColumns();
if (pkCols.size() == 1) {
MColumn pk = pkCols.get(0);
pk.setReferences(draftTable.getName() + "." + pk.getName());
pk.setForeignKeyName(foreignKeyConstraintName(table.getName(), pk.getName(), 0));
}
}
int fkCount = 0;
int ixCount = 0;
int uqCount = 0;
Collection<MColumn> cols = draftTable.allColumns();
for (MColumn col : cols) {
if (col.getForeignKeyName() != null) {
col.setForeignKeyName(foreignKeyConstraintName(draftTable.getName(), col.getName(), ++fkCount));
String[] indexCols = {col.getName()};
col.setForeignKeyIndex(foreignKeyIndexName(draftTable.getName(), indexCols, ++ixCount));
}
if (col.getUnique() != null) {
col.setUnique(uniqueConstraintName(draftTable.getName(), col.getName(), ++uqCount));
}
if (col.getUniqueOneToOne() != null) {
col.setUniqueOneToOne(uniqueConstraintName(draftTable.getName(), col.getName(), ++uqCount));
}
}
addTable(draftTable);
}
public FkeyBuilder fkeyBuilder(MTable destTable) {
return new FkeyBuilder(this, destTable);
}
public static class FkeyBuilder {
private final AtomicInteger count = new AtomicInteger();
private final ModelBuildContext ctx;
private final MTable destTable;
private final String tableName;
FkeyBuilder(ModelBuildContext ctx, MTable destTable) {
this.ctx = ctx;
this.destTable = destTable;
this.tableName = destTable.getName();
}
public FkeyBuilder addForeignKey(BeanDescriptor<?> desc, TableJoin tableJoin, boolean direction) {
String baseTable = ctx.normaliseTable(desc.getBaseTable());
String fkName = ctx.foreignKeyConstraintName(tableName, baseTable, count.incrementAndGet());
String fkIndex = ctx.foreignKeyIndexName(tableName, baseTable, count.get());
MCompoundForeignKey foreignKey = new MCompoundForeignKey(fkName, desc.getBaseTable(), fkIndex);
for (TableJoinColumn column : tableJoin.columns()) {
String localCol = direction ? column.getForeignDbColumn() : column.getLocalDbColumn();
String refCol = !direction ? column.getForeignDbColumn() : column.getLocalDbColumn();
foreignKey.addColumnPair(localCol, refCol);
}
destTable.addForeignKey(foreignKey);
return this;
}
}
}