Browse Source

add foreign key constraint annotation

add unique constraint annotation
fix small bug in build.xml for java source destination
tags/v1.2.0
bartolomiew 11 years ago
parent
commit
95d8f4bd13

+ 1
- 1
build.xml View File

@@ -78,7 +78,7 @@
<property name="library.jar" value="iciql-${iq.version}.jar" />
<property name="javadoc.jar" value="iciql-${iq.version}-javadoc.jar" />
<property name="sources.jar" value="/iciql-${iq.version}-sources.jar" />
<property name="sources.jar" value="iciql-${iq.version}-sources.jar" />
<property name="distribution.zip" value="iciql-${iq.version}.zip" />
</target>

+ 16
- 0
src/com/iciql/Define.java View File

@@ -1,6 +1,7 @@
/*
* Copyright 2004-2011 H2 Group.
* Copyright 2011 James Moger.
* Copyright 2012 Frédéric Gaillard.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,6 +45,21 @@ public class Define {
currentTableDefinition.defineIndex(name, type, columns);
}
public static void constraintUnique(String name, Object... columns) {
checkInDefine();
currentTableDefinition.defineConstraintUnique(name, columns);
}
/*
* The variable argument type Object can't be used twice :-)
*/
// public static void constraintForeignKey(String name, String refTableName,
// ConstraintDeleteType deleteType, ConstraintUpdateType updateType,
// ConstraintDeferrabilityType deferrabilityType, Object... columns, Object... refColumns) {
// checkInDefine();
// currentTableDefinition.defineForeignKey(name, columns, refTableName, Columns, deleteType, updateType, deferrabilityType);
// }
public static void primaryKey(Object... columns) {
checkInDefine();
currentTableDefinition.definePrimaryKey(columns);

+ 155
- 0
src/com/iciql/Iciql.java View File

@@ -1,6 +1,7 @@
/*
* Copyright 2004-2011 H2 Group.
* Copyright 2011 James Moger.
* Copyright 2012 Frédéric Gaillard.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -293,6 +294,160 @@ public interface Iciql {
String[] value() default {};
}
/**
* Enumeration defining the ON DELETE actions.
*/
public static enum ConstraintDeleteType {
UNSET, CASCADE, RESTRICT, SET_NULL, NO_ACTION, SET_DEFAULT;
}
/**
* Enumeration defining the ON UPDATE actions.
*/
public static enum ConstraintUpdateType {
UNSET, CASCADE, RESTRICT, SET_NULL, NO_ACTION, SET_DEFAULT;
}
/**
* Enumeration defining the deferrability.
*/
public static enum ConstraintDeferrabilityType {
UNSET, DEFERRABLE_INITIALLY_DEFERRED, DEFERRABLE_INITIALLY_IMMEDIATE, NOT_DEFERRABLE;
}
/**
* A foreign key constraint annotation.
* <p>
* <ul>
* <li>@IQContraintForeignKey(
* foreignColumns = { "idaccount"},
* referenceName = "account",
* referenceColumns = { "id" },
* deleteType = ConstrainDeleteType.CASCADE,
* updateType = ConstraintUpdateType.NO_ACTION )
* </ul>
* Note : reference columns should have a unique constraint defined in referenceName table,
* some database used to define a unique index instead of a unique constraint
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface IQContraintForeignKey {
/**
* Constraint name. If null or empty, iciql will generate one.
*/
String name() default "";
/**
* Type of the action on delete, default to unspecified.
* <ul>
* <li>com.iciql.iciql.ConstrainDeleteType.CASCADE
* <li>com.iciql.iciql.ConstrainDeleteType.RESTRICT
* <li>com.iciql.iciql.ConstrainDeleteType.SET_NULL
* <li>com.iciql.iciql.ConstrainDeleteType.NO_ACTION
* <li>com.iciql.iciql.ConstrainDeleteType.SET_DEFAULT
* </ul>
*/
ConstraintDeleteType deleteType() default ConstraintDeleteType.UNSET;
/**
* Type of the action on update, default to unspecified.
* <ul>
* <li>com.iciql.iciql.ConstrainUpdateType.CASCADE
* <li>com.iciql.iciql.ConstrainUpdateType.RESTRICT
* <li>com.iciql.iciql.ConstrainUpdateType.SET_NULL
* <li>com.iciql.iciql.ConstrainUpdateType.NO_ACTION
* <li>com.iciql.iciql.ConstrainUpdateType.SET_DEFAULT
* </ul>
*/
ConstraintUpdateType updateType() default ConstraintUpdateType.UNSET;
/**
* Type of the deferrability mode, default to unspecified
* <ul>
* <li>com.iciql.iciql.ConstrainUpdateType.CASCADE
* <li>ConstraintDeferrabilityType.DEFERRABLE_INITIALLY_DEFERRED
* <li>ConstraintDeferrabilityType.DEFERRABLE_INITIALLY_IMMEDIATE
* <li>ConstraintDeferrabilityType.NOT_DEFERRABLE
* </ul>
*/
ConstraintDeferrabilityType deferrabilityType() default ConstraintDeferrabilityType.UNSET;
/**
* The source table for the columns defined as foreign.
*/
String tableName() default "";
/**
* Columns defined as 'foreign'.
* <ul>
* <li>single column : foreignColumns = "id"
* <li>multiple column : foreignColumns = { "id", "name", "date" }
* </ul>
*/
String[] foreignColumns() default {};
/**
* The reference table for the columns defined as references.
*/
String referenceName() default "";
/**
* Columns defined as 'references'.
* <ul>
* <li>single column : referenceColumns = "id"
* <li>multiple column : referenceColumns = { "id", "name", "date" }
* </ul>
*/
String[] referenceColumns() default {};
}
/**
* Annotation to specify multiple foreign keys constraints.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface IQContraintsForeignKey {
IQContraintForeignKey[] value() default {};
}
/**
* A unique constraint annotation.
* <p>
* <ul>
* <li>@IQContraintUnique(uniqueColumns = { "street", "city" })
* <li>@IQContraintUnique(name="streetconstraint", uniqueColumns = { "street", "city" })
* </ul>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface IQContraintUnique {
/**
* Constraint name. If null or empty, iciql will generate one.
*/
String name() default "";
/**
* Columns defined as 'unique'.
* <ul>
* <li>single column : uniqueColumns = "id"
* <li>multiple column : uniqueColumns = { "id", "name", "date" }
* </ul>
*/
String[] uniqueColumns() default {};
}
/**
* Annotation to specify multiple unique constraints.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface IQContraintsUnique {
IQContraintUnique[] value() default {};
}
/**
* Annotation to define a view.
*/

+ 46
- 3
src/com/iciql/SQLDialect.java View File

@@ -1,6 +1,7 @@
/*
* Copyright 2004-2011 H2 Group.
* Copyright 2011 James Moger.
* Copyright 2012 Frédéric Gaillard.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +20,8 @@ package com.iciql;

import java.sql.DatabaseMetaData;

import com.iciql.TableDefinition.ConstraintForeignKeyDefinition;
import com.iciql.TableDefinition.ConstraintUniqueDefinition;
import com.iciql.TableDefinition.IndexDefinition;

/**
@@ -84,7 +87,9 @@ public interface SQLDialect {
* Get the CREATE VIEW statement.
*
* @param stat
* return the SQL statement
* @param def
* table definition
*/
<T> void prepareCreateView(SQLStatement stat, TableDefinition<T> def);

@@ -92,7 +97,9 @@ public interface SQLDialect {
* Get the CREATE VIEW statement.
*
* @param stat
* return the SQL statement
* @param def
* table definition
* @param fromWhere
*/
<T> void prepareCreateView(SQLStatement stat, TableDefinition<T> def, String fromWhere);
@@ -101,32 +108,68 @@ public interface SQLDialect {
* Get the DROP VIEW statement.
*
* @param stat
* return the SQL statement
* @param def
* table definition
*/
<T> void prepareDropView(SQLStatement stat, TableDefinition<T> def);
/**
* Get the CREATE INDEX statement.
*
* @param stat
* return the SQL statement
* @param schemaName
* the schema name
* @param tableName
* the table name
* @param index
* the index definition
* @return the SQL statement
*/
void prepareCreateIndex(SQLStatement stat, String schemaName, String tableName, IndexDefinition index);

/**
* Get the ALTER statement.
*
* @param stat
* return the SQL statement
* @param schemaName
* the schema name
* @param tableName
* the table name
* @param constraint
* the constraint definition
*/
void prepareCreateConstraintForeignKey(SQLStatement stat, String schemaName, String tableName, ConstraintForeignKeyDefinition constraint);

/**
* Get the ALTER statement.
*
* @param stat
* return the SQL statement
* @param schemaName
* the schema name
* @param tableName
* the table name
* @param constraint
* the constraint definition
* return the SQL statement
*/
void prepareCreateConstraintUnique(SQLStatement stat, String schemaName, String tableName, ConstraintUniqueDefinition constraint);

/**
* Get a MERGE or REPLACE INTO statement.
*
* @param stat
* return the SQL statement
* @param schemaName
* the schema name
* @param tableName
* the table name
* @param index
* the index definition
* @param def
* the table definition
* @param obj
* values
*/
<T> void prepareMerge(SQLStatement stat, String schemaName, String tableName, TableDefinition<T> def,
Object obj);

+ 105
- 0
src/com/iciql/SQLDialectDefault.java View File

@@ -1,6 +1,7 @@
/*
* Copyright 2004-2011 H2 Group.
* Copyright 2011 James Moger.
* Copyright 2012 Frédéric Gaillard.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +23,10 @@ import java.sql.SQLException;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import com.iciql.Iciql.ConstraintDeleteType;
import com.iciql.Iciql.ConstraintUpdateType;
import com.iciql.TableDefinition.ConstraintForeignKeyDefinition;
import com.iciql.TableDefinition.ConstraintUniqueDefinition;
import com.iciql.TableDefinition.FieldDefinition;
import com.iciql.TableDefinition.IndexDefinition;
import com.iciql.util.IciqlLogger;
@@ -257,6 +262,8 @@ public class SQLDialectDefault implements SQLDialect {
buff.append("INDEX ");
buff.append(index.indexName);
buff.append(" ON ");
// FIXME maybe we can use schemaName ?
// buff.append(prepareTableName(schemaName, tableName));
buff.append(tableName);
buff.append("(");
for (String col : index.columnNames) {
@@ -337,4 +344,102 @@ public class SQLDialectDefault implements SQLDialect {
}
return o.toString();
}
@SuppressWarnings("incomplete-switch")
@Override
public void prepareCreateConstraintForeignKey(SQLStatement stat, String schemaName, String tableName, ConstraintForeignKeyDefinition constraint) {
StatementBuilder buff = new StatementBuilder();
buff.append("ALTER TABLE ");
buff.append(prepareTableName(schemaName, tableName));
buff.append(" ADD CONSTRAINT ");
buff.append(constraint.constraintName);
buff.append(" FOREIGN KEY ");
buff.append(" (");
for (String col : constraint.foreignColumns) {
buff.appendExceptFirst(", ");
buff.append(prepareColumnName(col));
}
buff.append(") ");
buff.append(" REFERENCES ");
buff.append(constraint.referenceTable);
buff.append(" (");
buff.resetCount();
for (String col : constraint.referenceColumns) {
buff.appendExceptFirst(", ");
buff.append(prepareColumnName(col));
}
buff.append(") ");
if (constraint.deleteType != ConstraintDeleteType.UNSET) {
buff.append(" ON DELETE ");
switch (constraint.deleteType) {
case CASCADE:
buff.append("CASCADE ");
break;
case RESTRICT:
buff.append("RESTRICT ");
break;
case SET_NULL:
buff.append("SET NULL ");
break;
case NO_ACTION:
buff.append("NO ACTION ");
break;
case SET_DEFAULT:
buff.append("SET DEFAULT ");
break;
}
}
if (constraint.updateType != ConstraintUpdateType.UNSET) {
buff.append(" ON UPDATE ");
switch (constraint.updateType) {
case CASCADE:
buff.append("CASCADE ");
break;
case RESTRICT:
buff.append("RESTRICT ");
break;
case SET_NULL:
buff.append("SET NULL ");
break;
case NO_ACTION:
buff.append("NO ACTION ");
break;
case SET_DEFAULT:
buff.append("SET DEFAULT ");
break;
}
}
switch (constraint.deferrabilityType) {
case DEFERRABLE_INITIALLY_DEFERRED:
buff.append("DEFERRABLE INITIALLY DEFERRED ");
break;
case DEFERRABLE_INITIALLY_IMMEDIATE:
buff.append("DEFERRABLE INITIALLY IMMEDIATE ");
break;
case NOT_DEFERRABLE:
buff.append("NOT DEFERRABLE ");
break;
case UNSET:
break;
}
stat.setSQL(buff.toString().trim());
}
@Override
public void prepareCreateConstraintUnique(SQLStatement stat, String schemaName, String tableName, ConstraintUniqueDefinition constraint) {
StatementBuilder buff = new StatementBuilder();
buff.append("ALTER TABLE ");
buff.append(prepareTableName(schemaName, tableName));
buff.append(" ADD CONSTRAINT ");
buff.append(constraint.constraintName);
buff.append(" UNIQUE ");
buff.append(" (");
for (String col : constraint.uniqueColumns) {
buff.appendExceptFirst(", ");
buff.append(prepareColumnName(col));
}
buff.append(") ");
stat.setSQL(buff.toString().trim());
}
}

+ 241
- 0
src/com/iciql/TableDefinition.java View File

@@ -1,6 +1,7 @@
/*
* Copyright 2004-2011 H2 Group.
* Copyright 2011 James Moger.
* Copyright 2012 Frédéric Gaillard.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,11 +30,18 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import com.iciql.Iciql.ConstraintDeferrabilityType;
import com.iciql.Iciql.ConstraintDeleteType;
import com.iciql.Iciql.ConstraintUpdateType;
import com.iciql.Iciql.EnumId;
import com.iciql.Iciql.EnumType;
import com.iciql.Iciql.IQColumn;
import com.iciql.Iciql.IQConstraint;
import com.iciql.Iciql.IQContraintUnique;
import com.iciql.Iciql.IQContraintsUnique;
import com.iciql.Iciql.IQEnum;
import com.iciql.Iciql.IQContraintForeignKey;
import com.iciql.Iciql.IQContraintsForeignKey;
import com.iciql.Iciql.IQIgnore;
import com.iciql.Iciql.IQIndex;
import com.iciql.Iciql.IQIndexes;
@@ -68,6 +76,32 @@ public class TableDefinition<T> {
public List<String> columnNames;
}
/**
* The meta data of a constraint on foreign key.
*/
public static class ConstraintForeignKeyDefinition {
public String constraintName;
public List<String> foreignColumns;
public String referenceTable;
public List<String> referenceColumns;
public ConstraintDeleteType deleteType = ConstraintDeleteType.UNSET;
public ConstraintUpdateType updateType = ConstraintUpdateType.UNSET;
public ConstraintDeferrabilityType deferrabilityType = ConstraintDeferrabilityType.UNSET;
}
/**
* The meta data of a unique constraint.
*/
public static class ConstraintUniqueDefinition {
public String constraintName;
public List<String> uniqueColumns;
}
/**
* The meta data of a field.
*/
@@ -155,6 +189,8 @@ public class TableDefinition<T> {
private Class<T> clazz;
private IdentityHashMap<Object, FieldDefinition> fieldMap = Utils.newIdentityHashMap();
private ArrayList<IndexDefinition> indexes = Utils.newArrayList();
private ArrayList<ConstraintForeignKeyDefinition> constraintsForeignKey = Utils.newArrayList();
private ArrayList<ConstraintUniqueDefinition> constraintsUnique = Utils.newArrayList();
TableDefinition(Class<T> clazz) {
this.clazz = clazz;
@@ -267,6 +303,77 @@ public class TableDefinition<T> {
indexes.add(index);
}
/**
* Defines an unique constraint with the specified model fields.
*
* @param name
* the constraint name (optional)
* @param modelFields
* the ordered list of model fields
*/
void defineConstraintUnique(String name, Object[] modelFields) {
List<String> columnNames = mapColumnNames(modelFields);
addConstraintUnique(name, columnNames);
}
/**
* Defines an unique constraint.
*
* @param name
* @param columnNames
*/
private void addConstraintUnique(String name, List<String> columnNames) {
ConstraintUniqueDefinition constraint = new ConstraintUniqueDefinition();
if (StringUtils.isNullOrEmpty(name)) {
constraint.constraintName = tableName + "_" + constraintsUnique.size();
} else {
constraint.constraintName = name;
}
constraint.uniqueColumns = Utils.newArrayList(columnNames);
constraintsUnique.add(constraint);
}
/**
* Defines a foreign key constraint with the specified model fields.
*
* @param name
* the constraint name (optional)
* @param modelFields
* the ordered list of model fields
*/
void defineForeignKey(String name, Object[] modelFields, String refTableName, Object[] refModelFields,
ConstraintDeleteType deleteType, ConstraintUpdateType updateType,
ConstraintDeferrabilityType deferrabilityType) {
List<String> columnNames = mapColumnNames(modelFields);
List<String> referenceColumnNames = mapColumnNames(refModelFields);
addForeignKey(name, columnNames, refTableName, referenceColumnNames,
deleteType, updateType, deferrabilityType);
}
/**
* Defines a foreign key constraint.
*
* @param name
* @param columnNames
*/
private void addForeignKey(String name, List<String> columnNames, String referenceTableName,
List<String> referenceColumnNames, ConstraintDeleteType deleteType,
ConstraintUpdateType updateType, ConstraintDeferrabilityType deferrabilityType) {
ConstraintForeignKeyDefinition constraint = new ConstraintForeignKeyDefinition();
if (StringUtils.isNullOrEmpty(name)) {
constraint.constraintName = tableName + "_" + constraintsUnique.size();
} else {
constraint.constraintName = name;
}
constraint.foreignColumns = Utils.newArrayList(columnNames);
constraint.referenceTable = referenceTableName;
constraint.referenceColumns = Utils.newArrayList(referenceColumnNames);
constraint.deleteType = deleteType;
constraint.updateType = updateType;
constraint.deferrabilityType = deferrabilityType;
constraintsForeignKey.add(constraint);
}
void defineColumnName(Object column, String columnName) {
FieldDefinition def = fieldMap.get(column);
if (def != null) {
@@ -795,6 +902,36 @@ public class TableDefinition<T> {
}
}
// create unique constraints
for (ConstraintUniqueDefinition constraint : constraintsUnique) {
stat = new SQLStatement(db);
db.getDialect().prepareCreateConstraintUnique(stat, schemaName, tableName, constraint);
IciqlLogger.create(stat.getSQL());
try {
stat.executeUpdate();
} catch (IciqlException e) {
// maybe we should check more error codes
if (e.getIciqlCode() != IciqlException.CODE_OBJECT_ALREADY_EXISTS) {
throw e;
}
}
}
// create foreign keys constraints
for (ConstraintForeignKeyDefinition constraint : constraintsForeignKey) {
stat = new SQLStatement(db);
db.getDialect().prepareCreateConstraintForeignKey(stat, schemaName, tableName, constraint);
IciqlLogger.create(stat.getSQL());
try {
stat.executeUpdate();
} catch (IciqlException e) {
// maybe we should check more error codes
if (e.getIciqlCode() != IciqlException.CODE_OBJECT_ALREADY_EXISTS) {
throw e;
}
}
}
// tables are created using IF NOT EXISTS
// but we may still need to upgrade
db.upgradeTable(this);
@@ -911,6 +1048,102 @@ public class TableDefinition<T> {
addIndex(index);
}
}
if (clazz.isAnnotationPresent(IQContraintUnique.class)) {
// single table unique constraint
IQContraintUnique constraint = clazz.getAnnotation(IQContraintUnique.class);
addConstraintUnique(constraint);
}
if (clazz.isAnnotationPresent(IQContraintsUnique.class)) {
// multiple table unique constraints
IQContraintsUnique constraints = clazz.getAnnotation(IQContraintsUnique.class);
for (IQContraintUnique constraint : constraints.value()) {
addConstraintUnique(constraint);
}
}
if (clazz.isAnnotationPresent(IQContraintForeignKey.class)) {
// single table constraint
IQContraintForeignKey constraint = clazz.getAnnotation(IQContraintForeignKey.class);
addConstraintForeignKey(constraint);
}
if (clazz.isAnnotationPresent(IQContraintsForeignKey.class)) {
// multiple table constraints
IQContraintsForeignKey constraints = clazz.getAnnotation(IQContraintsForeignKey.class);
for (IQContraintForeignKey constraint : constraints.value()) {
addConstraintForeignKey(constraint);
}
}
}
private void addConstraintForeignKey(IQContraintForeignKey constraint) {
List<String> foreignColumns = Arrays.asList(constraint.foreignColumns());
List<String> referenceColumns = Arrays.asList(constraint.referenceColumns());
addContraintForeignKey(constraint.name(), foreignColumns, constraint.referenceName(), referenceColumns, constraint.deleteType(), constraint.updateType(), constraint.deferrabilityType());
}
private void addConstraintUnique(IQContraintUnique constraint) {
List<String> uniqueColumns = Arrays.asList(constraint.uniqueColumns());
addContraintUnique(constraint.name(), uniqueColumns);
}
/**
* Defines a foreign key constraint with the specified parameters.
*
* @param name
* name of the constraint
* @param foreignColumns
* list of columns declared as foreign
* @param referenceName
* reference table name
* @param referenceColumns
* list of columns used in reference table
* @param deleteType
* action on delete
* @param updateType
* action on update
* @param deferrabilityType
* deferrability mode
*/
private void addContraintForeignKey(String name,
List<String> foreignColumns, String referenceName,
List<String> referenceColumns, ConstraintDeleteType deleteType,
ConstraintUpdateType updateType, ConstraintDeferrabilityType deferrabilityType) {
ConstraintForeignKeyDefinition constraint = new ConstraintForeignKeyDefinition();
if (StringUtils.isNullOrEmpty(name)) {
constraint.constraintName = tableName + "_" + constraintsForeignKey.size();
} else {
constraint.constraintName = name;
}
constraint.foreignColumns = Utils.newArrayList(foreignColumns);
constraint.referenceColumns = Utils.newArrayList(referenceColumns);
constraint.referenceTable = referenceName;
constraint.deleteType = deleteType;
constraint.updateType = updateType;
constraint.deferrabilityType = deferrabilityType;
constraintsForeignKey.add(constraint);
}
/**
* Defines a unique constraint with the specified parameters.
*
* @param name
* name of the constraint
* @param uniqueColumns
* list of columns declared as unique
*/
private void addContraintUnique(String name, List<String> uniqueColumns) {
ConstraintUniqueDefinition constraint = new ConstraintUniqueDefinition();
if (StringUtils.isNullOrEmpty(name)) {
constraint.constraintName = tableName + "_" + constraintsUnique.size();
} else {
constraint.constraintName = name;
}
constraint.uniqueColumns = Utils.newArrayList(uniqueColumns);
constraintsUnique.add(constraint);
}
private void addIndex(IQIndex index) {
@@ -922,6 +1155,14 @@ public class TableDefinition<T> {
return indexes;
}
List<ConstraintUniqueDefinition> getContraintsUnique() {
return constraintsUnique;
}
List<ConstraintForeignKeyDefinition> getContraintsForeignKey() {
return constraintsForeignKey;
}
private void initObject(Object obj, Map<Object, FieldDefinition> map) {
for (FieldDefinition def : fields) {
Object newValue = def.initWithNewObject(obj);

+ 7
- 0
src/com/iciql/TableInspector.java View File

@@ -1,6 +1,7 @@
/*
* Copyright 2004-2011 H2 Group.
* Copyright 2011 James Moger.
* Copyright 2012 Frédéric Gaillard.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,6 +43,8 @@ import com.iciql.Iciql.IQIndexes;
import com.iciql.Iciql.IQSchema;
import com.iciql.Iciql.IQTable;
import com.iciql.Iciql.IndexType;
import com.iciql.TableDefinition.ConstraintForeignKeyDefinition;
import com.iciql.TableDefinition.ConstraintUniqueDefinition;
import com.iciql.TableDefinition.FieldDefinition;
import com.iciql.TableDefinition.IndexDefinition;
import com.iciql.util.StatementBuilder;
@@ -470,6 +473,10 @@ public class TableInspector {
}
// TODO complete index validation.
// need to actually compare index types and columns within each index.
// TODO add constraints validation
List<ConstraintUniqueDefinition> defContraintsU = def.getContraintsUnique();
List<ConstraintForeignKeyDefinition> defContraintsFK = def.getContraintsForeignKey();
}

/**

+ 64
- 0
tests/com/iciql/test/ForeignKeyTest.java View File

@@ -0,0 +1,64 @@
/*
* Copyright 2012 Frédéric Gaillard.
*
* 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 com.iciql.test;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.iciql.Db;
import com.iciql.test.models.CategoryAnnotationOnly;
import com.iciql.test.models.ProductAnnotationOnlyWithForeignKey;
public class ForeignKeyTest {
/**
* This object represents a database (actually a connection to the
* database).
*/
private Db db;
@Before
public void setUp() {
db = IciqlSuite.openNewDb();
db.insertAll(CategoryAnnotationOnly.getList());
db.insertAll(ProductAnnotationOnlyWithForeignKey.getList());
}
@After
public void tearDown() {
db.close();
}
@Test
public void testForeignKeyWithOnDeleteCascade() {
ProductAnnotationOnlyWithForeignKey p = new ProductAnnotationOnlyWithForeignKey();
long count1 = db.from(p).selectCount();
// should remove 2 associated products
CategoryAnnotationOnly c = new CategoryAnnotationOnly();
db.from(c).where(c.categoryId).is(1L).delete();
long count2 = db.from(p).selectCount();
assertEquals(count1, count2 + 2L);
}
}

+ 2
- 1
tests/com/iciql/test/IciqlSuite.java View File

@@ -1,5 +1,6 @@
/*
* Copyright 2011 James Moger.
* Copyright 2012 Frédéric Gaillard.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -89,7 +90,7 @@ import com.iciql.util.Utils;
@SuiteClasses({ AliasMapTest.class, AnnotationsTest.class, BooleanModelTest.class, ClobTest.class,
ConcurrencyTest.class, EnumsTest.class, ModelsTest.class, PrimitivesTest.class,
RuntimeQueryTest.class, SamplesTest.class, UpdateTest.class, UpgradesTest.class, JoinTest.class,
UUIDTest.class, ViewsTest.class })
UUIDTest.class, ViewsTest.class, ForeignKeyTest.class })
public class IciqlSuite {
private static final TestDb[] TEST_DBS = {

+ 69
- 0
tests/com/iciql/test/models/CategoryAnnotationOnly.java View File

@@ -0,0 +1,69 @@
/*
* Copyright 2012 Frédéric Gaillard.
*
* 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 com.iciql.test.models;

import java.util.Arrays;
import java.util.List;

import com.iciql.Iciql.IQColumn;
import com.iciql.Iciql.IQContraintUnique;
import com.iciql.Iciql.IQTable;

/**
* A table containing category data.
*/

@IQTable(name = "AnnotatedCatagory", primaryKey = "id")
// @IQIndex(value = "categ", type=IndexType.UNIQUE)
@IQContraintUnique(uniqueColumns = { "categ" })
public class CategoryAnnotationOnly {

@IQColumn(name = "id", autoIncrement = true)
public Long categoryId;

@IQColumn(name = "categ", length = 15, trim = true)
public String category;

public CategoryAnnotationOnly() {
// public constructor
}

private CategoryAnnotationOnly(long categoryId, String category) {
this.categoryId = categoryId;
this.category = category;
}

private static CategoryAnnotationOnly create(int categoryId, String category) {
return new CategoryAnnotationOnly(categoryId, category);
}

public static List<CategoryAnnotationOnly> getList() {
CategoryAnnotationOnly[] list = {
create(1, "Beverages"),
create(2, "Condiments"),
create(3, "Produce"),
create(4, "Meat/Poultry"),
create(5,"Seafood")
};
return Arrays.asList(list);
}

public String toString() {
return category;
}

}

+ 103
- 0
tests/com/iciql/test/models/ProductAnnotationOnlyWithForeignKey.java View File

@@ -0,0 +1,103 @@
/*
* Copyright 2004-2011 H2 Group.
* Copyright 2011 James Moger.
* Copyright 2012 Frédéric Gaillard.
*
* 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 com.iciql.test.models;

import java.util.Arrays;
import java.util.List;

import com.iciql.Iciql.ConstraintDeleteType;
import com.iciql.Iciql.IQColumn;
import com.iciql.Iciql.IQContraintForeignKey;
import com.iciql.Iciql.IQIndex;
import com.iciql.Iciql.IQIndexes;
import com.iciql.Iciql.IQTable;
import com.iciql.Iciql.IndexType;

/**
* A table containing product data.
*/

@IQTable(name = "AnnotatedProduct", primaryKey = "id")
@IQIndexes({ @IQIndex({ "name", "cat" }), @IQIndex(name = "nameidx", type = IndexType.HASH, value = "name") })
@IQContraintForeignKey(
foreignColumns= { "cat" },
referenceName = "AnnotatedCatagory",
referenceColumns = { "categ" },
deleteType = ConstraintDeleteType.CASCADE
)
public class ProductAnnotationOnlyWithForeignKey {

public String unmappedField;

@IQColumn(name = "id", autoIncrement = true)
public Long productId;

@IQColumn(name = "cat", length = 15, trim = true)
public String category;

@IQColumn(name = "name", length = 50)
public String productName;

@SuppressWarnings("unused")
@IQColumn
private Double unitPrice;

@IQColumn
private Integer unitsInStock;

public ProductAnnotationOnlyWithForeignKey() {
// public constructor
}

private ProductAnnotationOnlyWithForeignKey(long productId, String productName, String category, double unitPrice,
int unitsInStock, String unmappedField) {
this.productId = productId;
this.productName = productName;
this.category = category;
this.unitPrice = unitPrice;
this.unitsInStock = unitsInStock;
this.unmappedField = unmappedField;
}

private static ProductAnnotationOnlyWithForeignKey create(int productId, String productName, String category,
double unitPrice, int unitsInStock, String unmappedField) {
return new ProductAnnotationOnlyWithForeignKey(productId, productName, category, unitPrice, unitsInStock,
unmappedField);
}

public static List<ProductAnnotationOnlyWithForeignKey> getList() {
String unmappedField = "unmapped";
ProductAnnotationOnlyWithForeignKey[] list = { create(1, "Chai", "Beverages", 18, 39, unmappedField),
create(2, "Chang", "Beverages", 19.0, 17, unmappedField),
create(3, "Aniseed Syrup", "Condiments", 10.0, 13, unmappedField),
create(4, "Chef Anton's Cajun Seasoning", "Condiments", 22.0, 53, unmappedField),
create(5, "Chef Anton's Gumbo Mix", "Condiments", 21.3500, 0, unmappedField),
create(6, "Grandma's Boysenberry Spread", "Condiments", 25.0, 120, unmappedField),
create(7, "Uncle Bob's Organic Dried Pears", "Produce", 30.0, 15, unmappedField),
create(8, "Northwoods Cranberry Sauce", "Condiments", 40.0, 6, unmappedField),
create(9, "Mishi Kobe Niku", "Meat/Poultry", 97.0, 29, unmappedField),
create(10, "Ikura", "Seafood", 31.0, 31, unmappedField), };
return Arrays.asList(list);
}

public String toString() {
return productName + ": " + unitsInStock;
}

}

Loading…
Cancel
Save