@Table(uniqueConstraints) support from Zell.
This commit is contained in:
@@ -31,8 +31,12 @@ import java.sql.SQLException;
|
|||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
@@ -42,8 +46,10 @@ import com.samskivert.jdbc.depot.annotation.Entity;
|
|||||||
import com.samskivert.jdbc.depot.annotation.GeneratedValue;
|
import com.samskivert.jdbc.depot.annotation.GeneratedValue;
|
||||||
import com.samskivert.jdbc.depot.annotation.Id;
|
import com.samskivert.jdbc.depot.annotation.Id;
|
||||||
import com.samskivert.jdbc.depot.annotation.Index;
|
import com.samskivert.jdbc.depot.annotation.Index;
|
||||||
|
import com.samskivert.jdbc.depot.annotation.Table;
|
||||||
import com.samskivert.jdbc.depot.annotation.TableGenerator;
|
import com.samskivert.jdbc.depot.annotation.TableGenerator;
|
||||||
import com.samskivert.jdbc.depot.annotation.Transient;
|
import com.samskivert.jdbc.depot.annotation.Transient;
|
||||||
|
import com.samskivert.jdbc.depot.annotation.UniqueConstraint;
|
||||||
|
|
||||||
import com.samskivert.jdbc.JDBCUtil;
|
import com.samskivert.jdbc.JDBCUtil;
|
||||||
import com.samskivert.jdbc.depot.clause.Where;
|
import com.samskivert.jdbc.depot.clause.Where;
|
||||||
@@ -71,8 +77,10 @@ public class DepotMarshaller<T>
|
|||||||
{
|
{
|
||||||
_pclass = pclass;
|
_pclass = pclass;
|
||||||
|
|
||||||
// see if this is a computed entity
|
|
||||||
Entity entity = pclass.getAnnotation(Entity.class);
|
Entity entity = pclass.getAnnotation(Entity.class);
|
||||||
|
Table table = null;
|
||||||
|
|
||||||
|
// see if this is a computed entity
|
||||||
Computed computed = pclass.getAnnotation(Computed.class);
|
Computed computed = pclass.getAnnotation(Computed.class);
|
||||||
if (computed == null) {
|
if (computed == null) {
|
||||||
// if not, this class has a corresponding SQL table
|
// if not, this class has a corresponding SQL table
|
||||||
@@ -86,6 +94,9 @@ public class DepotMarshaller<T>
|
|||||||
}
|
}
|
||||||
_postamble = entity.postamble();
|
_postamble = entity.postamble();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for a Table annotation, for unique constraints
|
||||||
|
table = pclass.getAnnotation(Table.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the entity defines a new TableGenerator, map that in our static table as those are
|
// if the entity defines a new TableGenerator, map that in our static table as those are
|
||||||
@@ -221,6 +232,14 @@ public class DepotMarshaller<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add any unique constraints given
|
||||||
|
if (table != null) {
|
||||||
|
for (UniqueConstraint constraint : table.uniqueConstraints()) {
|
||||||
|
_declarations.add(
|
||||||
|
"UNIQUE (" + StringUtil.join(constraint.columnNames(), ", ") + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// add the primary key, if we have one
|
// add the primary key, if we have one
|
||||||
if (hasPrimaryKey()) {
|
if (hasPrimaryKey()) {
|
||||||
_declarations.add("PRIMARY KEY (" + getPrimaryKeyColumns() + ")");
|
_declarations.add("PRIMARY KEY (" + getPrimaryKeyColumns() + ")");
|
||||||
@@ -666,8 +685,8 @@ public class DepotMarshaller<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// enumerate all of the columns now that we've run our pre-migrations
|
// enumerate all of the columns now that we've run our pre-migrations
|
||||||
final HashSet<String> columns = new HashSet<String>();
|
final Set<String> columns = new HashSet<String>();
|
||||||
final HashSet<String> indices = new HashSet<String>();
|
final Map<String, Set<String>> indexColumns = new HashMap<String, Set<String>>();
|
||||||
ctx.invoke(new Modifier() {
|
ctx.invoke(new Modifier() {
|
||||||
public int invoke (Connection conn) throws SQLException {
|
public int invoke (Connection conn) throws SQLException {
|
||||||
DatabaseMetaData meta = conn.getMetaData();
|
DatabaseMetaData meta = conn.getMetaData();
|
||||||
@@ -675,14 +694,34 @@ public class DepotMarshaller<T>
|
|||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
columns.add(rs.getString("COLUMN_NAME"));
|
columns.add(rs.getString("COLUMN_NAME"));
|
||||||
}
|
}
|
||||||
|
|
||||||
rs = meta.getIndexInfo(null, null, getTableName(), false, false);
|
rs = meta.getIndexInfo(null, null, getTableName(), false, false);
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
indices.add(rs.getString("INDEX_NAME"));
|
String indexName = rs.getString("INDEX_NAME");
|
||||||
|
Set<String> set = indexColumns.get(indexName);
|
||||||
|
if (rs.getBoolean("NON_UNIQUE")) {
|
||||||
|
// not a unique index: just make sure there's an entry in the keyset
|
||||||
|
if (set == null) {
|
||||||
|
indexColumns.put(indexName, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// for unique indices we collect the column names
|
||||||
|
if (set == null) {
|
||||||
|
set = new HashSet<String>();
|
||||||
|
indexColumns.put(indexName, set);
|
||||||
|
}
|
||||||
|
set.add(rs.getString("COLUMN_NAME"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// this is a little silly, but we need a copy for name disambiguation later
|
||||||
|
Set<String> indicesCopy = new HashSet<String>(indexColumns.keySet());
|
||||||
|
|
||||||
// add any missing columns
|
// add any missing columns
|
||||||
for (String fname : _columnFields) {
|
for (String fname : _columnFields) {
|
||||||
FieldMarshaller fmarsh = _fields.get(fname);
|
FieldMarshaller fmarsh = _fields.get(fname);
|
||||||
@@ -717,12 +756,12 @@ public class DepotMarshaller<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add or remove the primary key as needed
|
// add or remove the primary key as needed
|
||||||
if (hasPrimaryKey() && !indices.remove("PRIMARY")) {
|
if (hasPrimaryKey() && !indexColumns.containsKey("PRIMARY")) {
|
||||||
String pkdef = "primary key (" + getPrimaryKeyColumns() + ")";
|
String pkdef = "primary key (" + getPrimaryKeyColumns() + ")";
|
||||||
log.info("Adding primary key to " + getTableName() + ": " + pkdef);
|
log.info("Adding primary key to " + getTableName() + ": " + pkdef);
|
||||||
ctx.invoke(new Modifier.Simple("alter table " + getTableName() + " add " + pkdef));
|
ctx.invoke(new Modifier.Simple("alter table " + getTableName() + " add " + pkdef));
|
||||||
|
|
||||||
} else if (!hasPrimaryKey() && indices.remove("PRIMARY")) {
|
} else if (!hasPrimaryKey() && indexColumns.remove("PRIMARY") != null) {
|
||||||
log.info("Dropping primary from " + getTableName());
|
log.info("Dropping primary from " + getTableName());
|
||||||
ctx.invoke(new Modifier.Simple("alter table " + getTableName() + " drop primary key"));
|
ctx.invoke(new Modifier.Simple("alter table " + getTableName() + " drop primary key"));
|
||||||
}
|
}
|
||||||
@@ -730,7 +769,7 @@ public class DepotMarshaller<T>
|
|||||||
// add any missing indices
|
// add any missing indices
|
||||||
Entity entity = _pclass.getAnnotation(Entity.class);
|
Entity entity = _pclass.getAnnotation(Entity.class);
|
||||||
for (Index index : (entity == null ? new Index[0] : entity.indices())) {
|
for (Index index : (entity == null ? new Index[0] : entity.indices())) {
|
||||||
if (indices.remove(index.name())) {
|
if (indexColumns.remove(index.name()) != null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String indexdef = "create " + index.type() + " index " + index.name() +
|
String indexdef = "create " + index.type() + " index " + index.name() +
|
||||||
@@ -739,6 +778,42 @@ public class DepotMarshaller<T>
|
|||||||
ctx.invoke(new Modifier.Simple(indexdef));
|
ctx.invoke(new Modifier.Simple(indexdef));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// to get the @Table(uniqueIndices...) indices, we use our clever set of column name sets
|
||||||
|
Set<Set<String>> uniqueIndices = new HashSet<Set<String>>(indexColumns.values());
|
||||||
|
Table table;
|
||||||
|
if (getTableName() != null && (table = _pclass.getAnnotation(Table.class)) != null) {
|
||||||
|
Set<String> colSet = new HashSet<String>();
|
||||||
|
for (UniqueConstraint constraint : table.uniqueConstraints()) {
|
||||||
|
// for each given UniqueConstraint, build a new column set
|
||||||
|
colSet.clear();
|
||||||
|
for (String column : constraint.columnNames()) {
|
||||||
|
colSet.add(column);
|
||||||
|
}
|
||||||
|
// and check if the table contained this set
|
||||||
|
if (uniqueIndices.contains(colSet)) {
|
||||||
|
continue; // good, carry on
|
||||||
|
}
|
||||||
|
|
||||||
|
// else build the index; we'll use mysql's convention of naming it after a column,
|
||||||
|
// with possible _N disambiguation; luckily we made a copy of the index names!
|
||||||
|
String indexName = colSet.iterator().next();
|
||||||
|
if (indicesCopy.contains(indexName)) {
|
||||||
|
int num = 1;
|
||||||
|
indexName += "_";
|
||||||
|
while (indicesCopy.contains(indexName + num)) {
|
||||||
|
num ++;
|
||||||
|
}
|
||||||
|
indexName += num;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] columnArr = colSet.toArray(new String[colSet.size()]);
|
||||||
|
String indexdef = "create unique index " + indexName + " on " +
|
||||||
|
getTableName() + " (" + StringUtil.join(columnArr, ", ") + ")";
|
||||||
|
log.info("Adding unique index: " + indexdef);
|
||||||
|
ctx.invoke(new Modifier.Simple(indexdef));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// we do not auto-remove columns but rather require that EntityMigration.Drop records be
|
// we do not auto-remove columns but rather require that EntityMigration.Drop records be
|
||||||
// registered by hand to avoid accidentally causin the loss of data
|
// registered by hand to avoid accidentally causin the loss of data
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user