/*
* Copyright 2007 - 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.jailer.datamodel;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.sf.jailer.configuration.Configuration;
import net.sf.jailer.database.Session;
/**
* Factory for {@link PrimaryKey}s. Builds the universal primary key as a
* super-set of all created primary key.
*
* @author Ralf Wisser
*/
public class PrimaryKeyFactory {
/**
* {@link #getUniversalPrimaryKey()} closes the factory, no further creation
* of PKs is allowed then.
*/
private boolean closed = false;
/**
* A super-set of all columns of created primary-keys.
*/
private PrimaryKey universalPrimaryKey = new PrimaryKey(
new ArrayList<Column>());
/**
* Constructs a new primary-key.
*
* @return a newly created primary-key
*
* @exception IllegalStateException
* if factory is closed
*/
public PrimaryKey createPrimaryKey(List<Column> columns) {
if (closed) {
throw new IllegalStateException("factory is closed");
}
PrimaryKey primaryKey = new PrimaryKey(columns);
if (Configuration.getInstance().getDoMinimizeUPK()) {
Set<Integer> assignedUPKColumns = new HashSet<Integer>();
for (Column column: columns) {
boolean assigned = false;
for (int i = 0; i < universalPrimaryKey.getColumns().size(); ++i) {
if (assignedUPKColumns.contains(i)) {
continue;
}
Column uPKColumn = universalPrimaryKey.getColumns().get(i);
if (uPKColumn.type.equalsIgnoreCase(column.type) && column.precision < 0 && uPKColumn.precision < 0) {
if (column.length > 0 && uPKColumn.length > 0 && column.length > uPKColumn.length) {
// increase length
universalPrimaryKey.getColumns().set(
i,
new Column(uPKColumn.name, uPKColumn.type,
column.length, column.precision));
}
assigned = true;
assignedUPKColumns.add(i);
break;
}
if (uPKColumn.type.equalsIgnoreCase(column.type) && column.precision >= 0 && uPKColumn.precision >= 0
&& (column.length >= uPKColumn.length && column.precision >= uPKColumn.precision
|| column.length <= uPKColumn.length && column.precision <= uPKColumn.precision)) {
if (column.length > 0 && column.length > uPKColumn.length) {
// increase length
universalPrimaryKey.getColumns().set(
i,
new Column(uPKColumn.name, uPKColumn.type,
Math.max(column.length, uPKColumn.length),
Math.max(column.precision,uPKColumn.precision)));
}
assigned = true;
assignedUPKColumns.add(i);
break;
}
}
if (!assigned) {
// add new columns to universal primary key
universalPrimaryKey.getColumns().add(
new Column(createUniqueUPKName(), column.type,
column.length, column.precision));
assignedUPKColumns.add(universalPrimaryKey.getColumns().size() - 1);
}
}
return primaryKey;
} else {
int n = 0;
if (!columns.isEmpty()) {
for (int i = 0; i < universalPrimaryKey.getColumns().size(); ++i) {
Column uPKColumn = universalPrimaryKey.getColumns().get(i);
Column column = columns.get(n);
if(PrimaryKey.isAssignable(uPKColumn,column)) {
++n;
} else {
if(PrimaryKey.isIncreasable(uPKColumn, column)) {
// increase length
universalPrimaryKey.getColumns().set(
i,
new Column(uPKColumn.name, uPKColumn.type,
Math.max(column.length, uPKColumn.length),
Math.max(column.precision,uPKColumn.precision)));
++n;
}
}
if(n>=columns.size()) {
break;
}
}
}
// add new columns to universal primary key
for (; n < columns.size(); ++n) {
Column column = columns.get(n);
universalPrimaryKey.getColumns().add(
new Column(createUniqueUPKName(), column.type,
column.length, column.precision));
}
return primaryKey;
}
}
/**
* Creates a unique name for a new universal primary key column.
*
* @return a unique name for a new universal primary key column
*/
private String createUniqueUPKName() {
return "PK" + universalPrimaryKey.getColumns().size();
}
/**
* Gets the primary-key to be used for the entity-table and closes the
* factory.
*
* @param session
* for guessing null-values of columns
* @return the universal primary key
*/
public PrimaryKey getUniversalPrimaryKey(Session session) {
closed = true;
return universalPrimaryKey;
}
}