Modifications to clone() on insertion and extraction from cache, from Zell. A

whole bunch of type safety jockeying and concretification of QueryClause by
yours truly.
This commit is contained in:
Michael Bayne
2007-01-16 05:30:02 +00:00
parent 4f6a334018
commit 180e4626c1
21 changed files with 230 additions and 196 deletions
@@ -65,7 +65,7 @@ public abstract class ConstructedQuery<T>
*
* This method is called by individual clauses.
*/
public String getTableAbbreviation (Class cl)
public String getTableAbbreviation (Class<? extends PersistentRecord> cl)
{
int ix = _classList.indexOf(cl);
if (ix < 0) {
@@ -197,11 +197,13 @@ public abstract class ConstructedQuery<T>
* class, as dictated by the key and query clauses. A persistence context is supplied for
* instantiation of marshallers, which may trigger table creations and schema migrations.
*/
protected ConstructedQuery (PersistenceContext ctx, Class type, QueryClause... clauses)
protected ConstructedQuery (PersistenceContext ctx, Class<? extends PersistentRecord> type,
QueryClause... clauses)
throws PersistenceException
{
_mainType = type;
Set<Class> classSet = new HashSet<Class>();
Set<Class<? extends PersistentRecord>> classSet =
new HashSet<Class<? extends PersistentRecord>>();
if (type != null) {
classSet.add(type);
}
@@ -261,17 +263,17 @@ public abstract class ConstructedQuery<T>
}
_classMap = new HashMap<Class, DepotMarshaller>();
for (Class<?> c : classSet) {
for (Class<? extends PersistentRecord> c : classSet) {
_classMap.put(c, ctx.getMarshaller(c));
}
_classList = new ArrayList<Class>(classSet);
_classList = new ArrayList<Class<? extends PersistentRecord>>(classSet);
}
/** The persistent class to instantiate for the results. */
protected Class _mainType;
protected Class<? extends PersistentRecord> _mainType;
/** A list of referenced classes, used to generate table abbreviations. */
protected List<Class> _classList;
protected List<Class<? extends PersistentRecord>> _classList;
/** Classes mapped to marshallers, used for table names and field lists. */
protected Map<Class, DepotMarshaller> _classMap;
@@ -63,7 +63,7 @@ import static com.samskivert.jdbc.depot.Log.log;
* Handles the marshalling and unmarshalling of persistent instances to JDBC primitives ({@link
* PreparedStatement} and {@link ResultSet}).
*/
public class DepotMarshaller<T>
public class DepotMarshaller<T extends PersistentRecord>
{
/** The name of a private static field that must be defined for all persistent object classes.
* It is used to handle schema migration. If automatic schema migration is not desired, define
@@ -29,9 +29,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import com.samskivert.io.PersistenceException;
import com.samskivert.jdbc.ConnectionProvider;
import com.samskivert.jdbc.JDBCUtil;
@@ -66,7 +63,8 @@ public class DepotRepository
/**
* Loads the persistent object that matches the specified primary key.
*/
protected <T> T load (Class<T> type, Comparable primaryKey, QueryClause... clauses)
protected <T extends PersistentRecord> T load (Class<T> type, Comparable primaryKey,
QueryClause... clauses)
throws PersistenceException
{
clauses = ArrayUtil.append(clauses, _ctx.getMarshaller(type).makePrimaryKey(primaryKey));
@@ -76,7 +74,8 @@ public class DepotRepository
/**
* Loads the persistent object that matches the specified primary key.
*/
protected <T> T load (Class<T> type, String ix, Comparable val, QueryClause... clauses)
protected <T extends PersistentRecord> T load (Class<T> type, String ix, Comparable val,
QueryClause... clauses)
throws PersistenceException
{
clauses = ArrayUtil.append(clauses, new Key<T>(type, ix, val));
@@ -86,8 +85,9 @@ public class DepotRepository
/**
* Loads the persistent object that matches the specified two-column primary key.
*/
protected <T> T load (Class<T> type, String ix1, Comparable val1, String ix2,
Comparable val2, QueryClause... clauses)
protected <T extends PersistentRecord> T load (Class<T> type, String ix1, Comparable val1,
String ix2, Comparable val2,
QueryClause... clauses)
throws PersistenceException
{
clauses = ArrayUtil.append(clauses, new Key<T>(type, ix1, val1, ix2, val2));
@@ -97,8 +97,9 @@ public class DepotRepository
/**
* Loads the persistent object that matches the specified three-column primary key.
*/
protected <T> T load (Class<T> type, String ix1, Comparable val1, String ix2,
Comparable val2, String ix3, Comparable val3, QueryClause... clauses)
protected <T extends PersistentRecord> T load (Class<T> type, String ix1, Comparable val1,
String ix2, Comparable val2, String ix3,
Comparable val3, QueryClause... clauses)
throws PersistenceException
{
clauses = ArrayUtil.append(clauses, new Key<T>(type, ix1, val1, ix2, val2, ix3, val3));
@@ -108,7 +109,7 @@ public class DepotRepository
/**
* Loads the first persistent object that matches the supplied key.
*/
protected <T> T load (Class<T> type, QueryClause... clauses)
protected <T extends PersistentRecord> T load (Class<T> type, QueryClause... clauses)
throws PersistenceException
{
final DepotMarshaller<T> marsh = _ctx.getMarshaller(type);
@@ -130,6 +131,7 @@ public class DepotRepository
}
}
// from Query
public void updateCache (PersistenceContext ctx, T result) {
CacheKey key = getCacheKey();
if (key == null) {
@@ -140,7 +142,18 @@ public class DepotRepository
// if we can, create a key from what was actually returned
key = marsh.getPrimaryKey(result);
}
ctx.cacheStore(key, result);
ctx.cacheStore(key, result != null ? result.clone() : null);
}
// from Query
public T transformCacheHit (CacheKey key, T value)
{
// we do not want to return a reference to the actual cached entity
if (value == null) {
return null;
}
@SuppressWarnings("unchecked") T cvalue = (T) value.clone();
return cvalue;
}
});
}
@@ -148,7 +161,7 @@ public class DepotRepository
/**
* Loads all persistent objects that match the specified key.
*/
protected <T,C extends Collection<T>> Collection<T> findAll (
protected <T extends PersistentRecord, C extends Collection<T>> Collection<T> findAll (
Class<T> type, QueryClause... clauses)
throws PersistenceException
{
@@ -169,13 +182,33 @@ public class DepotRepository
}
}
// from Query
public void updateCache (PersistenceContext ctx, ArrayList<T> result) {
if (marsh.hasPrimaryKey()) {
for (T bit : result) {
ctx.cacheStore(marsh.getPrimaryKey(bit), bit);
ctx.cacheStore(marsh.getPrimaryKey(bit), bit.clone());
}
}
}
// from Query
public ArrayList<T> transformCacheHit (CacheKey key, ArrayList<T> bits)
{
if (bits == null) {
return bits;
}
ArrayList<T> result = new ArrayList<T>();
for (T bit : bits) {
if (bit != null) {
@SuppressWarnings("unchecked") T cbit = (T) bit.clone();
result.add(cbit);
} else {
result.add(null);
}
}
return result;
}
});
}
@@ -185,7 +218,7 @@ public class DepotRepository
*
* @return the number of rows modified by this action, this should always be one.
*/
protected <T> int insert (final T record)
protected <T extends PersistentRecord> int insert (T record)
throws PersistenceException
{
final DepotMarshaller marsh = _ctx.getMarshaller(record.getClass());
@@ -194,12 +227,12 @@ public class DepotRepository
return _ctx.invoke(new CachingModifier<T>(record, key, key) {
public int invoke (Connection conn) throws SQLException {
// update our modifier's key so that it can cache our results
updateKey(marsh.assignPrimaryKey(conn, record, false));
PreparedStatement stmt = marsh.createInsert(conn, record);
updateKey(marsh.assignPrimaryKey(conn, _result, false));
PreparedStatement stmt = marsh.createInsert(conn, _result);
try {
int mods = stmt.executeUpdate();
// check again in case we have a post-factum key generator
updateKey(marsh.assignPrimaryKey(conn, record, true));
updateKey(marsh.assignPrimaryKey(conn, _result, true));
return mods;
} finally {
JDBCUtil.close(stmt);
@@ -214,7 +247,7 @@ public class DepotRepository
*
* @return the number of rows modified by this action.
*/
protected <T> int update (final T record)
protected <T extends PersistentRecord> int update (T record)
throws PersistenceException
{
final DepotMarshaller marsh = _ctx.getMarshaller(record.getClass());
@@ -224,7 +257,7 @@ public class DepotRepository
}
return _ctx.invoke(new CachingModifier<T>(record, key, key) {
public int invoke (Connection conn) throws SQLException {
PreparedStatement stmt = marsh.createUpdate(conn, record, key);
PreparedStatement stmt = marsh.createUpdate(conn, _result, key);
try {
return stmt.executeUpdate();
} finally {
@@ -240,7 +273,7 @@ public class DepotRepository
*
* @return the number of rows modified by this action.
*/
protected <T> int update (final T record, final String... modifiedFields)
protected <T extends PersistentRecord> int update (T record, final String... modifiedFields)
throws PersistenceException
{
final DepotMarshaller marsh = _ctx.getMarshaller(record.getClass());
@@ -250,7 +283,7 @@ public class DepotRepository
}
return _ctx.invoke(new CachingModifier<T>(record, key, key) {
public int invoke (Connection conn) throws SQLException {
PreparedStatement stmt = marsh.createUpdate(conn, record, key, modifiedFields);
PreparedStatement stmt = marsh.createUpdate(conn, _result, key, modifiedFields);
try {
return stmt.executeUpdate();
} finally {
@@ -270,8 +303,8 @@ public class DepotRepository
*
* @return the number of rows modified by this action.
*/
protected <T> int updatePartial (Class<T> type, Comparable primaryKey,
Map<String,Object> updates)
protected <T extends PersistentRecord> int updatePartial (
Class<T> type, Comparable primaryKey, Map<String,Object> updates)
throws PersistenceException
{
Object[] fieldsValues = new Object[updates.size()*2];
@@ -293,7 +326,8 @@ public class DepotRepository
*
* @return the number of rows modified by this action.
*/
protected <T> int updatePartial (Class<T> type, Comparable primaryKey, Object... fieldsValues)
protected <T extends PersistentRecord> int updatePartial (
Class<T> type, Comparable primaryKey, Object... fieldsValues)
throws PersistenceException
{
Key<T> key = _ctx.getMarshaller(type).makePrimaryKey(primaryKey);
@@ -312,8 +346,8 @@ public class DepotRepository
*
* @return the number of rows modified by this action.
*/
protected <T> int updatePartial (Class<T> type, final Where key, CacheInvalidator invalidator,
Object... fieldsValues)
protected <T extends PersistentRecord> int updatePartial (
Class<T> type, final Where key, CacheInvalidator invalidator, Object... fieldsValues)
throws PersistenceException
{
// separate the arguments into keys and values
@@ -354,7 +388,8 @@ public class DepotRepository
*
* @return the number of rows modified by this action.
*/
protected <T> int updateLiteral (Class<T> type, Comparable primaryKey, String... fieldsValues)
protected <T extends PersistentRecord> int updateLiteral (
Class<T> type, Comparable primaryKey, String... fieldsValues)
throws PersistenceException
{
Key<T> key = _ctx.getMarshaller(type).makePrimaryKey(primaryKey);
@@ -378,8 +413,8 @@ public class DepotRepository
*
* @return the number of rows modified by this action.
*/
protected <T> int updateLiteral (Class<T> type, final Where key, CacheInvalidator invalidator,
String... fieldsValues)
protected <T extends PersistentRecord> int updateLiteral (
Class<T> type, final Where key, CacheInvalidator invalidator, String... fieldsValues)
throws PersistenceException
{
// separate the arguments into keys and values
@@ -410,7 +445,7 @@ public class DepotRepository
*
* @return the number of rows modified by this action, this should always be one.
*/
protected <T> int store (final T record)
protected <T extends PersistentRecord> int store (T record)
throws PersistenceException
{
final DepotMarshaller marsh = _ctx.getMarshaller(record.getClass());
@@ -422,7 +457,7 @@ public class DepotRepository
// if our primary key isn't null, update rather than insert the record
// before been persisted and insert
if (key != null) {
stmt = marsh.createUpdate(conn, record, key);
stmt = marsh.createUpdate(conn, _result, key);
int mods = stmt.executeUpdate();
if (mods > 0) {
return mods;
@@ -432,10 +467,10 @@ public class DepotRepository
// if the update modified zero rows or the primary key was obviously unset, do
// an insertion
updateKey(marsh.assignPrimaryKey(conn, record, false));
stmt = marsh.createInsert(conn, record);
updateKey(marsh.assignPrimaryKey(conn, _result, false));
stmt = marsh.createInsert(conn, _result);
int mods = stmt.executeUpdate();
updateKey(marsh.assignPrimaryKey(conn, record, true));
updateKey(marsh.assignPrimaryKey(conn, _result, true));
return mods;
} finally {
@@ -451,7 +486,7 @@ public class DepotRepository
*
* @return the number of rows deleted by this action.
*/
protected <T> int delete (T record)
protected <T extends PersistentRecord> int delete (T record)
throws PersistenceException
{
@SuppressWarnings("unchecked") Class<T> type = (Class<T>)record.getClass();
@@ -468,7 +503,7 @@ public class DepotRepository
*
* @return the number of rows deleted by this action.
*/
protected <T> int delete (Class<T> type, Comparable primaryKeyValue)
protected <T extends PersistentRecord> int delete (Class<T> type, Comparable primaryKeyValue)
throws PersistenceException
{
Key<T> primaryKey = _ctx.getMarshaller(type).makePrimaryKey(primaryKeyValue);
@@ -480,7 +515,8 @@ public class DepotRepository
*
* @return the number of rows deleted by this action.
*/
protected <T> int deleteAll (Class<T> type, final Where key, CacheInvalidator invalidator)
protected <T extends PersistentRecord> int deleteAll (
Class<T> type, final Where key, CacheInvalidator invalidator)
throws PersistenceException
{
final DepotMarshaller marsh = _ctx.getMarshaller(type);
+9 -6
View File
@@ -23,9 +23,9 @@ package com.samskivert.jdbc.depot;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.samskivert.jdbc.depot.clause.Where;
@@ -37,7 +37,7 @@ import com.samskivert.jdbc.depot.clause.Where;
* itself upon modification. This class is created by many {@link DepotMarshaller} methods as
* a convenience, and may also be instantiated explicitly.
*/
public class Key<T> extends Where
public class Key<T extends PersistentRecord> extends Where
implements CacheKey, CacheInvalidator
{
/**
@@ -94,13 +94,16 @@ public class Key<T> extends Where
}
// from QueryClause
public List<Class> getClassSet()
public Collection<Class<? extends PersistentRecord>> getClassSet ()
{
return Arrays.asList(new Class[] { _pClass });
ArrayList<Class<? extends PersistentRecord>> set =
new ArrayList<Class<? extends PersistentRecord>>();
set.add(_pClass);
return set;
}
// from QueryClause
public void appendClause (ConstructedQuery query, StringBuilder builder)
public void appendClause (ConstructedQuery<?> query, StringBuilder builder)
{
builder.append(" where ");
boolean first = true;
@@ -59,7 +59,7 @@ public abstract class Modifier
* presuming both _key and _result are non-null. These variables may be set or modified
* during execution in addition to being supplied to the constructor.
*/
public static abstract class CachingModifier<T> extends Modifier
public static abstract class CachingModifier<T extends PersistentRecord> extends Modifier
{
/**
* Construct a new CachingModifier with the given result, cache key, and invalidator,
@@ -89,7 +89,7 @@ public abstract class Modifier
super.cacheUpdate(ctx);
// if we have both a key and a record, cache
if (_key != null && _result != null) {
ctx.cacheStore(_key, _result);
ctx.cacheStore(_key, _result.clone());
}
}
@@ -22,9 +22,9 @@ package com.samskivert.jdbc.depot;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.samskivert.jdbc.depot.clause.Where;
@@ -34,7 +34,7 @@ import com.samskivert.jdbc.depot.clause.Where;
* does not implement {@link CacheKey} but it does implement {@link CacheInvalidator} which means
* it can be sent into e.g. {@link DepotRepository#deleteAll) and have it clean up after itself.
*/
public class MultiKey<T> extends Where
public class MultiKey<T extends PersistentRecord> extends Where
implements CacheInvalidator
{
/**
@@ -85,13 +85,16 @@ public class MultiKey<T> extends Where
}
// from QueryClause
public List<Class> getClassSet()
public Collection<Class<? extends PersistentRecord>> getClassSet ()
{
return Arrays.asList(new Class[] { _pClass });
ArrayList<Class<? extends PersistentRecord>> set =
new ArrayList<Class<? extends PersistentRecord>>();
set.add(_pClass);
return set;
}
// from QueryClause
public void appendClause (ConstructedQuery query, StringBuilder builder)
public void appendClause (ConstructedQuery<?> query, StringBuilder builder)
{
builder.append(" where ");
boolean first = true;
@@ -140,7 +140,7 @@ public class PersistenceContext
* and register a pre-migration for every single schema migration and they will then be
* guaranteed to be run in registration order and with predictable pre- and post-conditions.
*/
public <T> void registerMigration (Class<T> type, EntityMigration migration)
public <T extends PersistentRecord> void registerMigration (Class<T> type, EntityMigration migration)
{
getRawMarshaller(type).registerMigration(migration);
}
@@ -149,7 +149,7 @@ public class PersistenceContext
* Returns the marshaller for the specified persistent object class, creating and initializing
* it if necessary.
*/
public <T> DepotMarshaller<T> getMarshaller (Class<T> type)
public <T extends PersistentRecord> DepotMarshaller<T> getMarshaller (Class<T> type)
throws PersistenceException
{
DepotMarshaller<T> marshaller = getRawMarshaller(type);
@@ -176,7 +176,11 @@ public class PersistenceContext
if (cacheHit != null) {
Log.debug("invoke: cache hit [hit=" + cacheHit + "]");
@SuppressWarnings("unchecked") T value = (T) cacheHit.getValue();
return value;
value = query.transformCacheHit(key, value);
if (value != null) {
return value;
}
Log.debug("invoke: transformCacheHit returned null; rejecting cached value.");
}
}
Log.debug("invoke: cache miss [key=" + key + "]");
@@ -337,7 +341,7 @@ public class PersistenceContext
* Looks up and creates, but does not initialize, the marshaller for the specified Entity
* type.
*/
protected <T> DepotMarshaller<T> getRawMarshaller (Class<T> type)
protected <T extends PersistentRecord> DepotMarshaller<T> getRawMarshaller (Class<T> type)
{
@SuppressWarnings("unchecked") DepotMarshaller<T> marshaller =
(DepotMarshaller<T>)_marshallers.get(type);
@@ -0,0 +1,41 @@
//
// $Id$
//
// samskivert library - useful routines for java programs
// Copyright (C) 2007 Michael Bayne, 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
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.jdbc.depot;
import java.io.Serializable;
/**
* 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.
*/
public class PersistentRecord
implements Cloneable, Serializable
{
@Override // from Object
public PersistentRecord clone ()
{
try {
return (PersistentRecord) super.clone();
} catch (CloneNotSupportedException cnse) {
throw new RuntimeException(cnse); // this should never happen
}
}
}
@@ -38,9 +38,15 @@ public interface Query<T>
*/
public T invoke (Connection conn)
throws SQLException;
/**
* Overriden by subclasses to perform special operations when the query would return a cache
* hit. The value may be mutated, modified, or null may be return to force a database hit.
*/
public T transformCacheHit (CacheKey key, T value);
/**
* Overriden by subclasses to perform case-by-case cache updates.
*/
void updateCache (PersistenceContext ctx, T result);
public void updateCache (PersistenceContext ctx, T result);
}
@@ -20,12 +20,9 @@
package com.samskivert.jdbc.depot.clause;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import com.samskivert.io.PersistenceException;
import com.samskivert.jdbc.depot.ConstructedQuery;
import com.samskivert.jdbc.depot.PersistentRecord;
import com.samskivert.jdbc.depot.expression.ColumnExp;
import com.samskivert.jdbc.depot.expression.LiteralExp;
import com.samskivert.jdbc.depot.expression.SQLExpression;
@@ -38,8 +35,7 @@ import com.samskivert.jdbc.depot.expression.SQLExpression;
* table through a {@link ColumnExp}, or a literal expression such as COUNT(*) through a
* {@link LiteralExp}.
*/
public class FieldOverride
implements QueryClause
public class FieldOverride extends QueryClause
{
public FieldOverride (String field, String str)
throws PersistenceException
@@ -47,7 +43,7 @@ public class FieldOverride
this(field, new LiteralExp(str));
}
public FieldOverride (String field, Class pClass, String pCol)
public FieldOverride (String field, Class<? extends PersistentRecord> pClass, String pCol)
throws PersistenceException
{
this(field, new ColumnExp(pClass, pCol));
@@ -69,25 +65,12 @@ public class FieldOverride
}
// from QueryClause
public Collection<Class> getClassSet ()
{
return null;
}
// from QueryClause
public void appendClause (ConstructedQuery query, StringBuilder builder)
public void appendClause (ConstructedQuery<?> query, StringBuilder builder)
{
_override.appendExpression(query, builder);
builder.append(" as ").append(_field);
}
// from QueryClause
public int bindArguments (PreparedStatement pstmt, int argIdx)
throws SQLException
{
return argIdx;
}
/** The name of the field on the persistent object to override. */
protected String _field;
@@ -20,34 +20,16 @@
package com.samskivert.jdbc.depot.clause;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import com.samskivert.jdbc.depot.ConstructedQuery;
/**
* Represents a FOR UPDATE clause.
*/
public class ForUpdate
implements QueryClause
public class ForUpdate extends QueryClause
{
// from QueryClause
public Collection<Class> getClassSet ()
{
return null;
}
// from QueryClause
public void appendClause (ConstructedQuery query, StringBuilder builder)
public void appendClause (ConstructedQuery<?> query, StringBuilder builder)
{
builder.append(" for update ");
}
// from QueryClause
public int bindArguments (PreparedStatement pstmt, int argIdx)
throws SQLException
{
return argIdx;
}
}
@@ -20,53 +20,45 @@
package com.samskivert.jdbc.depot.clause;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import com.samskivert.io.PersistenceException;
import com.samskivert.jdbc.depot.ConstructedQuery;
import com.samskivert.jdbc.depot.PersistentRecord;
import com.samskivert.util.CollectionUtil;
/**
* Completely overrides the FROM clause, if it exists.
*/
public class FromOverride
implements QueryClause
public class FromOverride extends QueryClause
{
public FromOverride (Class... fromClasses)
public FromOverride (Class<? extends PersistentRecord>... fromClasses)
throws PersistenceException
{
_fromClasses = fromClasses;
CollectionUtil.addAll(_fromClasses, fromClasses);
}
// from QueryClause
public Collection<Class> getClassSet ()
public Collection<Class<? extends PersistentRecord>> getClassSet ()
{
return Arrays.asList(_fromClasses);
return _fromClasses;
}
// from QueryClause
public void appendClause (ConstructedQuery query, StringBuilder builder)
public void appendClause (ConstructedQuery<?> query, StringBuilder builder)
{
builder.append(" from " );
for (int ii = 0; ii < _fromClasses.length; ii++) {
for (int ii = 0; ii < _fromClasses.size(); ii++) {
if (ii > 0) {
builder.append(", ");
}
builder.append(query.getTableName(_fromClasses[ii])).
append(" as ").
append(query.getTableAbbreviation(_fromClasses[ii]));
builder.append(query.getTableName(_fromClasses.get(ii))).
append(" as ").append(query.getTableAbbreviation(_fromClasses.get(ii)));
}
}
// from QueryClause
public int bindArguments (PreparedStatement pstmt, int argIdx)
throws SQLException
{
return argIdx;
}
/** The classes of the tables we're selecting from. */
protected Class[] _fromClasses;
protected ArrayList<Class<? extends PersistentRecord>> _fromClasses =
new ArrayList<Class<? extends PersistentRecord>>();
}
@@ -22,7 +22,6 @@ package com.samskivert.jdbc.depot.clause;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import com.samskivert.jdbc.depot.ConstructedQuery;
import com.samskivert.jdbc.depot.expression.SQLExpression;
@@ -30,8 +29,7 @@ import com.samskivert.jdbc.depot.expression.SQLExpression;
/**
* Represents a GROUP BY clause.
*/
public class GroupBy
implements QueryClause
public class GroupBy extends QueryClause
{
public GroupBy (SQLExpression... values)
{
@@ -39,13 +37,7 @@ public class GroupBy
}
// from QueryClause
public Collection<Class> getClassSet ()
{
return null;
}
// from QueryClause
public void appendClause (ConstructedQuery query, StringBuilder builder)
public void appendClause (ConstructedQuery<?> query, StringBuilder builder)
{
builder.append(" group by ");
for (int ii = 0; ii < _values.length; ii++) {
@@ -22,22 +22,23 @@ package com.samskivert.jdbc.depot.clause;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import com.samskivert.io.PersistenceException;
import com.samskivert.jdbc.depot.ConstructedQuery;
import com.samskivert.jdbc.depot.PersistentRecord;
import com.samskivert.jdbc.depot.expression.ColumnExp;
import com.samskivert.jdbc.depot.operator.SQLOperator;
import com.samskivert.jdbc.depot.operator.Conditionals.*;
import com.samskivert.jdbc.depot.operator.SQLOperator;
/**
* Represents a JOIN -- currently just an INNER one.
*/
public class Join
implements QueryClause
public class Join extends QueryClause
{
public Join (Class pClass, String pCol, Class joinClass, String jCol)
public Join (Class<? extends PersistentRecord> pClass, String pCol,
Class<? extends PersistentRecord> joinClass, String jCol)
throws PersistenceException
{
_joinClass = joinClass;
@@ -51,20 +52,23 @@ public class Join
_joinCondition = new Equals(primary, join);
}
public Join (Class joinClass, SQLOperator joinCondition)
public Join (Class<? extends PersistentRecord> joinClass, SQLOperator joinCondition)
{
_joinClass = joinClass;
_joinCondition = joinCondition;
}
// from QueryClause
public Collection<Class> getClassSet ()
public Collection<Class<? extends PersistentRecord>> getClassSet ()
{
return Arrays.asList(new Class[] { _joinClass });
ArrayList<Class<? extends PersistentRecord>> set =
new ArrayList<Class<? extends PersistentRecord>>();
set.add(_joinClass);
return set;
}
// from QueryClause
public void appendClause (ConstructedQuery query, StringBuilder builder)
public void appendClause (ConstructedQuery<?> query, StringBuilder builder)
{
builder.append(" inner join " );
builder.append(query.getTableName(_joinClass)).append(" as ");
@@ -80,7 +84,7 @@ public class Join
}
/** The class of the table we're to join against. */
protected Class _joinClass;
protected Class<? extends PersistentRecord> _joinClass;
/** The condition used to join in the new table. */
protected SQLOperator _joinCondition;
@@ -22,15 +22,13 @@ package com.samskivert.jdbc.depot.clause;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import com.samskivert.jdbc.depot.ConstructedQuery;
/**
* Represents a LIMIT/OFFSET clause, for pagination.
*/
public class Limit
implements QueryClause
public class Limit extends QueryClause
{
public Limit (int offset, int count)
{
@@ -39,13 +37,7 @@ public class Limit
}
// from QueryClause
public Collection<Class> getClassSet ()
{
return null;
}
// from QueryClause
public void appendClause (ConstructedQuery query, StringBuilder builder)
public void appendClause (ConstructedQuery<?> query, StringBuilder builder)
{
builder.append(" limit ? offset ? ");
}
@@ -22,7 +22,6 @@ package com.samskivert.jdbc.depot.clause;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import com.samskivert.jdbc.depot.ConstructedQuery;
import com.samskivert.jdbc.depot.expression.ColumnExp;
@@ -31,8 +30,7 @@ import com.samskivert.jdbc.depot.expression.SQLExpression;
/**
* Represents an ORDER BY clause.
*/
public class OrderBy
implements QueryClause
public class OrderBy extends QueryClause
{
/** Indicates the order of the clause. */
public enum Order { ASC, DESC };
@@ -76,13 +74,7 @@ public class OrderBy
}
// from QueryClause
public Collection<Class> getClassSet ()
{
return null;
}
// from QueryClause
public void appendClause (ConstructedQuery query, StringBuilder builder)
public void appendClause (ConstructedQuery<?> query, StringBuilder builder)
{
builder.append(" order by ");
for (int ii = 0; ii < _values.length; ii++) {
@@ -25,29 +25,36 @@ import java.sql.SQLException;
import java.util.Collection;
import com.samskivert.jdbc.depot.ConstructedQuery;
import com.samskivert.jdbc.depot.PersistentRecord;
/**
* Represents a piece or modifier of an SQL query.
*/
public interface QueryClause
public abstract class QueryClause
{
/**
* Return a set of all persistent classes referenced by this clause. Null may be returned if
* no classes are rererenced.
* Return a set of all persistent classes referenced by this clause. The default implementation
* returns null to indicate that no classes are rererenced.
*/
public Collection<Class> getClassSet ();
public Collection<Class<? extends PersistentRecord>> getClassSet ()
{
return null;
}
/**
* Construct the SQL form of this query clause. The implementor is expected to call methods
* on the Query object to e.g. resolve current table abbreviations associated with classes.
* Construct the SQL form of this query clause. The implementor is expected to call methods on
* the Query object to e.g. resolve current table abbreviations associated with classes.
*/
public void appendClause (ConstructedQuery query, StringBuilder builder);
public abstract void appendClause (ConstructedQuery<?> query, StringBuilder builder);
/**
* Bind any objects that were referenced in the generated SQL. For each ? that appears in the
* SQL, precisely one parameter must be claimed and bound in this method, and argIdx
* incremented and returned.
* incremented and returned. The default implementation binds nothing.
*/
public int bindArguments (PreparedStatement pstmt, int argIdx)
throws SQLException;
throws SQLException
{
return argIdx;
}
}
@@ -22,24 +22,22 @@ package com.samskivert.jdbc.depot.clause;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import com.samskivert.jdbc.depot.ConstructedQuery;
import com.samskivert.jdbc.depot.PersistentRecord;
import com.samskivert.jdbc.depot.clause.QueryClause;
import com.samskivert.jdbc.depot.expression.ColumnExp;
import com.samskivert.jdbc.depot.expression.ValueExp;
import com.samskivert.jdbc.depot.operator.SQLOperator;
import com.samskivert.jdbc.depot.operator.Conditionals.Equals;
import com.samskivert.jdbc.depot.operator.Conditionals.IsNull;
import com.samskivert.jdbc.depot.operator.Logic.And;
import com.samskivert.jdbc.depot.operator.SQLOperator;
/**
* Represents a where clause: the condition can be any comparison operator or logical combination
* thereof.
*/
public class Where
implements QueryClause
public class Where extends QueryClause
{
public Where (String index, Comparable value)
{
@@ -88,13 +86,7 @@ public class Where
}
// from QueryClause
public List<Class> getClassSet()
{
return Arrays.asList(new Class[] { });
}
// from QueryClause
public void appendClause (ConstructedQuery query, StringBuilder builder)
public void appendClause (ConstructedQuery<?> query, StringBuilder builder)
{
builder.append(" where ");
_condition.appendExpression(query, builder);
@@ -24,6 +24,7 @@ import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.samskivert.jdbc.depot.ConstructedQuery;
import com.samskivert.jdbc.depot.PersistentRecord;
/**
* An expression identifying a column of a class, e.g. GameRecord.itemId. If no class is given,
@@ -33,7 +34,7 @@ public class ColumnExp
implements SQLExpression
{
/** The table that hosts the column we reference, or null. */
final public Class pClass;
final public Class<? extends PersistentRecord> pClass;
/** The name of the column we reference. */
final public String pColumn;
@@ -43,7 +44,7 @@ public class ColumnExp
this(null, column);
}
public ColumnExp (Class c, String column)
public ColumnExp (Class<? extends PersistentRecord> c, String column)
{
super();
pClass = c;
@@ -51,7 +52,7 @@ public class ColumnExp
}
// from SQLExpression
public void appendExpression (ConstructedQuery query, StringBuilder builder)
public void appendExpression (ConstructedQuery<?> query, StringBuilder builder)
{
if (pClass == null || query == null) {
builder.append(pColumn);
@@ -34,7 +34,7 @@ public interface SQLExpression
* Construct the SQL form of this expression. The implementor is invited to call methods on the
* Query object to e.g. resolve the current table abbreviations associated with classes.
*/
public void appendExpression (ConstructedQuery query, StringBuilder builder);
public void appendExpression (ConstructedQuery<?> query, StringBuilder builder);
/**
* Bind any objects that were referenced in the generated SQL. For each ? that appears in the
@@ -25,6 +25,7 @@ import java.sql.SQLException;
import java.util.Collection;
import com.samskivert.jdbc.depot.ConstructedQuery;
import com.samskivert.jdbc.depot.PersistentRecord;
import com.samskivert.jdbc.depot.expression.ColumnExp;
import com.samskivert.jdbc.depot.expression.SQLExpression;
import com.samskivert.jdbc.depot.operator.SQLOperator.BinaryOperator;
@@ -45,7 +46,7 @@ public abstract class Conditionals
this(new ColumnExp(null, pColumn));
}
public IsNull (Class pClass, String pColumn)
public IsNull (Class<? extends PersistentRecord> pClass, String pColumn)
{
this(new ColumnExp(pClass, pColumn));
}
@@ -161,12 +162,13 @@ public abstract class Conditionals
this(new ColumnExp(null, pColumn), values.toArray(new Comparable[values.size()]));
}
public In (Class pClass, String pColumn, Comparable... values)
public In (Class<? extends PersistentRecord> pClass, String pColumn, Comparable... values)
{
this(new ColumnExp(pClass, pColumn), values);
}
public In (Class pClass, String pColumn, Collection<? extends Comparable> values)
public In (Class<? extends PersistentRecord> pClass, String pColumn,
Collection<? extends Comparable> values)
{
this(new ColumnExp(pClass, pColumn), values.toArray(new Comparable[values.size()]));
}