aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJames Moger <james.moger@gmail.com>2011-12-09 16:42:59 -0500
committerJames Moger <james.moger@gmail.com>2011-12-09 16:42:59 -0500
commit876c4e51578dfa7bd98956d2f07ae7498a70629c (patch)
treee23df1f9a29cb027c55a95e50f019e7f6d717d08 /src
parent407ea16f9f8f6d3bd5135783d98b63c0e4704609 (diff)
downloadiciql-876c4e51578dfa7bd98956d2f07ae7498a70629c.tar.gz
iciql-876c4e51578dfa7bd98956d2f07ae7498a70629c.zip
Columns mapped by name in result set instead of index. Disallow multiple
primitive bools in a model WITH explicit referencing.
Diffstat (limited to 'src')
-rw-r--r--src/com/iciql/Db.java17
-rw-r--r--src/com/iciql/Iciql.java11
-rw-r--r--src/com/iciql/Query.java18
-rw-r--r--src/com/iciql/QueryJoin.java3
-rw-r--r--src/com/iciql/QueryWhere.java5
-rw-r--r--src/com/iciql/TableDefinition.java68
6 files changed, 114 insertions, 8 deletions
diff --git a/src/com/iciql/Db.java b/src/com/iciql/Db.java
index e05ec56..4dc0b5e 100644
--- a/src/com/iciql/Db.java
+++ b/src/com/iciql/Db.java
@@ -138,6 +138,20 @@ public class Db {
throw new IciqlException(e);
}
}
+
+ /**
+ * Convenience function to avoid import statements in application code.
+ */
+ public static void activateConsoleLogger() {
+ IciqlLogger.activateConsoleLogger();
+ }
+
+ /**
+ * Convenience function to avoid import statements in application code.
+ */
+ public static void deactivateConsoleLogger() {
+ IciqlLogger.deactivateConsoleLogger();
+ }
public static Db open(String url) {
try {
@@ -273,9 +287,10 @@ public class Db {
List<T> result = new ArrayList<T>();
TableDefinition<T> def = (TableDefinition<T>) define(modelClass);
try {
+ int [] columns = def.mapColumns(rs);
while (rs.next()) {
T item = Utils.newObject(modelClass);
- def.readRow(item, rs);
+ def.readRow(item, rs, columns);
result.add(item);
}
} catch (SQLException e) {
diff --git a/src/com/iciql/Iciql.java b/src/com/iciql/Iciql.java
index eaa256a..b13baf4 100644
--- a/src/com/iciql/Iciql.java
+++ b/src/com/iciql/Iciql.java
@@ -500,6 +500,17 @@ public interface Iciql {
}
/**
+ * Annotation to define a field that should contain the result a function.
+ * This annotation ensures that functions mapped in anonymous inner classes
+ * can still be referenced in the ResultSet after the switch to dynamic
+ * column-name mapping from fixed position column mapping.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.FIELD)
+ public @interface IQFunction{
+ }
+
+ /**
* Annotation to define an ignored field.
*/
@Retention(RetentionPolicy.RUNTIME)
diff --git a/src/com/iciql/Query.java b/src/com/iciql/Query.java
index b43f774..33b6dfa 100644
--- a/src/com/iciql/Query.java
+++ b/src/com/iciql/Query.java
@@ -123,9 +123,10 @@ public class Query<T> {
appendFromWhere(stat);
ResultSet rs = stat.executeQuery();
try {
+ int[] columns = def.mapColumns(rs);
while (rs.next()) {
T item = from.newObject();
- from.getAliasDefinition().readRow(item, rs);
+ def.readRow(item, rs, columns);
result.add(item);
}
} catch (SQLException e) {
@@ -150,6 +151,7 @@ public class Query<T> {
}
public UpdateColumnSet<T, Boolean> set(boolean field) {
+ from.getAliasDefinition().checkMultipleBooleans();
return setPrimitive(field);
}
@@ -269,9 +271,10 @@ public class Query<T> {
appendFromWhere(stat);
ResultSet rs = stat.executeQuery();
try {
+ int[] columns = def.mapColumns(rs);
while (rs.next()) {
X row = Utils.newObject(clazz);
- def.readRow(row, rs);
+ def.readRow(row, rs, columns);
result.add(row);
}
} catch (SQLException e) {
@@ -328,6 +331,7 @@ public class Query<T> {
* @return a query condition to continue building the condition
*/
public QueryCondition<T, Boolean> where(boolean x) {
+ from.getAliasDefinition().checkMultipleBooleans();
return wherePrimitive(x);
}
@@ -449,6 +453,10 @@ public class Query<T> {
return new QueryWhere<T>(this);
}
+ public QueryWhere<T> where(String fragment, List<?> args) {
+ return this.where(fragment, args.toArray());
+ }
+
public QueryWhere<T> where(String fragment, Object... args) {
conditions.add(new RuntimeToken(fragment, args));
return new QueryWhere<T>(this);
@@ -477,6 +485,7 @@ public class Query<T> {
}
public Query<T> orderBy(boolean field) {
+ from.getAliasDefinition().checkMultipleBooleans();
return orderByPrimitive(field);
}
@@ -541,6 +550,7 @@ public class Query<T> {
}
public Query<T> groupBy(boolean field) {
+ from.getAliasDefinition().checkMultipleBooleans();
return groupByPrimitive(field);
}
@@ -737,6 +747,10 @@ public class Query<T> {
return db;
}
+ SelectTable<T> getFrom() {
+ return from;
+ }
+
boolean isJoin() {
return !joins.isEmpty();
}
diff --git a/src/com/iciql/QueryJoin.java b/src/com/iciql/QueryJoin.java
index 652d937..6d0484e 100644
--- a/src/com/iciql/QueryJoin.java
+++ b/src/com/iciql/QueryJoin.java
@@ -32,6 +32,7 @@ public class QueryJoin<T> {
}
public QueryJoinCondition<T, Boolean> on(boolean x) {
+ query.getFrom().getAliasDefinition().checkMultipleBooleans();
return addPrimitive(x);
}
@@ -59,7 +60,7 @@ public class QueryJoin<T> {
return addPrimitive(x);
}
- private <A> QueryJoinCondition<T, A> addPrimitive(A x) {
+ private <A> QueryJoinCondition<T, A> addPrimitive(A x) {
A alias = query.getPrimitiveAliasByValue(x);
if (alias == null) {
// this will result in an unmapped field exception
diff --git a/src/com/iciql/QueryWhere.java b/src/com/iciql/QueryWhere.java
index c1e3b03..df93439 100644
--- a/src/com/iciql/QueryWhere.java
+++ b/src/com/iciql/QueryWhere.java
@@ -42,6 +42,7 @@ public class QueryWhere<T> {
* @return a query condition to continue building the condition
*/
public QueryCondition<T, Boolean> and(boolean x) {
+ query.getFrom().getAliasDefinition().checkMultipleBooleans();
return addPrimitive(ConditionAndOr.AND, x);
}
@@ -111,7 +112,7 @@ public class QueryWhere<T> {
return addPrimitive(ConditionAndOr.AND, x);
}
- private <A> QueryCondition<T, A> addPrimitive(ConditionAndOr condition, A x) {
+ private <A> QueryCondition<T, A> addPrimitive(ConditionAndOr condition, A x) {
query.addConditionToken(condition);
A alias = query.getPrimitiveAliasByValue(x);
if (alias == null) {
@@ -141,6 +142,7 @@ public class QueryWhere<T> {
* @return a query condition to continue building the condition
*/
public QueryCondition<T, Boolean> or(boolean x) {
+ query.getFrom().getAliasDefinition().checkMultipleBooleans();
return addPrimitive(ConditionAndOr.OR, x);
}
@@ -273,6 +275,7 @@ public class QueryWhere<T> {
* @return the query
*/
public QueryWhere<T> orderBy(boolean field) {
+ query.getFrom().getAliasDefinition().checkMultipleBooleans();
return orderByPrimitive(field);
}
diff --git a/src/com/iciql/TableDefinition.java b/src/com/iciql/TableDefinition.java
index 97060f9..1147238 100644
--- a/src/com/iciql/TableDefinition.java
+++ b/src/com/iciql/TableDefinition.java
@@ -30,6 +30,7 @@ import com.iciql.Iciql.EnumId;
import com.iciql.Iciql.EnumType;
import com.iciql.Iciql.IQColumn;
import com.iciql.Iciql.IQEnum;
+import com.iciql.Iciql.IQFunction;
import com.iciql.Iciql.IQIgnore;
import com.iciql.Iciql.IQIndex;
import com.iciql.Iciql.IQIndexes;
@@ -73,6 +74,7 @@ public class TableDefinition<T> {
String dataType;
int length;
int scale;
+ boolean isFunction;
boolean isPrimaryKey;
boolean isAutoIncrement;
boolean trim;
@@ -115,6 +117,10 @@ public class TableDefinition<T> {
}
private Object read(ResultSet rs, int columnIndex) {
+ if (columnIndex == 0) {
+ // unmapped column or function field
+ return null;
+ }
try {
return rs.getObject(columnIndex);
} catch (SQLException e) {
@@ -129,6 +135,7 @@ public class TableDefinition<T> {
int tableVersion;
List<String> primaryKeyColumnNames;
boolean memoryTable;
+ boolean multiplePrimitiveBools;
private boolean createIfRequired = true;
private Class<T> clazz;
@@ -354,6 +361,7 @@ public class TableDefinition<T> {
throw new IciqlException(e, "failed to get default object for {0}", columnName);
}
+ boolean isFunction = f.isAnnotationPresent(IQFunction.class);
boolean hasAnnotation = f.isAnnotationPresent(IQColumn.class);
if (hasAnnotation) {
IQColumn col = f.getAnnotation(IQColumn.class);
@@ -385,6 +393,7 @@ public class TableDefinition<T> {
fieldDef.scale = scale;
fieldDef.trim = trim;
fieldDef.nullable = nullable;
+ fieldDef.isFunction = isFunction;
fieldDef.defaultValue = defaultValue;
fieldDef.enumType = enumType;
fieldDef.dataType = ModelUtils.getDataType(fieldDef);
@@ -392,16 +401,32 @@ public class TableDefinition<T> {
}
}
List<String> primaryKey = Utils.newArrayList();
+ int primitiveBoolean = 0;
for (FieldDefinition fieldDef : fields) {
if (fieldDef.isPrimaryKey) {
primaryKey.add(fieldDef.columnName);
}
+ if (fieldDef.isPrimitive && fieldDef.field.getType().equals(boolean.class)) {
+ primitiveBoolean++;
+ }
+ }
+ if (primitiveBoolean > 1) {
+ multiplePrimitiveBools = true;
+ IciqlLogger
+ .warn("Model {0} has multiple primitive booleans! Possible where,set,join clause problem!");
}
if (primaryKey.size() > 0) {
setPrimaryKey(primaryKey);
}
}
+ void checkMultipleBooleans() {
+ if (multiplePrimitiveBools) {
+ throw new IciqlException(
+ "Can not explicitly reference multiple primitive booleans in a model class!");
+ }
+ }
+
/**
* Optionally truncates strings to the maximum length and converts
* java.lang.Enum types to Strings or Integers.
@@ -698,10 +723,47 @@ public class TableDefinition<T> {
}
}
- void readRow(Object item, ResultSet rs) {
+ /**
+ * Most queries executed by iciql have named select lists (select alpha,
+ * beta where...) but sometimes a wildcard select is executed (select *).
+ * When a wildcard query is executed on a table that has more columns than
+ * are mapped in your model object this creates a column mapping issue. JaQu
+ * assumed that you can always use the integer index of the reflectively
+ * mapped field definition to determine position in the result set.
+ *
+ * This is not always true.
+ *
+ * So iciql maps column names to column index in the result set to properly
+ * map the results of wildcard queries.
+ *
+ * @param rs
+ * @return
+ */
+ int[] mapColumns(ResultSet rs) {
+ int[] columns = new int[fields.size()];
for (int i = 0; i < fields.size(); i++) {
- FieldDefinition def = fields.get(i);
- Object o = def.read(rs, i + 1);
+ try {
+ FieldDefinition def = fields.get(i);
+ int columnIndex;
+ if (def.isFunction) {
+ // XXX review functions _always_ map after fields?
+ columnIndex = i + 1;
+ } else {
+ columnIndex = rs.findColumn(def.columnName);
+ }
+ columns[i] = columnIndex;
+ } catch (SQLException s) {
+ throw new IciqlException(s);
+ }
+ }
+ return columns;
+ }
+
+ void readRow(Object item, ResultSet rs, int[] columns) {
+ for (int i = 0; i < fields.size(); i++) {
+ FieldDefinition def = fields.get(i);
+ int index = columns[i];
+ Object o = def.read(rs, index);
def.setValue(item, o);
}
}