Great big revampage: no more strings anywhere. It's all ColumnExps all the way

down (well, all the way to the public API anyway).

Revamped index creation while I was in there because that was one of the big
string users. Now you just put @Index on the field you want indexed, and if you
want a multi-column index you do things with a magical static method just like
we do for complex (function) indices.

@UniqueConstraint may still go away since it's basically exactly the same thing
as @Index(unique=true), so it's kind of pointless to support both.
This commit is contained in:
Michael Bayne
2009-01-08 02:10:54 +00:00
parent a66f15e355
commit a9c992bb44
30 changed files with 260 additions and 356 deletions
+1
View File
@@ -3,6 +3,7 @@
<project name="library-dependencies">
<fileset dir="${libs.dir}" id="depot.libs">
<include name="ant.jar"/>
<include name="commons-collections.jar"/>
<include name="ehcache.jar"/>
<include name="google-collect.jar"/>
<include name="junit4.jar"/>
@@ -47,6 +47,7 @@ import com.samskivert.depot.clause.InsertClause;
import com.samskivert.depot.clause.QueryClause;
import com.samskivert.depot.clause.UpdateClause;
import com.samskivert.depot.clause.WhereClause;
import com.samskivert.depot.expression.ColumnExp;
import com.samskivert.depot.expression.SQLExpression;
import com.samskivert.depot.expression.ValueExp;
import com.samskivert.depot.impl.DepotMarshaller;
@@ -55,8 +56,8 @@ import com.samskivert.depot.impl.DepotTypes;
import com.samskivert.depot.impl.FindAllKeysQuery;
import com.samskivert.depot.impl.FindAllQuery;
import com.samskivert.depot.impl.FindOneQuery;
import com.samskivert.depot.impl.Modifier;
import com.samskivert.depot.impl.Modifier.*;
import com.samskivert.depot.impl.Modifier;
import com.samskivert.depot.impl.SQLBuilder;
import static com.samskivert.depot.Log.log;
@@ -208,7 +209,7 @@ public abstract class DepotRepository
*
* @throws DatabaseException if any problem is encountered communicating with the database.
*/
protected <T extends PersistentRecord> T load (Class<T> type, String ix, Comparable<?> val,
protected <T extends PersistentRecord> T load (Class<T> type, ColumnExp ix, Comparable<?> val,
QueryClause... clauses)
throws DatabaseException
{
@@ -221,8 +222,8 @@ public abstract class DepotRepository
*
* @throws DatabaseException if any problem is encountered communicating with the database.
*/
protected <T extends PersistentRecord> T load (Class<T> type, String ix1, Comparable<?> val1,
String ix2, Comparable<?> val2,
protected <T extends PersistentRecord> T load (Class<T> type, ColumnExp ix1, Comparable<?> val1,
ColumnExp ix2, Comparable<?> val2,
QueryClause... clauses)
throws DatabaseException
{
@@ -235,8 +236,8 @@ public abstract class DepotRepository
*
* @throws DatabaseException if any problem is encountered communicating with the database.
*/
protected <T extends PersistentRecord> T load (Class<T> type, String ix1, Comparable<?> val1,
String ix2, Comparable<?> val2, String ix3,
protected <T extends PersistentRecord> T load (Class<T> type, ColumnExp ix1, Comparable<?> val1,
ColumnExp ix2, Comparable<?> val2, ColumnExp ix3,
Comparable<?> val3, QueryClause... clauses)
throws DatabaseException
{
@@ -448,7 +449,7 @@ public abstract class DepotRepository
updateKey(marsh.getPrimaryKey(_result, false));
}
builder.newQuery(new InsertClause<T>(pClass, _result, identityFields));
builder.newQuery(new InsertClause(pClass, _result, identityFields));
PreparedStatement stmt = builder.prepare(conn);
try {
@@ -515,7 +516,7 @@ public abstract class DepotRepository
*
* @throws DatabaseException if any problem is encountered communicating with the database.
*/
protected <T extends PersistentRecord> int update (T record, final String... modifiedFields)
protected <T extends PersistentRecord> int update (T record, final ColumnExp... modifiedFields)
throws DatabaseException
{
@SuppressWarnings("unchecked") Class<T> pClass = (Class<T>) record.getClass();
@@ -527,7 +528,8 @@ public abstract class DepotRepository
throw new IllegalArgumentException("Can't update record with null primary key.");
}
UpdateClause<T> update = new UpdateClause<T>(pClass, key, modifiedFields, record);
UpdateClause<T> update = new UpdateClause<T>(
pClass, key, ColumnExp.toNames(modifiedFields), record);
final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, update));
builder.newQuery(update);
@@ -551,7 +553,7 @@ public abstract class DepotRepository
*
* @param type the type of the persistent object to be modified.
* @param primaryKey the primary key to match in the update.
* @param updates an mapping from the names of the fields/columns ti the values to be assigned.
* @param updates an mapping from the columns to the values to be assigned.
*
* @return the number of rows modified by this action.
*
@@ -560,12 +562,12 @@ public abstract class DepotRepository
* @throws DatabaseException if any problem is encountered communicating with the database.
*/
protected <T extends PersistentRecord> int updatePartial (
Class<T> type, Comparable<?> primaryKey, Map<String,Object> updates)
Class<T> type, Comparable<?> primaryKey, Map<ColumnExp,Object> updates)
throws DatabaseException
{
Object[] fieldsValues = new Object[updates.size()*2];
int idx = 0;
for (Map.Entry<String,Object> entry : updates.entrySet()) {
for (Map.Entry<ColumnExp,Object> entry : updates.entrySet()) {
fieldsValues[idx++] = entry.getKey();
fieldsValues[idx++] = entry.getValue();
}
@@ -577,7 +579,7 @@ public abstract class DepotRepository
*
* @param type the type of the persistent object to be modified.
* @param primaryKey the primary key to match in the update.
* @param fieldsValues an array containing the names of the fields/columns and the values to be
* @param fieldsValues an array containing the columns (as ColumnExp) and the values to be
* assigned, in key, value, key, value, etc. order.
*
* @return the number of rows modified by this action.
@@ -598,7 +600,7 @@ public abstract class DepotRepository
* primary key.
*
* @param type the type of the persistent object to be modified.
* @param fieldsValues an array containing the names of the fields/columns and the values to be
* @param fieldsValues an array containing the columns (as ColumnExp) and the values to be
* assigned, in key, value, key, value, etc. order.
*
* @return the number of rows modified by this action.
@@ -608,7 +610,7 @@ public abstract class DepotRepository
* @throws DatabaseException if any problem is encountered communicating with the database.
*/
protected <T extends PersistentRecord> int updatePartial (
Class<T> type, String ix1, Comparable<?> val1, String ix2, Comparable<?> val2,
Class<T> type, ColumnExp ix1, Comparable<?> val1, ColumnExp ix2, Comparable<?> val2,
Object... fieldsValues)
throws DatabaseException
{
@@ -620,7 +622,7 @@ public abstract class DepotRepository
* primary key.
*
* @param type the type of the persistent object to be modified.
* @param fieldsValues an array containing the names of the fields/columns and the values to be
* @param fieldsValues an array containing the columns (as ColumnExp) and the values to be
* assigned, in key, value, key, value, etc. order.
*
* @return the number of rows modified by this action.
@@ -630,8 +632,8 @@ public abstract class DepotRepository
* @throws DatabaseException if any problem is encountered communicating with the database.
*/
protected <T extends PersistentRecord> int updatePartial (
Class<T> type, String ix1, Comparable<?> val1, String ix2, Comparable<?> val2,
String ix3, Comparable<?> val3, Object... fieldsValues)
Class<T> type, ColumnExp ix1, Comparable<?> val1, ColumnExp ix2, Comparable<?> val2,
ColumnExp ix3, Comparable<?> val3, Object... fieldsValues)
throws DatabaseException
{
return updatePartial(new Key<T>(type, ix1, val1, ix2, val2, ix3, val3), fieldsValues);
@@ -641,7 +643,7 @@ public abstract class DepotRepository
* Updates the specified columns for all persistent objects matching the supplied key.
*
* @param key the key for the persistent objects to be modified.
* @param fieldsValues an array containing the names of the fields/columns and the values to be
* @param fieldsValues an array containing the columns (as ColumnExp) and the values to be
* assigned, in key, value, key, value, etc. order.
*
* @return the number of rows modified by this action.
@@ -666,7 +668,7 @@ public abstract class DepotRepository
* @param key the key to match in the update.
* @param invalidator a cache invalidator that will be run prior to the update to flush the
* relevant persistent objects from the cache, or null if no invalidation is needed.
* @param fieldsValues an array containing the names of the fields/columns and the values to be
* @param fieldsValues an array containing the columns (as ColumnExp) and the values to be
* assigned, in key, value, key, value, etc. order.
*
* @return the number of rows modified by this action.
@@ -688,7 +690,7 @@ public abstract class DepotRepository
final String[] fields = new String[fieldsValues.length/2];
final SQLExpression[] values = new SQLExpression[fields.length];
for (int ii = 0, idx = 0; ii < fields.length; ii++) {
fields[ii] = (String)fieldsValues[idx++];
fields[ii] = ((ColumnExp)fieldsValues[idx++]).name;
values[ii] = new ValueExp(fieldsValues[idx++]);
}
UpdateClause<T> update = new UpdateClause<T>(type, key, fields, values);
@@ -720,8 +722,7 @@ public abstract class DepotRepository
*
* @param type the type of the persistent object to be modified.
* @param primaryKey the key to match in the update.
* @param fieldsValues an array containing the names of the fields/columns and the values to be
* assigned, in key, literal value, key, literal value, etc. order.
* @param fieldsValues a map containing the columns and the values to be assigned.
*
* @return the number of rows modified by this action.
*
@@ -730,7 +731,7 @@ public abstract class DepotRepository
* @throws DatabaseException if any problem is encountered communicating with the database.
*/
protected <T extends PersistentRecord> int updateLiteral (
Class<T> type, Comparable<?> primaryKey, Map<String, SQLExpression> fieldsValues)
Class<T> type, Comparable<?> primaryKey, Map<ColumnExp, SQLExpression> fieldsValues)
throws DatabaseException
{
Key<T> key = _ctx.getMarshaller(type).makePrimaryKey(primaryKey);
@@ -748,8 +749,7 @@ public abstract class DepotRepository
* </pre>
*
* @param type the type of the persistent object to be modified.
* @param fieldsValues an array containing the names of the fields/columns and the values to be
* assigned, in key, literal value, key, literal value, etc. order.
* @param fieldsValues a map containing the columns and the values to be assigned.
*
* @return the number of rows modified by this action.
*
@@ -758,8 +758,8 @@ public abstract class DepotRepository
* @throws DatabaseException if any problem is encountered communicating with the database.
*/
protected <T extends PersistentRecord> int updateLiteral (
Class<T> type, String ix1, Comparable<?> val1, String ix2, Comparable<?> val2,
Map<String, SQLExpression> fieldsValues)
Class<T> type, ColumnExp ix1, Comparable<?> val1, ColumnExp ix2, Comparable<?> val2,
Map<ColumnExp, SQLExpression> fieldsValues)
throws DatabaseException
{
Key<T> key = new Key<T>(type, ix1, val1, ix2, val2);
@@ -787,8 +787,8 @@ public abstract class DepotRepository
* @throws DatabaseException if any problem is encountered communicating with the database.
*/
protected <T extends PersistentRecord> int updateLiteral (
Class<T> type, String ix1, Comparable<?> val1, String ix2, Comparable<?> val2,
String ix3, Comparable<?> val3, Map<String, SQLExpression> fieldsValues)
Class<T> type, ColumnExp ix1, Comparable<?> val1, ColumnExp ix2, Comparable<?> val2,
ColumnExp ix3, Comparable<?> val3, Map<ColumnExp, SQLExpression> fieldsValues)
throws DatabaseException
{
Key<T> key = new Key<T>(type, ix1, val1, ix2, val2, ix3, val3);
@@ -818,7 +818,7 @@ public abstract class DepotRepository
*/
protected <T extends PersistentRecord> int updateLiteral (
Class<T> type, final WhereClause key, CacheInvalidator invalidator,
Map<String, SQLExpression> fieldsValues)
Map<ColumnExp, SQLExpression> fieldsValues)
throws DatabaseException
{
requireNotComputed(type, "updateLiteral");
@@ -832,8 +832,8 @@ public abstract class DepotRepository
final String[] fields = new String[fieldsValues.size()];
final SQLExpression[] values = new SQLExpression[fields.length];
int ii = 0;
for (Map.Entry<String, SQLExpression> entry : fieldsValues.entrySet()) {
fields[ii] = entry.getKey();
for (Map.Entry<ColumnExp, SQLExpression> entry : fieldsValues.entrySet()) {
fields[ii] = entry.getKey().name;
values[ii] = entry.getValue();
ii ++;
}
@@ -907,7 +907,7 @@ public abstract class DepotRepository
updateKey(marsh.getPrimaryKey(_result, false));
}
builder.newQuery(new InsertClause<T>(pClass, _result, identityFields));
builder.newQuery(new InsertClause(pClass, _result, identityFields));
stmt = builder.prepare(conn);
int mods = stmt.executeUpdate();
@@ -1012,7 +1012,7 @@ public abstract class DepotRepository
}
where.validateQueryType(type); // and another
DeleteClause<T> delete = new DeleteClause<T>(type, where);
DeleteClause delete = new DeleteClause(type, where);
final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, delete));
builder.newQuery(delete);
+23 -12
View File
@@ -28,6 +28,7 @@ import java.util.Map;
import com.google.common.collect.Maps;
import com.samskivert.depot.clause.WhereClause;
import com.samskivert.depot.expression.ColumnExp;
import com.samskivert.depot.expression.SQLExpression;
import com.samskivert.depot.impl.DepotMarshaller;
import com.samskivert.depot.impl.DepotUtil;
@@ -71,33 +72,42 @@ public class Key<T extends PersistentRecord> extends WhereClause
/**
* Constructs a new single-column {@code Key} with the given value.
*/
public Key (Class<T> pClass, String ix, Comparable<?> val)
public Key (Class<T> pClass, ColumnExp ix, Comparable<?> val)
{
this(pClass, new String[] { ix }, new Comparable[] { val });
this(pClass, new ColumnExp[] { ix }, new Comparable[] { val });
}
/**
* Constructs a new two-column {@code Key} with the given values.
*/
public Key (Class<T> pClass, String ix1, Comparable<?> val1,
String ix2, Comparable<?> val2)
public Key (Class<T> pClass, ColumnExp ix1, Comparable<?> val1,
ColumnExp ix2, Comparable<?> val2)
{
this(pClass, new String[] { ix1, ix2 }, new Comparable[] { val1, val2 });
this(pClass, new ColumnExp[] { ix1, ix2 }, new Comparable[] { val1, val2 });
}
/**
* Constructs a new three-column {@code Key} with the given values.
*/
public Key (Class<T> pClass, String ix1, Comparable<?> val1,
String ix2, Comparable<?> val2, String ix3, Comparable<?> val3)
public Key (Class<T> pClass, ColumnExp ix1, Comparable<?> val1,
ColumnExp ix2, Comparable<?> val2, ColumnExp ix3, Comparable<?> val3)
{
this(pClass, new String[] { ix1, ix2, ix3 }, new Comparable[] { val1, val2, val3 });
this(pClass, new ColumnExp[] { ix1, ix2, ix3 }, new Comparable[] { val1, val2, val3 });
}
/**
* TEMP: legacy foo bar!
*/
public Key (Class<T> pClass, String[] fields, Comparable<?>[] values)
{
_pClass = pClass;
_values = values;
}
/**
* Constructs a new multi-column {@code Key} with the given values.
*/
public Key (Class<T> pClass, String[] fields, Comparable<?>[] values)
public Key (Class<T> pClass, ColumnExp[] fields, Comparable<?>[] values)
{
if (fields.length != values.length) {
throw new IllegalArgumentException("Field and Value arrays must be of equal length.");
@@ -109,7 +119,7 @@ public class Key<T extends PersistentRecord> extends WhereClause
// build a local map of field name -> field value
Map<String, Comparable<?>> map = Maps.newHashMap();
for (int i = 0; i < fields.length; i ++) {
map.put(fields[i], values[i]);
map.put(fields[i].name, values[i]);
}
// look up the cached primary key fields for this object
@@ -138,9 +148,10 @@ public class Key<T extends PersistentRecord> extends WhereClause
}
/**
* Used to create a key when you know you have the canonical values array.
* Used to create a key when you know you have the canonical values array. Don't call this
* unless you know what you're doing!
*/
protected Key (Class<T> pClass, Comparable<?>[] values)
public Key (Class<T> pClass, Comparable<?>[] values)
{
_pClass = pClass;
_values = values;
+3 -1
View File
@@ -33,6 +33,7 @@ import com.google.common.base.Function;
import com.samskivert.util.StringUtil;
import com.samskivert.depot.clause.WhereClause;
import com.samskivert.depot.expression.ColumnExp;
import com.samskivert.depot.expression.LiteralExp;
import com.samskivert.depot.expression.SQLExpression;
import com.samskivert.depot.impl.DepotUtil;
@@ -171,7 +172,8 @@ public abstract class KeySet<T extends PersistentRecord> extends WhereClause
// from WhereClause
public SQLExpression getWhereExpression () {
// Single-column keys result in the compact IN(keyVal1, keyVal2, ...)
return new Conditionals.In(_pClass, DepotUtil.getKeyFields(_pClass)[0], _keys);
ColumnExp column = new ColumnExp(_pClass, DepotUtil.getKeyFields(_pClass)[0]);
return new Conditionals.In(column, _keys);
}
// from Iterable<Key<T>>
@@ -22,6 +22,8 @@ package com.samskivert.depot;
import java.io.Serializable;
import com.samskivert.depot.expression.ColumnExp;
/**
* The base class for all persistent records used in Depot. Persistent records must be cloneable
* and serializable; this class is used to enforce those requirements.
@@ -29,6 +31,10 @@ import java.io.Serializable;
public class PersistentRecord
implements Cloneable, Serializable
{
// AUTO-GENERATED: FIELDS START
public static final Class<PersistentRecord> _R = PersistentRecord.class;
// AUTO-GENERATED: FIELDS END
@Override // from Object
public PersistentRecord clone ()
{
@@ -38,4 +44,13 @@ public class PersistentRecord
throw new RuntimeException(cnse); // this should never happen
}
}
/**
* Creates a column expression for this class with the specified field name. Used by the
* autogenerated column expression constants.
*/
protected static ColumnExp colexp (Class<? extends PersistentRecord> clazz, String fieldName)
{
return new ColumnExp(clazz, fieldName);
}
}
@@ -26,7 +26,9 @@ import java.util.Map;
import com.samskivert.jdbc.ColumnDefinition;
import com.samskivert.jdbc.DatabaseLiaison;
import com.samskivert.depot.annotation.Column;
import com.samskivert.depot.expression.ColumnExp;
import com.samskivert.depot.impl.FieldMarshaller;
import com.samskivert.depot.impl.Modifier;
@@ -74,10 +76,10 @@ public abstract class SchemaMigration extends Modifier
*/
public static class Rename extends SchemaMigration
{
public Rename (int targetVersion, String oldColumnName, String newColumnName) {
public Rename (int targetVersion, String oldColumnName, ColumnExp newColumn) {
super(targetVersion);
_oldColumnName = oldColumnName;
_newColumnName = newColumnName;
_newColumnName = newColumn.name;
}
@Override public boolean runBeforeDefault () {
@@ -132,9 +134,9 @@ public abstract class SchemaMigration extends Modifier
*/
public static class Retype extends SchemaMigration
{
public Retype (int targetVersion, String fieldName) {
public Retype (int targetVersion, ColumnExp column) {
super(targetVersion);
_fieldName = fieldName;
_fieldName = column.name;
}
@Override public boolean runBeforeDefault () {
@@ -170,9 +172,9 @@ public abstract class SchemaMigration extends Modifier
*/
public static class Add extends SchemaMigration
{
public Add (int targetVersion, String fieldName, String defaultValue) {
public Add (int targetVersion, ColumnExp column, String defaultValue) {
super(targetVersion);
_fieldName = fieldName;
_fieldName = column.name;
_defaultValue = defaultValue;
}
@@ -20,6 +20,7 @@
package com.samskivert.depot.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -27,23 +28,22 @@ import java.lang.annotation.Target;
/**
* Defines an index on an entity table.
*/
@Target(value={})
@Target(value=ElementType.FIELD)
@Retention(value=RetentionPolicy.RUNTIME)
public @interface Index
{
/** Defines the name of the index. */
String name ();
/** Defines the name of the index. If this is defined, a static method must be defined on the
* record that provides the index configuration. The method must match one of the following
* two signatures:
* <pre>
* public static ColumnExp[] indexName ()
* public static List<Tuple<SQLExpression, OrderBy.Order>> indexName ()
* </pre>
* The first form will result in a simple multicolum index being created with the supplied
* columns. The second will create a function index using the supplied SQLExpressions.
*/
String name () default "";
/** Does this index enforce a uniqueness constraint? */
boolean unique () default false;
/** Defines the fields on which the index operates. */
String[] fields () default {};
/** Whether or not this is a complex index. If true, a static method
* must be defined on the record that declares this index of the signature:
* <pre>public static List<Tuple<SQLExpression, OrderBy.Order>> indexNameExpression ()</pre>
* which should return the index's defining expressions and whether each one is ascending
* or descending. */
boolean complex () default false;
}
@@ -25,15 +25,16 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation is used to specify that a unique constraint is to be included in the
* generated DDL for a table.
* Used to specify a uniqueness constraint on a set of columns. If you want a single column to be
* unique, simply use {@link Column#unique}.
*/
@Target(value={})
@Retention(value=RetentionPolicy.RUNTIME)
public @interface UniqueConstraint
{
/**
* An array of the field names that make up the constraint
*/
public String[] fieldNames () default {};
/** The name of the index that will be created to enforce this constraint. */
String name ();
/** An array of the field names that make up the constraint */
String[] fields ();
}
@@ -32,17 +32,15 @@ import com.samskivert.util.Tuple;
/**
* Represents an CREATE INDEX instruction to the database.
*/
public class CreateIndexClause<T extends PersistentRecord>
public class CreateIndexClause
implements QueryClause
{
/**
* Create a new {@link CreateIndexClause} clause. The name must be unique within the
* relevant database.
* Create a new {@link CreateIndexClause} clause. The name must be unique within the relevant
* database.
*/
public CreateIndexClause (
Class<? extends PersistentRecord> pClass, String name, boolean unique,
List<Tuple<SQLExpression, Order>> fields)
public CreateIndexClause (Class<? extends PersistentRecord> pClass, String name, boolean unique,
List<Tuple<SQLExpression, Order>> fields)
{
_pClass = pClass;
_name = name;
@@ -83,9 +81,7 @@ public class CreateIndexClause<T extends PersistentRecord>
}
protected Class<? extends PersistentRecord> _pClass;
protected String _name;
protected boolean _unique;
/** The components of the index, e.g. columns or functions of columns. */
@@ -28,7 +28,7 @@ import com.samskivert.depot.impl.ExpressionVisitor;
/**
* Builds actual SQL given a main persistent type and some {@link QueryClause} objects.
*/
public class DeleteClause<T extends PersistentRecord> implements QueryClause
public class DeleteClause implements QueryClause
{
public DeleteClause (Class<? extends PersistentRecord> pClass, WhereClause where)
{
@@ -55,6 +55,12 @@ public class FieldDefinition implements QueryClause
_definition = override;
}
public FieldDefinition (ColumnExp field, SQLExpression override)
{
_field = field.name;
_definition = override;
}
/**
* The field we're defining. The Query object uses this for indexing.
*/
@@ -29,10 +29,10 @@ import com.samskivert.depot.impl.ExpressionVisitor;
/**
* Builds actual SQL given a main persistent type and some {@link QueryClause} objects.
*/
public class InsertClause<T extends PersistentRecord> implements QueryClause
public class InsertClause implements QueryClause
{
public InsertClause (
Class<? extends PersistentRecord> pClass, Object pojo, Set<String> identityFields)
public InsertClause (Class<? extends PersistentRecord> pClass, Object pojo,
Set<String> identityFields)
{
_pClass = pClass;
_pojo = pojo;
@@ -37,13 +37,6 @@ public class Join implements QueryClause
/** Indicates the join type to be used. The default is INNER. */
public static enum Type { INNER, LEFT_OUTER, RIGHT_OUTER };
public Join (Class<? extends PersistentRecord> pClass, String pCol,
Class<? extends PersistentRecord> joinClass, String jCol)
{
_joinClass = joinClass;
_joinCondition = new Equals(new ColumnExp(joinClass, jCol), new ColumnExp(pClass, pCol));
}
public Join (ColumnExp primary, ColumnExp join)
{
_joinClass = join.getPersistentClass();
@@ -23,6 +23,7 @@ package com.samskivert.depot.clause;
import java.util.Collection;
import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.expression.ColumnExp;
import com.samskivert.depot.expression.SQLExpression;
import com.samskivert.depot.impl.ExpressionVisitor;
@@ -31,11 +31,24 @@ import com.samskivert.depot.impl.ExpressionVisitor;
public class ColumnExp
implements SQLExpression
{
/** The name of the column we reference. */
public final String name;
/** Converts an array of column expressions to an array of just the bare names. */
public static String[] toNames (ColumnExp[] columns)
{
String[] names = new String[columns.length];
for (int ii = 0; ii < names.length; ii++) {
names[ii] = columns[ii].name;
}
return names;
}
public ColumnExp (Class<? extends PersistentRecord> pClass, String field)
{
super();
_pClass = pClass;
_pField = field;
this.name = field;
}
// from SQLExpression
@@ -57,18 +70,15 @@ public class ColumnExp
public String getField ()
{
return _pField;
return name;
}
@Override // from Object
public String toString ()
{
return "\"" + _pField + "\""; // TODO: qualify with record name and be uber verbose?
return "\"" + name + "\""; // TODO: qualify with record name and be uber verbose?
}
/** The table that hosts the column we reference, or null. */
protected final Class<? extends PersistentRecord> _pClass;
/** The name of the column we reference. */
protected final String _pField;
}
@@ -248,7 +248,7 @@ public class BindVisitor implements ExpressionVisitor
updateClause.getWhereClause().accept(this);
}
public void visit (InsertClause<? extends PersistentRecord> insertClause)
public void visit (InsertClause insertClause)
{
DepotMarshaller<?> marsh = _types.getMarshaller(insertClause.getPersistentClass());
Object pojo = insertClause.getPojo();
@@ -266,12 +266,12 @@ public class BindVisitor implements ExpressionVisitor
}
}
public void visit (DeleteClause<? extends PersistentRecord> deleteClause)
public void visit (DeleteClause deleteClause)
{
deleteClause.getWhereClause().accept(this);
}
public void visit (CreateIndexClause<? extends PersistentRecord> createIndexClause)
public void visit (CreateIndexClause createIndexClause)
{
for (Tuple<SQLExpression, Order> field : createIndexClause.getFields()) {
field.left.accept(this);
@@ -430,7 +430,7 @@ public abstract class BuildVisitor implements ExpressionVisitor
updateClause.getWhereClause().accept(this);
}
public void visit (DeleteClause<? extends PersistentRecord> deleteClause)
public void visit (DeleteClause deleteClause)
{
_builder.append("delete from ");
appendTableName(deleteClause.getPersistentClass());
@@ -440,7 +440,7 @@ public abstract class BuildVisitor implements ExpressionVisitor
deleteClause.getWhereClause().accept(this);
}
public void visit (InsertClause<? extends PersistentRecord> insertClause)
public void visit (InsertClause insertClause)
{
Class<? extends PersistentRecord> pClass = insertClause.getPersistentClass();
DepotMarshaller<?> marsh = _types.getMarshaller(pClass);
@@ -480,7 +480,7 @@ public abstract class BuildVisitor implements ExpressionVisitor
_builder.append(")");
}
public void visit (CreateIndexClause<? extends PersistentRecord> createIndexClause)
public void visit (CreateIndexClause createIndexClause)
{
_builder.append("create ");
if (createIndexClause.isUnique()) {
@@ -31,7 +31,8 @@ import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -46,6 +47,7 @@ import com.samskivert.depot.PersistenceContext;
import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.SchemaMigration;
import com.samskivert.depot.Stats;
import com.samskivert.depot.annotation.Column;
import com.samskivert.depot.annotation.Computed;
import com.samskivert.depot.annotation.Entity;
import com.samskivert.depot.annotation.FullTextIndex;
@@ -194,6 +196,20 @@ public class DepotMarshaller<T extends PersistentRecord>
}
}
// check whether this field is indexed
Index index = field.getAnnotation(Index.class);
if (index != null) {
String ixName = index.name().equals("") ? field.getName() + "Index" : index.name();
_indexes.add(buildIndex(ixName, index.unique(),
new ColumnExp(_pClass, field.getName())));
}
// if this column is marked as unique, that also means we create an index
Column column = field.getAnnotation(Column.class);
if (column != null && column.unique()) {
_indexes.add(buildIndex(field.getName() + "Index", true,
new ColumnExp(_pClass, field.getName())));
}
}
// if we did not find a schema version field, freak out (but not for computed records, for
@@ -207,32 +223,30 @@ public class DepotMarshaller<T extends PersistentRecord>
_allFields = fields.toArray(new String[fields.size()]);
// now check for @Entity annotations on the entire superclass chain
Class<?> iterClass = pClass;
Class<? extends PersistentRecord> iterClass = pClass.asSubclass(PersistentRecord.class);
do {
entity = iterClass.getAnnotation(Entity.class);
if (entity != null) {
// add any indices needed for uniqueness constraints
for (UniqueConstraint constraint : entity.uniqueConstraints()) {
String[] conFields = constraint.fieldNames();
Set<String> colSet = Sets.newHashSet();
for (int ii = 0; ii < conFields.length; ii ++) {
FieldMarshaller<?> fm = _fields.get(conFields[ii]);
List<ColumnExp> colExps = Lists.newArrayList();
for (String field : constraint.fields()) {
FieldMarshaller<?> fm = _fields.get(field);
if (fm == null) {
throw new IllegalArgumentException(
"Unknown unique constraint field: " + conFields[ii]);
"Unknown unique constraint field: " + field);
}
colSet.add(fm.getColumnName());
colExps.add(new ColumnExp(_pClass, field));
}
_uniqueConstraints.add(colSet);
_indexes.add(buildIndex(constraint.name(), true, colExps));
}
// add any explicit multicolumn or complex indices
for (Index index : entity.indices()) {
if (_indexes.containsKey(index.name())) {
continue;
}
_indexes.put(index.name(), index);
_indexes.add(buildIndex(index.name(), index.unique()));
}
// if there are FTS indexes in the Table, map those out here for future use
// note any FTS indices
for (FullTextIndex fti : entity.fullTextIndices()) {
if (_fullTextIndexes.containsKey(fti.name())) {
continue;
@@ -241,7 +255,7 @@ public class DepotMarshaller<T extends PersistentRecord>
}
}
iterClass = iterClass.getSuperclass();
iterClass = iterClass.getSuperclass().asSubclass(PersistentRecord.class);
} while (PersistentRecord.class.isAssignableFrom(iterClass) &&
!PersistentRecord.class.equals(iterClass));
@@ -385,7 +399,7 @@ public class DepotMarshaller<T extends PersistentRecord>
// make sure the keys are all null or all non-null
if (nulls == 0) {
return makePrimaryKey(values);
return new Key<T>(_pClass, values);
} else if (nulls == values.length) {
return null;
} else if (nulls == zeros) {
@@ -394,7 +408,7 @@ public class DepotMarshaller<T extends PersistentRecord>
// this is a compromise that allows sensible things like (id=99, type=0) but
// unfortunately also allows less sensible things like (id=0, type=5) while
// continuing to disallow the dangerous (id=0)
return makePrimaryKey(values);
return new Key<T>(_pClass, values);
}
// throw an informative error message
@@ -413,19 +427,15 @@ public class DepotMarshaller<T extends PersistentRecord>
/**
* Creates a primary key record for the type of object handled by this marshaller, using the
* supplied primary key value.
* supplied primary key value. This is only allowed for records with single column keys.
*/
public Key<T> makePrimaryKey (Comparable<?>... values)
public Key<T> makePrimaryKey (Comparable<?> value)
{
if (!hasPrimaryKey()) {
throw new UnsupportedOperationException(
getClass().getName() + " does not define a primary key");
}
String[] fields = new String[_pkColumns.size()];
for (int ii = 0; ii < _pkColumns.size(); ii++) {
fields[ii] = _pkColumns.get(ii).getField().getName();
}
return new Key<T>(_pClass, fields, values);
return new Key<T>(_pClass, new Comparable<?>[] { value });
}
/**
@@ -448,7 +458,7 @@ public class DepotMarshaller<T extends PersistentRecord>
}
values[ii] = (Comparable<?>) keyValue;
}
return makePrimaryKey(values);
return new Key<T>(_pClass, values);
}
/**
@@ -703,12 +713,6 @@ public class DepotMarshaller<T extends PersistentRecord>
{
log.info("Creating initial table '" + getTableName() + "'.");
final String[][] uniqueConCols = new String[_uniqueConstraints.size()][];
int kk = 0;
for (Set<String> colSet : _uniqueConstraints) {
uniqueConCols[kk++] = colSet.toArray(new String[colSet.size()]);
}
final Iterable<Index> indexen = _indexes.values();
ctx.invoke(new Modifier() {
@Override
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
@@ -722,14 +726,11 @@ public class DepotMarshaller<T extends PersistentRecord>
}
liaison.createTableIfMissing(
conn, getTableName(), fieldsToColumns(_columnFields),
declarations, uniqueConCols, primaryKeyColumns);
declarations, null, primaryKeyColumns);
// add its indexen
for (Index index : indexen) {
String ixName = getTableName() + "_" + index.name();
execute(conn, builder, index.complex() ?
buildComplexIndex(ixName, index.unique(), index.name()) :
buildSimpleIndex(ixName, index.unique(), index.fields()));
for (CreateIndexClause iclause : _indexes) {
execute(conn, builder, iclause);
}
// create our value generators
@@ -752,7 +753,6 @@ public class DepotMarshaller<T extends PersistentRecord>
{
if (builder.newQuery(clause)) {
PreparedStatement stmt = builder.prepare(conn);
try {
return stmt.executeUpdate();
} finally {
@@ -783,9 +783,6 @@ public class DepotMarshaller<T extends PersistentRecord>
metaData = TableMetaData.load(ctx, getTableName());
}
// this is a little silly, but we need a copy for name disambiguation later
Set<String> indicesCopy = Sets.newHashSet(metaData.indexColumns.keySet());
// figure out which columns we have in the table now, so that when all is said and done we
// can see what new columns we have in the table and run the creation code for any value
// generators that are defined on those columns (we can't just track the columns we add in
@@ -854,57 +851,17 @@ public class DepotMarshaller<T extends PersistentRecord>
}
// add any named indices that exist on the record but not yet on the table
for (final Index index : _indexes.values()) {
final String ixName = getTableName() + "_" + index.name();
if (metaData.indexColumns.containsKey(ixName)) {
// this index already exists
metaData.indexColumns.remove(ixName);
for (final CreateIndexClause iclause : _indexes) {
if (metaData.indexColumns.containsKey(iclause.getName())) {
metaData.indexColumns.remove(iclause.getName()); // this index already exists
continue;
}
// but this is a new, named index, so we create it
log.info("Creating new index: " + ixName);
log.info("Creating new index: " + iclause.getName());
ctx.invoke(new Modifier() {
@Override
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
execute(conn, builder, index.complex() ?
buildComplexIndex(ixName, index.unique(), index.name()) :
buildSimpleIndex(ixName, index.unique(), index.fields()));
return 0;
}
});
}
// now check if there are any @Entity(uniqueConstraints) that need to be created
Set<Set<String>> uniqueIndices = Sets.newHashSet(metaData.indexColumns.values());
// unique constraints are unordered and may be unnamed, so we view them only as column sets
for (Set<String> colSet : _uniqueConstraints) {
if (uniqueIndices.contains(colSet)) {
// the table already contains precisely this column set
continue;
}
// else build the new constraint; we'll name it after one of its columns, adding _N
// to resolve any possible ambiguities, because using all the column names in the
// index name may exceed the maximum length of an SQL identifier
String indexName = colSet.iterator().next();
if (indicesCopy.contains(indexName)) {
int num = 1;
indexName += "_";
while (indicesCopy.contains(indexName + num)) {
num ++;
}
indexName += num;
}
final String[] colArr = colSet.toArray(new String[colSet.size()]);
final String fName = indexName;
ctx.invoke(new Modifier() {
@Override
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
if (!liaison.tableContainsIndex(conn, getTableName(), fName)) {
execute(conn, builder, buildSimpleIndex(fName, true, colArr));
}
execute(conn, builder, iclause);
return 0;
}
});
@@ -981,57 +938,49 @@ public class DepotMarshaller<T extends PersistentRecord>
return metaData;
}
private CreateIndexClause<T> buildComplexIndex (String ixName, boolean unique, String localIxName)
throws SQLException
protected CreateIndexClause buildIndex (String name, boolean unique)
{
List<Tuple<SQLExpression, Order>> definition;
String methName = localIxName + "Definition";
Method method;
try {
method = _pClass.getMethod(methName);
method = _pClass.getMethod(name);
} catch (NoSuchMethodException nsme) {
throw new IllegalArgumentException(
"Index flagged as complex, but no defining method '" + methName
+ "' found.", nsme);
"Index flagged as complex, but no defining method '" + name + "' found.", nsme);
}
Object result;
try {
result = method.invoke(null);
return buildIndex(name, unique, method.invoke(null));
} catch (Exception e) {
throw new IllegalArgumentException(
"Error calling index definition method '" + methName + "'", e);
"Error calling index definition method '" + name + "'", e);
}
if (result instanceof SQLExpression) {
definition = new ArrayList<Tuple<SQLExpression,Order>>();
definition.add(new Tuple<SQLExpression, Order>((SQLExpression)result, Order.ASC));
} else if (result instanceof List) {
@SuppressWarnings("unchecked")
List<Tuple<SQLExpression, Order>> def = (List<Tuple<SQLExpression, Order>>)result;
definition = def;
} else {
throw new IllegalArgumentException("Method '" + methName
+ "' must return SQLExpression or " + "List<Tuple<SQLExpression, Order>>");
}
return new CreateIndexClause<T>(_pClass, ixName, unique, definition);
}
private CreateIndexClause<T> buildSimpleIndex (String ixName, boolean unique, String[] fields)
throws SQLException
protected CreateIndexClause buildIndex (String name, boolean unique, Object config)
{
List<Tuple<SQLExpression, Order>> definition = new ArrayList<Tuple<SQLExpression,Order>>();
for (String field : fields) {
ColumnExp column = new ColumnExp(_pClass, field);
definition.add(new Tuple<SQLExpression, Order>(column, Order.ASC));
List<Tuple<SQLExpression, Order>> definition = Lists.newArrayList();
if (config instanceof ColumnExp) {
definition.add(new Tuple<SQLExpression, Order>((ColumnExp)config, Order.ASC));
} else if (config instanceof ColumnExp[]) {
for (ColumnExp column : (ColumnExp[])config) {
definition.add(new Tuple<SQLExpression, Order>(column, Order.ASC));
}
} else if (config instanceof SQLExpression) {
definition.add(new Tuple<SQLExpression, Order>((SQLExpression)config, Order.ASC));
} else if (config instanceof Tuple) {
@SuppressWarnings("unchecked") Tuple<SQLExpression, Order> tuple =
(Tuple<SQLExpression, Order>)config;
definition.add(tuple);
} else if (config instanceof List) {
@SuppressWarnings("unchecked") List<Tuple<SQLExpression, Order>> defs =
(List<Tuple<SQLExpression, Order>>)config;
definition.addAll(defs);
} else {
throw new IllegalArgumentException(
"Method '" + name + "' must return ColumnExp[], SQLExpression or " +
"List<Tuple<SQLExpression, Order>>");
}
return new CreateIndexClause<T>(_pClass, ixName, unique, definition);
return new CreateIndexClause(_pClass, getTableName() + "_" + name, unique, definition);
}
// translate an array of field names to an array of column names
@@ -1197,12 +1146,10 @@ public class DepotMarshaller<T extends PersistentRecord>
/** The fields of our object with directly corresponding table columns. */
protected String[] _columnFields;
/** The indexes defined in @Entity annotations for this record. */
protected Map<String, Index> _indexes = Maps.newHashMap();
/** The unique constraints defined in @Entity annotations for this record. */
protected Set<Set<String>> _uniqueConstraints = Sets.newHashSet();
/** The indexes defined for this record. */
protected List<CreateIndexClause> _indexes = Lists.newArrayList();
/** Any full text indices defined on this entity. */
protected Map<String, FullTextIndex> _fullTextIndexes = Maps.newHashMap();
/** The version of our persistent object schema as specified in the class definition. */
@@ -34,19 +34,9 @@ import com.samskivert.depot.expression.ColumnExp;
public class DepotMigrationHistoryRecord extends PersistentRecord
{
// AUTO-GENERATED: FIELDS START
/** The column identifier for the {@link #ident} field. */
public static final String IDENT = "ident";
/** The qualified column identifier for the {@link #ident} field. */
public static final ColumnExp IDENT_C =
new ColumnExp(DepotMigrationHistoryRecord.class, IDENT);
/** The column identifier for the {@link #whenCompleted} field. */
public static final String WHEN_COMPLETED = "whenCompleted";
/** The qualified column identifier for the {@link #whenCompleted} field. */
public static final ColumnExp WHEN_COMPLETED_C =
new ColumnExp(DepotMigrationHistoryRecord.class, WHEN_COMPLETED);
public static final Class<DepotMigrationHistoryRecord> _R = DepotMigrationHistoryRecord.class;
public static final ColumnExp IDENT = colexp(_R, "ident");
public static final ColumnExp WHEN_COMPLETED = colexp(_R, "whenCompleted");
// AUTO-GENERATED: FIELDS END
/** Our schema version. Probably not likely to change. */
@@ -68,7 +58,7 @@ public class DepotMigrationHistoryRecord extends PersistentRecord
{
return new Key<DepotMigrationHistoryRecord>(
DepotMigrationHistoryRecord.class,
new String[] { IDENT },
new ColumnExp[] { IDENT },
new Comparable[] { ident });
}
// AUTO-GENERATED: METHODS END
@@ -81,8 +81,8 @@ public interface ExpressionVisitor
public void visit (Exists<? extends PersistentRecord> exists);
public void visit (SelectClause<? extends PersistentRecord> selectClause);
public void visit (UpdateClause<? extends PersistentRecord> updateClause);
public void visit (DeleteClause<? extends PersistentRecord> deleteClause);
public void visit (InsertClause<? extends PersistentRecord> insertClause);
public void visit (CreateIndexClause<? extends PersistentRecord> createIndexClause);
public void visit (DeleteClause deleteClause);
public void visit (InsertClause insertClause);
public void visit (CreateIndexClause createIndexClause);
public void visit (DropIndexClause<? extends PersistentRecord> dropIndexClause);
}
@@ -67,7 +67,7 @@ public class HSQLBuilder
// (lower(COL1) like '%foo%') OR (lower(COL1) like '%bar%') OR ...
// (lower(COL2) like '%foo%') OR (lower(COL2) like '%bar%') OR ...
// ... and so on. Not efficient, but basically functional.
Class<? extends PersistentRecord> pClass = match.getPersistentRecord();
Class<? extends PersistentRecord> pClass = match.getPersistentClass();
// find the fields involved
String[] fields = _types.getMarshaller(pClass).
@@ -117,7 +117,7 @@ public class HSQLBuilder
}
@Override
public void visit (CreateIndexClause<? extends PersistentRecord> createIndexClause)
public void visit (CreateIndexClause createIndexClause)
{
for (Tuple<SQLExpression, Order> field : createIndexClause.getFields()) {
if (!(field.left instanceof ColumnExp)) {
@@ -67,7 +67,7 @@ public class MySQLBuilder
@Override public void visit (FullTextMatch match)
{
_builder.append("match(");
Class<? extends PersistentRecord> pClass = match.getPersistentRecord();
Class<? extends PersistentRecord> pClass = match.getPersistentClass();
String[] fields =
_types.getMarshaller(pClass).getFullTextIndex(match.getName()).fields();
for (int ii = 0; ii < fields.length; ii ++) {
@@ -79,7 +79,7 @@ public class MySQLBuilder
_builder.append(") against (? in boolean mode)");
}
@Override public void visit (DeleteClause<? extends PersistentRecord> deleteClause)
@Override public void visit (DeleteClause deleteClause)
{
_builder.append("delete from ");
appendTableName(deleteClause.getPersistentClass());
@@ -103,7 +103,7 @@ public class MySQLBuilder
}
@Override
public void visit (CreateIndexClause<? extends PersistentRecord> createIndexClause)
public void visit (CreateIndexClause createIndexClause)
{
for (Tuple<SQLExpression, Order> field : createIndexClause.getFields()) {
if (!(field.left instanceof ColumnExp)) {
@@ -38,16 +38,6 @@ public abstract class Conditionals
public static class IsNull
implements SQLOperator
{
public IsNull (String pColumn)
{
this(new ColumnExp(null, pColumn));
}
public IsNull (Class<? extends PersistentRecord> pClass, String pColumn)
{
this(new ColumnExp(pClass, pColumn));
}
public IsNull (ColumnExp column)
{
_column = column;
@@ -199,17 +189,6 @@ public abstract class Conditionals
/** The maximum number of keys allowed in an IN() clause. */
public static final int MAX_KEYS = Short.MAX_VALUE;
public In (Class<? extends PersistentRecord> pClass, String pColumn, Comparable<?>... values)
{
this(new ColumnExp(pClass, pColumn), values);
}
public In (Class<? extends PersistentRecord> pClass, String pColumn,
Collection<? extends Comparable<?>> values)
{
this(new ColumnExp(pClass, pColumn), values.toArray(new Comparable<?>[values.size()]));
}
public In (ColumnExp column, Comparable<?>... values)
{
if (values.length == 0) {
@@ -329,7 +308,7 @@ public abstract class Conditionals
_query = query;
}
public Class<? extends PersistentRecord> getPersistentRecord ()
public Class<? extends PersistentRecord> getPersistentClass ()
{
return _pClass;
}
@@ -35,58 +35,18 @@ import com.samskivert.util.StringUtil;
/**
* A test persistent object.
*/
@Entity(indices={ @Index(name="createdIndex", fields={"created"}) })
@Entity
public class TestRecord extends PersistentRecord
{
// AUTO-GENERATED: FIELDS START
/** The column identifier for the {@link #recordId} field. */
public static final String RECORD_ID = "recordId";
/** The qualified column identifier for the {@link #recordId} field. */
public static final ColumnExp RECORD_ID_C =
new ColumnExp(TestRecord.class, RECORD_ID);
/** The column identifier for the {@link #name} field. */
public static final String NAME = "name";
/** The qualified column identifier for the {@link #name} field. */
public static final ColumnExp NAME_C =
new ColumnExp(TestRecord.class, NAME);
/** The column identifier for the {@link #age} field. */
public static final String AGE = "age";
/** The qualified column identifier for the {@link #age} field. */
public static final ColumnExp AGE_C =
new ColumnExp(TestRecord.class, AGE);
/** The column identifier for the {@link #homeTown} field. */
public static final String HOME_TOWN = "homeTown";
/** The qualified column identifier for the {@link #homeTown} field. */
public static final ColumnExp HOME_TOWN_C =
new ColumnExp(TestRecord.class, HOME_TOWN);
/** The column identifier for the {@link #created} field. */
public static final String CREATED = "created";
/** The qualified column identifier for the {@link #created} field. */
public static final ColumnExp CREATED_C =
new ColumnExp(TestRecord.class, CREATED);
/** The column identifier for the {@link #lastModified} field. */
public static final String LAST_MODIFIED = "lastModified";
/** The qualified column identifier for the {@link #lastModified} field. */
public static final ColumnExp LAST_MODIFIED_C =
new ColumnExp(TestRecord.class, LAST_MODIFIED);
/** The column identifier for the {@link #numbers} field. */
public static final String NUMBERS = "numbers";
/** The qualified column identifier for the {@link #numbers} field. */
public static final ColumnExp NUMBERS_C =
new ColumnExp(TestRecord.class, NUMBERS);
public static final Class<TestRecord> _R = TestRecord.class;
public static final ColumnExp RECORD_ID = colexp(_R, "recordId");
public static final ColumnExp NAME = colexp(_R, "name");
public static final ColumnExp AGE = colexp(_R, "age");
public static final ColumnExp HOME_TOWN = colexp(_R, "homeTown");
public static final ColumnExp CREATED = colexp(_R, "created");
public static final ColumnExp LAST_MODIFIED = colexp(_R, "lastModified");
public static final ColumnExp NUMBERS = colexp(_R, "numbers");
// AUTO-GENERATED: FIELDS END
public static final int SCHEMA_VERSION = 3;
@@ -100,6 +60,7 @@ public class TestRecord extends PersistentRecord
public String homeTown;
@Index
public Date created;
public Timestamp lastModified;
@@ -121,7 +82,7 @@ public class TestRecord extends PersistentRecord
{
return new Key<TestRecord>(
TestRecord.class,
new String[] { RECORD_ID },
new ColumnExp[] { RECORD_ID },
new Comparable[] { recordId });
}
// AUTO-GENERATED: METHODS END
@@ -119,7 +119,7 @@ public class TestRepository extends DepotRepository
System.out.println("Delete none " + repo.deleteAll(TestRecord.class, none) + ".");
// test collection caching
Where where = new Where(new Conditionals.GreaterThan(TestRecord.RECORD_ID_C, 100));
Where where = new Where(new Conditionals.GreaterThan(TestRecord.RECORD_ID, 100));
System.out.println("100 and up: " + repo.findAll(TestRecord.class, where).size());
System.out.println("100 and up again: " + repo.findAll(TestRecord.class, where).size());
@@ -131,7 +131,7 @@ public class TestRepository extends DepotRepository
System.out.println("Names " + repo.findAll(TestNameRecord.class) + ".");
System.out.println("Have " + repo.findAll(TestRecord.class).size() + " records.");
repo.deleteAll(TestRecord.class, new Where(new Conditionals.LessThan(
TestRecord.RECORD_ID_C, CREATE_RECORDS/2)));
TestRecord.RECORD_ID, CREATE_RECORDS/2)));
System.out.println("Now have " + repo.findAll(TestRecord.class).size() + " records.");
repo.deleteAll(TestRecord.class, new Where(new LiteralExp("true")));
// // TODO: try to break our In() clause
@@ -3,7 +3,7 @@
//
// Depot library - a Java relational persistence library
// Copyright (C) 2006-2008 Michael Bayne and Pär Winzell
//
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
@@ -37,6 +37,7 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -254,29 +255,24 @@ public class GenRecordTask extends Task
// generate our fields section
StringBuilder fsection = new StringBuilder();
// add our prototype declaration
VelocityContext ctx = new VelocityContext();
ctx.put("record", rname);
fsection.append(mergeTemplate(PROTO_TMPL, ctx));
// add our ColumnExp constants
for (int ii = 0; ii < flist.size(); ii++) {
Field f = flist.get(ii);
String fname = f.getName();
// create our velocity context
VelocityContext ctx = new VelocityContext();
ctx.put("record", rname);
ctx.put("field", fname);
ctx.put("capfield", StringUtil.unStudlyName(fname).toUpperCase());
VelocityContext fctx = (VelocityContext)ctx.clone();
fctx.put("field", fname);
fctx.put("capfield", StringUtil.unStudlyName(fname).toUpperCase());
// now generate our bits
if (declared.contains(f)) {
if (fsection.length() > 0) {
fsection.append("\n");
}
fsection.append(mergeTemplate(NAME_TMPL, ctx));
}
if (!isAbstract) {
if (fsection.length() > 0) {
fsection.append("\n");
}
fsection.append(mergeTemplate(COL_TMPL, ctx));
}
fsection.append(mergeTemplate(COL_TMPL, fctx));
}
// generate our methods section
@@ -284,10 +280,6 @@ public class GenRecordTask extends Task
// add a getKey() method, if applicable
if (kflist.size() > 0) {
// create our velocity context
VelocityContext ctx = new VelocityContext();
ctx.put("record", rname);
StringBuilder argList = new StringBuilder();
StringBuilder argNameList = new StringBuilder();
StringBuilder fieldNameList = new StringBuilder();
@@ -470,7 +462,7 @@ public class GenRecordTask extends Task
protected Class<?> _prclass;
/** Specifies the path to the name code template. */
protected static final String NAME_TMPL = "com/samskivert/depot/tools/record_name.tmpl";
protected static final String PROTO_TMPL = "com/samskivert/depot/tools/record_proto.tmpl";
/** Specifies the path to the column code template. */
protected static final String COL_TMPL = "com/samskivert/depot/tools/record_column.tmpl";
@@ -1,3 +1 @@
/** The qualified column identifier for the {@link #$field} field. */
public static final ColumnExp ${capfield}_C =
new ColumnExp(${record}.class, $capfield);
public static final ColumnExp ${capfield} = colexp(_R, "$field");
@@ -6,6 +6,6 @@
{
return new Key<${record}>(
${record}.class,
new String[] { $fieldNameList },
new ColumnExp[] { $fieldNameList },
new Comparable[] { $argNameList });
}
@@ -1,2 +0,0 @@
/** The column identifier for the {@link #$field} field. */
public static final String $capfield = "$field";
@@ -0,0 +1 @@
public static final Class<${record}> _R = ${record}.class;