diff --git a/src/java/com/samskivert/jdbc/depot/ConstructedQuery.java b/src/java/com/samskivert/jdbc/depot/ConstructedQuery.java index ee8061c..6697da4 100644 --- a/src/java/com/samskivert/jdbc/depot/ConstructedQuery.java +++ b/src/java/com/samskivert/jdbc/depot/ConstructedQuery.java @@ -65,7 +65,7 @@ public abstract class ConstructedQuery * * This method is called by individual clauses. */ - public String getTableAbbreviation (Class cl) + public String getTableAbbreviation (Class cl) { int ix = _classList.indexOf(cl); if (ix < 0) { @@ -197,11 +197,13 @@ public abstract class ConstructedQuery * 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 type, + QueryClause... clauses) throws PersistenceException { _mainType = type; - Set classSet = new HashSet(); + Set> classSet = + new HashSet>(); if (type != null) { classSet.add(type); } @@ -261,17 +263,17 @@ public abstract class ConstructedQuery } _classMap = new HashMap(); - for (Class c : classSet) { + for (Class c : classSet) { _classMap.put(c, ctx.getMarshaller(c)); } - _classList = new ArrayList(classSet); + _classList = new ArrayList>(classSet); } /** The persistent class to instantiate for the results. */ - protected Class _mainType; + protected Class _mainType; /** A list of referenced classes, used to generate table abbreviations. */ - protected List _classList; + protected List> _classList; /** Classes mapped to marshallers, used for table names and field lists. */ protected Map _classMap; diff --git a/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java b/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java index 1206d89..105efab 100644 --- a/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java +++ b/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java @@ -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 +public class DepotMarshaller { /** 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 diff --git a/src/java/com/samskivert/jdbc/depot/DepotRepository.java b/src/java/com/samskivert/jdbc/depot/DepotRepository.java index 5b62109..e7e7b35 100644 --- a/src/java/com/samskivert/jdbc/depot/DepotRepository.java +++ b/src/java/com/samskivert/jdbc/depot/DepotRepository.java @@ -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 load (Class type, Comparable primaryKey, QueryClause... clauses) + protected T load (Class 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 load (Class type, String ix, Comparable val, QueryClause... clauses) + protected T load (Class type, String ix, Comparable val, + QueryClause... clauses) throws PersistenceException { clauses = ArrayUtil.append(clauses, new Key(type, ix, val)); @@ -86,8 +85,9 @@ public class DepotRepository /** * Loads the persistent object that matches the specified two-column primary key. */ - protected T load (Class type, String ix1, Comparable val1, String ix2, - Comparable val2, QueryClause... clauses) + protected T load (Class type, String ix1, Comparable val1, + String ix2, Comparable val2, + QueryClause... clauses) throws PersistenceException { clauses = ArrayUtil.append(clauses, new Key(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 load (Class type, String ix1, Comparable val1, String ix2, - Comparable val2, String ix3, Comparable val3, QueryClause... clauses) + protected T load (Class type, String ix1, Comparable val1, + String ix2, Comparable val2, String ix3, + Comparable val3, QueryClause... clauses) throws PersistenceException { clauses = ArrayUtil.append(clauses, new Key(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 load (Class type, QueryClause... clauses) + protected T load (Class type, QueryClause... clauses) throws PersistenceException { final DepotMarshaller 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 > Collection findAll ( + protected > Collection findAll ( Class type, QueryClause... clauses) throws PersistenceException { @@ -169,13 +182,33 @@ public class DepotRepository } } + // from Query public void updateCache (PersistenceContext ctx, ArrayList 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 transformCacheHit (CacheKey key, ArrayList bits) + { + if (bits == null) { + return bits; + } + + ArrayList result = new ArrayList(); + 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 int insert (final T record) + protected 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(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 int update (final T record) + protected 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(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 int update (final T record, final String... modifiedFields) + protected 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(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 int updatePartial (Class type, Comparable primaryKey, - Map updates) + protected int updatePartial ( + Class type, Comparable primaryKey, Map 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 int updatePartial (Class type, Comparable primaryKey, Object... fieldsValues) + protected int updatePartial ( + Class type, Comparable primaryKey, Object... fieldsValues) throws PersistenceException { Key key = _ctx.getMarshaller(type).makePrimaryKey(primaryKey); @@ -312,8 +346,8 @@ public class DepotRepository * * @return the number of rows modified by this action. */ - protected int updatePartial (Class type, final Where key, CacheInvalidator invalidator, - Object... fieldsValues) + protected int updatePartial ( + Class 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 int updateLiteral (Class type, Comparable primaryKey, String... fieldsValues) + protected int updateLiteral ( + Class type, Comparable primaryKey, String... fieldsValues) throws PersistenceException { Key key = _ctx.getMarshaller(type).makePrimaryKey(primaryKey); @@ -378,8 +413,8 @@ public class DepotRepository * * @return the number of rows modified by this action. */ - protected int updateLiteral (Class type, final Where key, CacheInvalidator invalidator, - String... fieldsValues) + protected int updateLiteral ( + Class 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 int store (final T record) + protected 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 int delete (T record) + protected int delete (T record) throws PersistenceException { @SuppressWarnings("unchecked") Class type = (Class)record.getClass(); @@ -468,7 +503,7 @@ public class DepotRepository * * @return the number of rows deleted by this action. */ - protected int delete (Class type, Comparable primaryKeyValue) + protected int delete (Class type, Comparable primaryKeyValue) throws PersistenceException { Key primaryKey = _ctx.getMarshaller(type).makePrimaryKey(primaryKeyValue); @@ -480,7 +515,8 @@ public class DepotRepository * * @return the number of rows deleted by this action. */ - protected int deleteAll (Class type, final Where key, CacheInvalidator invalidator) + protected int deleteAll ( + Class type, final Where key, CacheInvalidator invalidator) throws PersistenceException { final DepotMarshaller marsh = _ctx.getMarshaller(type); diff --git a/src/java/com/samskivert/jdbc/depot/Key.java b/src/java/com/samskivert/jdbc/depot/Key.java index 7f63490..66d07b8 100644 --- a/src/java/com/samskivert/jdbc/depot/Key.java +++ b/src/java/com/samskivert/jdbc/depot/Key.java @@ -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 extends Where +public class Key extends Where implements CacheKey, CacheInvalidator { /** @@ -94,13 +94,16 @@ public class Key extends Where } // from QueryClause - public List getClassSet() + public Collection> getClassSet () { - return Arrays.asList(new Class[] { _pClass }); + ArrayList> set = + new ArrayList>(); + 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; diff --git a/src/java/com/samskivert/jdbc/depot/Modifier.java b/src/java/com/samskivert/jdbc/depot/Modifier.java index 317ff26..530a091 100644 --- a/src/java/com/samskivert/jdbc/depot/Modifier.java +++ b/src/java/com/samskivert/jdbc/depot/Modifier.java @@ -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 extends Modifier + public static abstract class CachingModifier 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()); } } diff --git a/src/java/com/samskivert/jdbc/depot/MultiKey.java b/src/java/com/samskivert/jdbc/depot/MultiKey.java index 0176d84..8f226be 100644 --- a/src/java/com/samskivert/jdbc/depot/MultiKey.java +++ b/src/java/com/samskivert/jdbc/depot/MultiKey.java @@ -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 extends Where +public class MultiKey extends Where implements CacheInvalidator { /** @@ -85,13 +85,16 @@ public class MultiKey extends Where } // from QueryClause - public List getClassSet() + public Collection> getClassSet () { - return Arrays.asList(new Class[] { _pClass }); + ArrayList> set = + new ArrayList>(); + 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; diff --git a/src/java/com/samskivert/jdbc/depot/PersistenceContext.java b/src/java/com/samskivert/jdbc/depot/PersistenceContext.java index 92b56fc..64107eb 100644 --- a/src/java/com/samskivert/jdbc/depot/PersistenceContext.java +++ b/src/java/com/samskivert/jdbc/depot/PersistenceContext.java @@ -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 void registerMigration (Class type, EntityMigration migration) + public void registerMigration (Class 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 DepotMarshaller getMarshaller (Class type) + public DepotMarshaller getMarshaller (Class type) throws PersistenceException { DepotMarshaller 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 DepotMarshaller getRawMarshaller (Class type) + protected DepotMarshaller getRawMarshaller (Class type) { @SuppressWarnings("unchecked") DepotMarshaller marshaller = (DepotMarshaller)_marshallers.get(type); diff --git a/src/java/com/samskivert/jdbc/depot/PersistentRecord.java b/src/java/com/samskivert/jdbc/depot/PersistentRecord.java new file mode 100644 index 0000000..4c844c1 --- /dev/null +++ b/src/java/com/samskivert/jdbc/depot/PersistentRecord.java @@ -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 + } + } +} diff --git a/src/java/com/samskivert/jdbc/depot/Query.java b/src/java/com/samskivert/jdbc/depot/Query.java index 58b8cc5..83b95d3 100644 --- a/src/java/com/samskivert/jdbc/depot/Query.java +++ b/src/java/com/samskivert/jdbc/depot/Query.java @@ -38,9 +38,15 @@ public interface Query */ 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); } diff --git a/src/java/com/samskivert/jdbc/depot/clause/FieldOverride.java b/src/java/com/samskivert/jdbc/depot/clause/FieldOverride.java index ef04dcf..565c14a 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/FieldOverride.java +++ b/src/java/com/samskivert/jdbc/depot/clause/FieldOverride.java @@ -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 pClass, String pCol) throws PersistenceException { this(field, new ColumnExp(pClass, pCol)); @@ -69,25 +65,12 @@ public class FieldOverride } // from QueryClause - public Collection 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; diff --git a/src/java/com/samskivert/jdbc/depot/clause/ForUpdate.java b/src/java/com/samskivert/jdbc/depot/clause/ForUpdate.java index 20972ed..d8289f0 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/ForUpdate.java +++ b/src/java/com/samskivert/jdbc/depot/clause/ForUpdate.java @@ -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 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; - } } diff --git a/src/java/com/samskivert/jdbc/depot/clause/FromOverride.java b/src/java/com/samskivert/jdbc/depot/clause/FromOverride.java index f9a1366..dd67d96 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/FromOverride.java +++ b/src/java/com/samskivert/jdbc/depot/clause/FromOverride.java @@ -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... fromClasses) throws PersistenceException { - _fromClasses = fromClasses; + CollectionUtil.addAll(_fromClasses, fromClasses); } // from QueryClause - public Collection getClassSet () + public Collection> 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> _fromClasses = + new ArrayList>(); } diff --git a/src/java/com/samskivert/jdbc/depot/clause/GroupBy.java b/src/java/com/samskivert/jdbc/depot/clause/GroupBy.java index a40ca05..a21f8f1 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/GroupBy.java +++ b/src/java/com/samskivert/jdbc/depot/clause/GroupBy.java @@ -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 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++) { diff --git a/src/java/com/samskivert/jdbc/depot/clause/Join.java b/src/java/com/samskivert/jdbc/depot/clause/Join.java index 52a10b3..167d2ae 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/Join.java +++ b/src/java/com/samskivert/jdbc/depot/clause/Join.java @@ -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 pClass, String pCol, + Class 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 joinClass, SQLOperator joinCondition) { _joinClass = joinClass; _joinCondition = joinCondition; } // from QueryClause - public Collection getClassSet () + public Collection> getClassSet () { - return Arrays.asList(new Class[] { _joinClass }); + ArrayList> set = + new ArrayList>(); + 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 _joinClass; /** The condition used to join in the new table. */ protected SQLOperator _joinCondition; diff --git a/src/java/com/samskivert/jdbc/depot/clause/Limit.java b/src/java/com/samskivert/jdbc/depot/clause/Limit.java index 50063d5..936524b 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/Limit.java +++ b/src/java/com/samskivert/jdbc/depot/clause/Limit.java @@ -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 getClassSet () - { - return null; - } - - // from QueryClause - public void appendClause (ConstructedQuery query, StringBuilder builder) + public void appendClause (ConstructedQuery query, StringBuilder builder) { builder.append(" limit ? offset ? "); } diff --git a/src/java/com/samskivert/jdbc/depot/clause/OrderBy.java b/src/java/com/samskivert/jdbc/depot/clause/OrderBy.java index dc24891..c7fb4e5 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/OrderBy.java +++ b/src/java/com/samskivert/jdbc/depot/clause/OrderBy.java @@ -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 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++) { diff --git a/src/java/com/samskivert/jdbc/depot/clause/QueryClause.java b/src/java/com/samskivert/jdbc/depot/clause/QueryClause.java index 4c0a8ad..83052e1 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/QueryClause.java +++ b/src/java/com/samskivert/jdbc/depot/clause/QueryClause.java @@ -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 getClassSet (); + public Collection> 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; + } } diff --git a/src/java/com/samskivert/jdbc/depot/clause/Where.java b/src/java/com/samskivert/jdbc/depot/clause/Where.java index 3fcb0ba..e222634 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/Where.java +++ b/src/java/com/samskivert/jdbc/depot/clause/Where.java @@ -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 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); diff --git a/src/java/com/samskivert/jdbc/depot/expression/ColumnExp.java b/src/java/com/samskivert/jdbc/depot/expression/ColumnExp.java index 6f811c7..6c08740 100644 --- a/src/java/com/samskivert/jdbc/depot/expression/ColumnExp.java +++ b/src/java/com/samskivert/jdbc/depot/expression/ColumnExp.java @@ -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 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 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); diff --git a/src/java/com/samskivert/jdbc/depot/expression/SQLExpression.java b/src/java/com/samskivert/jdbc/depot/expression/SQLExpression.java index dc2a0ad..84cebdb 100644 --- a/src/java/com/samskivert/jdbc/depot/expression/SQLExpression.java +++ b/src/java/com/samskivert/jdbc/depot/expression/SQLExpression.java @@ -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 diff --git a/src/java/com/samskivert/jdbc/depot/operator/Conditionals.java b/src/java/com/samskivert/jdbc/depot/operator/Conditionals.java index 9270014..73f4026 100644 --- a/src/java/com/samskivert/jdbc/depot/operator/Conditionals.java +++ b/src/java/com/samskivert/jdbc/depot/operator/Conditionals.java @@ -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 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 pClass, String pColumn, Comparable... values) { this(new ColumnExp(pClass, pColumn), values); } - public In (Class pClass, String pColumn, Collection values) + public In (Class pClass, String pColumn, + Collection values) { this(new ColumnExp(pClass, pColumn), values.toArray(new Comparable[values.size()])); }