aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJames Moger <james.moger@gmail.com>2012-09-25 18:05:13 -0400
committerJames Moger <james.moger@gmail.com>2012-09-25 18:05:13 -0400
commitc42ebc94e34b3a1aa27c292188e73f5b06af814a (patch)
tree5dbb4e5e261e13a0563e64a995042f1d7cd2479e /src
parentb4d82730f640969ed92de915134ef28821d225ed (diff)
downloadiciql-c42ebc94e34b3a1aa27c292188e73f5b06af814a.tar.gz
iciql-c42ebc94e34b3a1aa27c292188e73f5b06af814a.zip
Support for read-only views (issue 8)
Diffstat (limited to 'src')
-rw-r--r--src/com/iciql/Db.java27
-rw-r--r--src/com/iciql/Define.java12
-rw-r--r--src/com/iciql/Iciql.java61
-rw-r--r--src/com/iciql/IciqlException.java3
-rw-r--r--src/com/iciql/Query.java27
-rw-r--r--src/com/iciql/QueryWhere.java8
-rw-r--r--src/com/iciql/SQLDialect.java26
-rw-r--r--src/com/iciql/SQLDialectDefault.java51
-rw-r--r--src/com/iciql/SQLDialectH2.java13
-rw-r--r--src/com/iciql/SQLDialectHSQL.java8
-rw-r--r--src/com/iciql/SQLDialectMySQL.java9
-rw-r--r--src/com/iciql/SQLStatement.java12
-rw-r--r--src/com/iciql/TableDefinition.java125
13 files changed, 377 insertions, 5 deletions
diff --git a/src/com/iciql/Db.java b/src/com/iciql/Db.java
index 90e7613..caec637 100644
--- a/src/com/iciql/Db.java
+++ b/src/com/iciql/Db.java
@@ -38,6 +38,7 @@ import javax.sql.DataSource;
import com.iciql.DbUpgrader.DefaultDbUpgrader;
import com.iciql.Iciql.IQTable;
import com.iciql.Iciql.IQVersion;
+import com.iciql.Iciql.IQView;
import com.iciql.util.IciqlLogger;
import com.iciql.util.JdbcUtils;
import com.iciql.util.StringUtils;
@@ -284,6 +285,27 @@ public class Db {
return rc;
}
+ @SuppressWarnings("unchecked")
+ public <T> int dropView(Class<? extends T> modelClass) {
+ TableDefinition<T> def = (TableDefinition<T>) define(modelClass);
+ SQLStatement stat = new SQLStatement(this);
+ getDialect().prepareDropView(stat, def);
+ IciqlLogger.drop(stat.getSQL());
+ int rc = 0;
+ try {
+ rc = stat.executeUpdate();
+ } catch (IciqlException e) {
+ if (e.getIciqlCode() != IciqlException.CODE_OBJECT_NOT_FOUND) {
+ throw e;
+ }
+ }
+ // remove this model class from the table definition cache
+ classMap.remove(modelClass);
+ // remove this model class from the upgrade checked cache
+ upgradeChecked.remove(modelClass);
+ return rc;
+ }
+
public <T> List<T> buildObjects(Class<? extends T> modelClass, ResultSet rs) {
return buildObjects(modelClass, false, rs);
}
@@ -400,6 +422,11 @@ public class Db {
// initializer
T t = instance(clazz);
def.mapObject(t);
+ } else if (clazz.isAnnotationPresent(IQView.class)) {
+ // annotated classes skip the Define().define() static
+ // initializer
+ T t = instance(clazz);
+ def.mapObject(t);
}
}
return def;
diff --git a/src/com/iciql/Define.java b/src/com/iciql/Define.java
index 3b58231..53f9862 100644
--- a/src/com/iciql/Define.java
+++ b/src/com/iciql/Define.java
@@ -59,6 +59,11 @@ public class Define {
currentTableDefinition.defineTableName(tableName);
}
+ public static void viewTableName(String viewTableName) {
+ checkInDefine();
+ currentTableDefinition.defineViewTableName(viewTableName);
+ }
+
public static void memoryTable() {
checkInDefine();
currentTableDefinition.defineMemoryTable();
@@ -98,7 +103,12 @@ public class Define {
checkInDefine();
currentTableDefinition.defineDefaultValue(column, defaultValue);
}
-
+
+ public static void constraint(Object column, String constraint) {
+ checkInDefine();
+ currentTableDefinition.defineConstraint(column, constraint);
+ }
+
static synchronized <T> void define(TableDefinition<T> tableDefinition, Iciql table) {
currentTableDefinition = tableDefinition;
currentTable = table;
diff --git a/src/com/iciql/Iciql.java b/src/com/iciql/Iciql.java
index eaa256a..7b3a7c1 100644
--- a/src/com/iciql/Iciql.java
+++ b/src/com/iciql/Iciql.java
@@ -294,6 +294,67 @@ public interface Iciql {
}
/**
+ * Annotation to define a view.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.TYPE)
+ public @interface IQView {
+
+ /**
+ * The view name. If not specified the class name is used as the view
+ * name.
+ * <p>
+ * The view name may still be overridden in the define() method if the
+ * model class is not annotated with IQView. Default: unspecified.
+ */
+ String name() default "";
+
+ /**
+ * The source table for the view.
+ * <p>
+ * The view name may still be overridden in the define() method if the
+ * model class is not annotated with IQView. Default: unspecified.
+ */
+ String tableName() default "";
+
+ /**
+ * The inherit columns allows this model class to inherit columns from
+ * its super class. Any IQTable annotation present on the super class is
+ * ignored. Default: false.
+ */
+ boolean inheritColumns() default false;
+
+ /**
+ * Whether or not iciql tries to create the view. Default:
+ * true.
+ */
+ boolean create() default true;
+
+ /**
+ * If true, only fields that are explicitly annotated as IQColumn are
+ * mapped. Default: true.
+ */
+ boolean annotationsOnly() default true;
+ }
+
+ /**
+ * String snippet defining SQL constraints for a field. Use "this" as
+ * a placeholder for the column name. "this" will be substituted at
+ * runtime.
+ * <p>
+ * IQConstraint("this > 2 AND this <= 7")
+ * <p>
+ * This snippet may still be overridden in the define() method if the
+ * model class is not annotated with IQTable or IQView. Default: unspecified.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.FIELD)
+ public @interface IQConstraint {
+
+ String value() default "";
+ }
+
+ /**
* Annotation to specify multiple indexes.
*/
@Retention(RetentionPolicy.RUNTIME)
diff --git a/src/com/iciql/IciqlException.java b/src/com/iciql/IciqlException.java
index 7e7021e..07fd363 100644
--- a/src/com/iciql/IciqlException.java
+++ b/src/com/iciql/IciqlException.java
@@ -121,6 +121,9 @@ public class IciqlException extends RuntimeException {
} else if ("42P01".equals(state)) {
// PostgreSQL table not found
iciqlCode = CODE_OBJECT_NOT_FOUND;
+ } else if ("X0X05".equals(state)) {
+ // Derby view/table not found exists
+ iciqlCode = CODE_OBJECT_NOT_FOUND;
} else if ("X0Y32".equals(state)) {
// Derby table already exists
iciqlCode = CODE_OBJECT_ALREADY_EXISTS;
diff --git a/src/com/iciql/Query.java b/src/com/iciql/Query.java
index 6c0ecf9..5dc78a5 100644
--- a/src/com/iciql/Query.java
+++ b/src/com/iciql/Query.java
@@ -107,6 +107,23 @@ public class Query<T> {
List<X> list = (List<X>) select(x);
return list.isEmpty() ? null : list.get(0);
}
+
+ public <X> void createView(Class<X> viewClass) {
+ TableDefinition<X> viewDef = db.define(viewClass);
+
+ SQLStatement fromWhere = new SQLStatement(db);
+ appendFromWhere(fromWhere, false);
+
+ SQLStatement stat = new SQLStatement(db);
+ db.getDialect().prepareCreateView(stat, viewDef, fromWhere.toSQL());
+ IciqlLogger.create(stat.toSQL());
+ stat.execute();
+ }
+
+ public <X> void replaceView(Class<X> viewClass) {
+ db.dropView(viewClass);
+ createView(viewClass);
+ }
public String getSQL() {
SQLStatement stat = getSelectStatement(false);
@@ -803,8 +820,12 @@ public class Query<T> {
}
}
}
-
+
void appendFromWhere(SQLStatement stat) {
+ appendFromWhere(stat, true);
+ }
+
+ void appendFromWhere(SQLStatement stat, boolean log) {
stat.appendSQL(" FROM ");
from.appendSQL(stat);
for (SelectTable<T> join : joins) {
@@ -834,7 +855,9 @@ public class Query<T> {
}
}
db.getDialect().appendLimitOffset(stat, limit, offset);
- IciqlLogger.select(stat.getSQL());
+ if (log) {
+ IciqlLogger.select(stat.getSQL());
+ }
}
/**
diff --git a/src/com/iciql/QueryWhere.java b/src/com/iciql/QueryWhere.java
index 3f1afe1..5baa5ab 100644
--- a/src/com/iciql/QueryWhere.java
+++ b/src/com/iciql/QueryWhere.java
@@ -347,6 +347,14 @@ public class QueryWhere<T> {
public List<T> selectDistinct() {
return query.selectDistinct();
}
+
+ public void createView(Class<?> viewClass) {
+ query.createView(viewClass);
+ }
+
+ public void replaceView(Class<?> viewClass) {
+ query.replaceView(viewClass);
+ }
/**
* Order by primitive boolean field
diff --git a/src/com/iciql/SQLDialect.java b/src/com/iciql/SQLDialect.java
index 28f5566..8e3e3d2 100644
--- a/src/com/iciql/SQLDialect.java
+++ b/src/com/iciql/SQLDialect.java
@@ -79,6 +79,32 @@ public interface SQLDialect {
*/
<T> void prepareDropTable(SQLStatement stat, TableDefinition<T> def);
+
+ /**
+ * Get the CREATE VIEW statement.
+ *
+ * @param stat
+ * @param def
+ */
+ <T> void prepareCreateView(SQLStatement stat, TableDefinition<T> def);
+
+ /**
+ * Get the CREATE VIEW statement.
+ *
+ * @param stat
+ * @param def
+ * @param fromWhere
+ */
+ <T> void prepareCreateView(SQLStatement stat, TableDefinition<T> def, String fromWhere);
+
+ /**
+ * Get the DROP VIEW statement.
+ *
+ * @param stat
+ * @param def
+ */
+ <T> void prepareDropView(SQLStatement stat, TableDefinition<T> def);
+
/**
* Get the CREATE INDEX statement.
*
diff --git a/src/com/iciql/SQLDialectDefault.java b/src/com/iciql/SQLDialectDefault.java
index 7cc6bd7..0cd0448 100644
--- a/src/com/iciql/SQLDialectDefault.java
+++ b/src/com/iciql/SQLDialectDefault.java
@@ -166,6 +166,57 @@ public class SQLDialectDefault implements SQLDialect {
stat.setSQL(buff.toString());
}
+ @Override
+ public <T> void prepareDropView(SQLStatement stat, TableDefinition<T> def) {
+ StatementBuilder buff = new StatementBuilder("DROP VIEW "
+ + prepareTableName(def.schemaName, def.tableName));
+ stat.setSQL(buff.toString());
+ return;
+ }
+
+ protected <T> String prepareCreateView(TableDefinition<T> def) {
+ return "CREATE VIEW";
+ }
+
+ @Override
+ public <T> void prepareCreateView(SQLStatement stat, TableDefinition<T> def) {
+ StatementBuilder buff = new StatementBuilder();
+ buff.append(" FROM ");
+ buff.append(prepareTableName(def.schemaName, def.viewTableName));
+
+ StatementBuilder where = new StatementBuilder();
+ for (FieldDefinition field : def.fields) {
+ if (!StringUtils.isNullOrEmpty(field.constraint)) {
+ where.appendExceptFirst(", ");
+ String col = prepareColumnName(field.columnName);
+ String constraint = field.constraint.replace("{0}", col).replace("this", col);
+ where.append(constraint);
+ }
+ }
+ if (where.length() > 0) {
+ buff.append(" WHERE ");
+ buff.append(where.toString());
+ }
+
+ prepareCreateView(stat, def, buff.toString());
+ }
+
+ @Override
+ public <T> void prepareCreateView(SQLStatement stat, TableDefinition<T> def, String fromWhere) {
+ StatementBuilder buff = new StatementBuilder();
+ buff.append(prepareCreateView(def));
+ buff.append(" ");
+ buff.append(prepareTableName(def.schemaName, def.tableName));
+
+ buff.append(" AS SELECT ");
+ for (FieldDefinition field : def.fields) {
+ buff.appendExceptFirst(", ");
+ buff.append(prepareColumnName(field.columnName));
+ }
+ buff.append(fromWhere);
+ stat.setSQL(buff.toString());
+ }
+
protected boolean isIntegerType(String dataType) {
if ("INT".equals(dataType)) {
return true;
diff --git a/src/com/iciql/SQLDialectH2.java b/src/com/iciql/SQLDialectH2.java
index 1da45f6..6b3bab1 100644
--- a/src/com/iciql/SQLDialectH2.java
+++ b/src/com/iciql/SQLDialectH2.java
@@ -37,6 +37,19 @@ public class SQLDialectH2 extends SQLDialectDefault {
return "CREATE CACHED TABLE IF NOT EXISTS";
}
}
+
+ @Override
+ protected <T> String prepareCreateView(TableDefinition<T> def) {
+ return "CREATE VIEW IF NOT EXISTS";
+ }
+
+ @Override
+ public <T> void prepareDropView(SQLStatement stat, TableDefinition<T> def) {
+ StatementBuilder buff = new StatementBuilder("DROP VIEW IF EXISTS "
+ + prepareTableName(def.schemaName, def.tableName));
+ stat.setSQL(buff.toString());
+ return;
+ }
@Override
protected boolean prepareColumnDefinition(StatementBuilder buff, String dataType,
diff --git a/src/com/iciql/SQLDialectHSQL.java b/src/com/iciql/SQLDialectHSQL.java
index 9975be6..82e6833 100644
--- a/src/com/iciql/SQLDialectHSQL.java
+++ b/src/com/iciql/SQLDialectHSQL.java
@@ -38,6 +38,14 @@ public class SQLDialectHSQL extends SQLDialectDefault {
return "CREATE CACHED TABLE IF NOT EXISTS";
}
}
+
+ @Override
+ public <T> void prepareDropView(SQLStatement stat, TableDefinition<T> def) {
+ StatementBuilder buff = new StatementBuilder("DROP VIEW IF EXISTS "
+ + prepareTableName(def.schemaName, def.tableName));
+ stat.setSQL(buff.toString());
+ return;
+ }
@Override
protected boolean prepareColumnDefinition(StatementBuilder buff, String dataType,
diff --git a/src/com/iciql/SQLDialectMySQL.java b/src/com/iciql/SQLDialectMySQL.java
index 7fa1fa9..52676d4 100644
--- a/src/com/iciql/SQLDialectMySQL.java
+++ b/src/com/iciql/SQLDialectMySQL.java
@@ -36,6 +36,15 @@ public class SQLDialectMySQL extends SQLDialectDefault {
protected <T> String prepareCreateTable(TableDefinition<T> def) {
return "CREATE TABLE IF NOT EXISTS";
}
+
+ @Override
+ public <T> void prepareDropView(SQLStatement stat, TableDefinition<T> def) {
+ StatementBuilder buff = new StatementBuilder("DROP VIEW IF EXISTS "
+ + prepareTableName(def.schemaName, def.tableName));
+ stat.setSQL(buff.toString());
+ return;
+ }
+
@Override
public String prepareColumnName(String name) {
return "`" + name + "`";
diff --git a/src/com/iciql/SQLStatement.java b/src/com/iciql/SQLStatement.java
index 2f97829..394fc42 100644
--- a/src/com/iciql/SQLStatement.java
+++ b/src/com/iciql/SQLStatement.java
@@ -115,6 +115,18 @@ public class SQLStatement {
params.add(o);
return this;
}
+
+ void execute() {
+ PreparedStatement ps = null;
+ try {
+ ps = prepare(false);
+ ps.execute();
+ } catch (SQLException e) {
+ throw IciqlException.fromSQL(getSQL(), e);
+ } finally {
+ JdbcUtils.closeSilently(ps);
+ }
+ }
ResultSet executeQuery() {
try {
diff --git a/src/com/iciql/TableDefinition.java b/src/com/iciql/TableDefinition.java
index f6a8c26..aa25722 100644
--- a/src/com/iciql/TableDefinition.java
+++ b/src/com/iciql/TableDefinition.java
@@ -24,12 +24,15 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IdentityHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import com.iciql.Iciql.EnumId;
import com.iciql.Iciql.EnumType;
import com.iciql.Iciql.IQColumn;
+import com.iciql.Iciql.IQConstraint;
import com.iciql.Iciql.IQEnum;
import com.iciql.Iciql.IQIgnore;
import com.iciql.Iciql.IQIndex;
@@ -37,6 +40,7 @@ import com.iciql.Iciql.IQIndexes;
import com.iciql.Iciql.IQSchema;
import com.iciql.Iciql.IQTable;
import com.iciql.Iciql.IQVersion;
+import com.iciql.Iciql.IQView;
import com.iciql.Iciql.IndexType;
import com.iciql.util.IciqlLogger;
import com.iciql.util.StatementBuilder;
@@ -81,6 +85,7 @@ public class TableDefinition<T> {
String defaultValue;
EnumType enumType;
boolean isPrimitive;
+ String constraint;
Object getValue(Object obj) {
try {
@@ -140,6 +145,7 @@ public class TableDefinition<T> {
public ArrayList<FieldDefinition> fields = Utils.newArrayList();
String schemaName;
String tableName;
+ String viewTableName;
int tableVersion;
List<String> primaryKeyColumnNames;
boolean memoryTable;
@@ -172,6 +178,10 @@ public class TableDefinition<T> {
this.tableName = tableName;
}
+ void defineViewTableName(String viewTableName) {
+ this.viewTableName = viewTableName;
+ }
+
void defineMemoryTable() {
this.memoryTable = true;
}
@@ -302,6 +312,13 @@ public class TableDefinition<T> {
}
}
+ void defineConstraint(Object column, String constraint) {
+ FieldDefinition def = fieldMap.get(column);
+ if (def != null) {
+ def.constraint = constraint;
+ }
+ }
+
void mapFields() {
boolean byAnnotationsOnly = false;
boolean inheritColumns = false;
@@ -311,11 +328,33 @@ public class TableDefinition<T> {
inheritColumns = tableAnnotation.inheritColumns();
}
+ if (clazz.isAnnotationPresent(IQView.class)) {
+ IQView viewAnnotation = clazz.getAnnotation(IQView.class);
+ byAnnotationsOnly = viewAnnotation.annotationsOnly();
+ inheritColumns = viewAnnotation.inheritColumns();
+ }
+
List<Field> classFields = Utils.newArrayList();
classFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
if (inheritColumns) {
Class<?> superClass = clazz.getSuperclass();
classFields.addAll(Arrays.asList(superClass.getDeclaredFields()));
+
+ if (superClass.isAnnotationPresent(IQView.class)) {
+ IQView superView = superClass.getAnnotation(IQView.class);
+ if (superView.inheritColumns()) {
+ // inherit columns from super.super.class
+ Class<?> superSuperClass = superClass.getSuperclass();
+ classFields.addAll(Arrays.asList(superSuperClass.getDeclaredFields()));
+ }
+ } else if (superClass.isAnnotationPresent(IQTable.class)) {
+ IQTable superTable = superClass.getAnnotation(IQTable.class);
+ if (superTable.inheritColumns()) {
+ // inherit columns from super.super.class
+ Class<?> superSuperClass = superClass.getSuperclass();
+ classFields.addAll(Arrays.asList(superSuperClass.getDeclaredFields()));
+ }
+ }
}
Set<FieldDefinition> uniqueFields = new LinkedHashSet<FieldDefinition>();
@@ -336,6 +375,7 @@ public class TableDefinition<T> {
boolean nullable = !f.getType().isPrimitive();
EnumType enumType = null;
String defaultValue = "";
+ String constraint = "";
// configure Java -> SQL enum mapping
if (f.getType().isEnum()) {
enumType = EnumType.DEFAULT_TYPE;
@@ -388,9 +428,18 @@ public class TableDefinition<T> {
defaultValue = col.defaultValue();
}
}
+
+ boolean hasConstraint = f.isAnnotationPresent(IQConstraint.class);
+ if (hasConstraint) {
+ IQConstraint con = f.getAnnotation(IQConstraint.class);
+ // annotation overrides
+ if (!StringUtils.isNullOrEmpty(con.value())) {
+ constraint = con.value();
+ }
+ }
boolean reflectiveMatch = !byAnnotationsOnly;
- if (reflectiveMatch || hasAnnotation) {
+ if (reflectiveMatch || hasAnnotation || hasConstraint) {
FieldDefinition fieldDef = new FieldDefinition();
fieldDef.isPrimitive = f.getType().isPrimitive();
fieldDef.field = f;
@@ -404,6 +453,7 @@ public class TableDefinition<T> {
fieldDef.defaultValue = defaultValue;
fieldDef.enumType = enumType;
fieldDef.dataType = ModelUtils.getDataType(fieldDef);
+ fieldDef.constraint = constraint;
uniqueFields.add(fieldDef);
}
}
@@ -540,6 +590,9 @@ public class TableDefinition<T> {
}
long insert(Db db, Object obj, boolean returnKey) {
+ if (!StringUtils.isNullOrEmpty(viewTableName)) {
+ throw new IciqlException("Iciql does not support inserting rows into views!");
+ }
SQLStatement stat = new SQLStatement(db);
StatementBuilder buff = new StatementBuilder("INSERT INTO ");
buff.append(db.getDialect().prepareTableName(schemaName, tableName)).append('(');
@@ -615,6 +668,9 @@ public class TableDefinition<T> {
}
int update(Db db, Object obj) {
+ if (!StringUtils.isNullOrEmpty(viewTableName)) {
+ throw new IciqlException("Iciql does not support updating rows in views!");
+ }
if (primaryKeyColumnNames == null || primaryKeyColumnNames.size() == 0) {
throw new IllegalStateException("No primary key columns defined for table " + obj.getClass()
+ " - no update possible");
@@ -661,6 +717,9 @@ public class TableDefinition<T> {
}
int delete(Db db, Object obj) {
+ if (!StringUtils.isNullOrEmpty(viewTableName)) {
+ throw new IciqlException("Iciql does not support deleting rows from views!");
+ }
if (primaryKeyColumnNames == null || primaryKeyColumnNames.size() == 0) {
throw new IllegalStateException("No primary key columns defined for table " + obj.getClass()
+ " - no update possible");
@@ -703,7 +762,11 @@ public class TableDefinition<T> {
return this;
}
SQLStatement stat = new SQLStatement(db);
- db.getDialect().prepareCreateTable(stat, this);
+ if (StringUtils.isNullOrEmpty(viewTableName)) {
+ db.getDialect().prepareCreateTable(stat, this);
+ } else {
+ db.getDialect().prepareCreateView(stat, this);
+ }
IciqlLogger.create(stat.getSQL());
try {
stat.executeUpdate();
@@ -773,6 +836,64 @@ public class TableDefinition<T> {
}
}
+ if (clazz.isAnnotationPresent(IQView.class)) {
+ IQView viewAnnotation = clazz.getAnnotation(IQView.class);
+
+ // setup view name mapping, if properly annotated
+ // set this as the table name so it fits in seemlessly with iciql
+ if (!StringUtils.isNullOrEmpty(viewAnnotation.name())) {
+ tableName = viewAnnotation.name();
+ } else {
+ tableName = clazz.getSimpleName();
+ }
+
+ // setup source table name mapping, if properly annotated
+ if (!StringUtils.isNullOrEmpty(viewAnnotation.tableName())) {
+ viewTableName = viewAnnotation.tableName();
+ } else {
+ // check for IQTable annotation on super class
+ Class<?> superClass = clazz.getSuperclass();
+ if (superClass.isAnnotationPresent(IQTable.class)) {
+ IQTable table = superClass.getAnnotation(IQTable.class);
+ if (StringUtils.isNullOrEmpty(table.name())) {
+ // super.SimpleClassName
+ viewTableName = superClass.getSimpleName();
+ } else {
+ // super.IQTable.name()
+ viewTableName = table.name();
+ }
+ } else if (superClass.isAnnotationPresent(IQView.class)) {
+ // super class is a view
+ IQView parentView = superClass.getAnnotation(IQView.class);
+ if (StringUtils.isNullOrEmpty(parentView.tableName())) {
+ // parent view does not define a tableName, must be inherited
+ Class<?> superParent = superClass.getSuperclass();
+ if (superParent != null && superParent.isAnnotationPresent(IQTable.class)) {
+ IQTable superParentTable = superParent.getAnnotation(IQTable.class);
+ if (StringUtils.isNullOrEmpty(superParentTable.name())) {
+ // super.super.SimpleClassName
+ viewTableName = superParent.getSimpleName();
+ } else {
+ // super.super.IQTable.name()
+ viewTableName = superParentTable.name();
+ }
+ }
+ } else {
+ // super.IQView.tableName()
+ viewTableName = parentView.tableName();
+ }
+ }
+
+ if (StringUtils.isNullOrEmpty(viewTableName)) {
+ // still missing view table name
+ throw new IciqlException("View model class \"{0}\" is missing a table name!", tableName);
+ }
+ }
+
+ // allow control over createTableIfRequired()
+ createIfRequired = viewAnnotation.create();
+ }
+
if (clazz.isAnnotationPresent(IQIndex.class)) {
// single table index
IQIndex index = clazz.getAnnotation(IQIndex.class);