Add support for parameterized queries to Table &c.
Then fix up UserRepository to not concatenate strings. Good lord. 25 years ago MDB was too lazy.
This commit is contained in:
@@ -12,16 +12,16 @@ import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.jdbc.jora.*;
|
||||
|
||||
/**
|
||||
* The JORA repository simplifies the process of building persistence
|
||||
* services that make use of the JORA object relational mapping package.
|
||||
* The JORA repository simplifies the process of building persistence services that make use of the
|
||||
* JORA object relational mapping package.
|
||||
*
|
||||
* @see com.samskivert.jdbc.jora.Table
|
||||
*/
|
||||
public abstract class JORARepository extends SimpleRepository
|
||||
{
|
||||
/**
|
||||
* Creates and initializes a JORA repository which will access the
|
||||
* database identified by the supplied database identifier.
|
||||
* Creates and initializes a JORA repository which will access the database identified by the
|
||||
* supplied database identifier.
|
||||
*
|
||||
* @param provider the connection provider which will be used to
|
||||
* obtain our database connection.
|
||||
@@ -73,13 +73,12 @@ public abstract class JORARepository extends SimpleRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates fields specified by the supplied field mask in the supplied
|
||||
* object in the specified table.
|
||||
* Updates fields specified by the supplied field mask in the supplied object in the specified
|
||||
* table.
|
||||
*
|
||||
* @return the number of rows modified by the update.
|
||||
*/
|
||||
protected <T> int update (final Table<T> table, final T object,
|
||||
final FieldMask mask)
|
||||
protected <T> int update (final Table<T> table, final T object, final FieldMask mask)
|
||||
throws PersistenceException
|
||||
{
|
||||
return executeUpdate(new Operation<Integer>() {
|
||||
@@ -92,16 +91,13 @@ public abstract class JORARepository extends SimpleRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all objects from the specified table that match the supplied
|
||||
* query.
|
||||
* Loads all objects from the specified table that match the supplied query.
|
||||
*/
|
||||
protected <T> ArrayList<T> loadAll (final Table<T> table,
|
||||
final String query)
|
||||
protected <T> ArrayList<T> loadAll (final Table<T> table, final String query)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<ArrayList<T>>() {
|
||||
public ArrayList<T> invoke (
|
||||
Connection conn, DatabaseLiaison liaison)
|
||||
public ArrayList<T> invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.select(conn, query).toArrayList();
|
||||
@@ -110,16 +106,34 @@ public abstract class JORARepository extends SimpleRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all objects from the specified table that match the supplied
|
||||
* query, joining with the supplied auxiliary table(s).
|
||||
* Loads all objects from the specified table that match the supplied parameterized query.
|
||||
*
|
||||
* @param query a WHERE clause using ? placeholders for parameters.
|
||||
* @param params parameter values to bind to the ? placeholders.
|
||||
*/
|
||||
protected <T> ArrayList<T> loadAll (
|
||||
final Table<T> table, final String auxtable, final String query)
|
||||
protected <T> ArrayList<T> loadAllParams (final Table<T> table, final String query,
|
||||
final Object... params)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<ArrayList<T>>() {
|
||||
public ArrayList<T> invoke (
|
||||
Connection conn, DatabaseLiaison liaison)
|
||||
public ArrayList<T> invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.selectParams(conn, query, params).toArrayList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all objects from the specified table that match the supplied query, joining with the
|
||||
* supplied auxiliary table(s).
|
||||
*/
|
||||
protected <T> ArrayList<T> loadAll (final Table<T> table, final String auxtable,
|
||||
final String query)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<ArrayList<T>>() {
|
||||
public ArrayList<T> invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.select(conn, auxtable, query).toArrayList();
|
||||
@@ -128,16 +142,13 @@ public abstract class JORARepository extends SimpleRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all objects from the specified table that match the supplied
|
||||
* example.
|
||||
* Loads all objects from the specified table that match the supplied example.
|
||||
*/
|
||||
protected <T> ArrayList<T> loadAllByExample (
|
||||
final Table<T> table, final T example)
|
||||
protected <T> ArrayList<T> loadAllByExample (final Table<T> table, final T example)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<ArrayList<T>>() {
|
||||
public ArrayList<T> invoke (
|
||||
Connection conn, DatabaseLiaison liaison)
|
||||
public ArrayList<T> invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.queryByExample(conn, example).toArrayList();
|
||||
@@ -146,27 +157,24 @@ public abstract class JORARepository extends SimpleRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all objects from the specified table that match the supplied
|
||||
* example.
|
||||
* Loads all objects from the specified table that match the supplied example.
|
||||
*/
|
||||
protected <T> ArrayList<T> loadAllByExample (
|
||||
final Table<T> table, final T example, final FieldMask mask)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<ArrayList<T>>() {
|
||||
public ArrayList<T> invoke (
|
||||
Connection conn, DatabaseLiaison liaison)
|
||||
public ArrayList<T> invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
{
|
||||
return table.queryByExample(conn, example, mask).toArrayList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a single object from the specified table that matches the
|
||||
* supplied query. <em>Note:</em> the query should match one or zero
|
||||
* records, not more.
|
||||
* Loads a single object from the specified table that matches the supplied query.
|
||||
* <em>Note:</em> the query should match one or zero records, not more.
|
||||
*/
|
||||
protected <T> T load (final Table<T> table, final String query)
|
||||
throws PersistenceException
|
||||
@@ -181,12 +189,30 @@ public abstract class JORARepository extends SimpleRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a single object from the specified table that matches the supplied
|
||||
* query, joining with the supplied auxiliary table(s). <em>Note:</em> the
|
||||
* query should match one or zero records, not more.
|
||||
* Loads a single object from the specified table that matches the supplied parameterized query.
|
||||
* <em>Note:</em> the query should match one or zero records, not more.
|
||||
*
|
||||
* @param query a WHERE clause using ? placeholders for parameters.
|
||||
* @param params parameter values to bind to the ? placeholders.
|
||||
*/
|
||||
protected <T> T load (
|
||||
final Table<T> table, final String auxtable, final String query)
|
||||
protected <T> T loadParams (final Table<T> table, final String query, final Object... params)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<T>() {
|
||||
public T invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.selectParams(conn, query, params).get();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a single object from the specified table that matches the supplied query, joining with
|
||||
* the supplied auxiliary table(s). <em>Note:</em> the query should match one or zero records,
|
||||
* not more.
|
||||
*/
|
||||
protected <T> T load (final Table<T> table, final String auxtable, final String query)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<T>() {
|
||||
@@ -199,9 +225,29 @@ public abstract class JORARepository extends SimpleRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a single object from the specified table that matches the
|
||||
* supplied example. <em>Note:</em> the query should match one or zero
|
||||
* records, not more.
|
||||
* Loads a single object from the specified table that matches the supplied parameterized query,
|
||||
* joining with the supplied auxiliary table(s). <em>Note:</em> the query should match one or
|
||||
* zero records, not more.
|
||||
*
|
||||
* @param query a WHERE clause using ? placeholders for parameters.
|
||||
* @param params parameter values to bind to the ? placeholders.
|
||||
*/
|
||||
protected <T> T loadParams (final Table<T> table, final String auxtable, final String query,
|
||||
final Object... params)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<T>() {
|
||||
public T invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.selectParams(conn, auxtable, query, params).get();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a single object from the specified table that matches the supplied example.
|
||||
* <em>Note:</em> the query should match one or zero records, not more.
|
||||
*/
|
||||
protected <T> T loadByExample (final Table<T> table, final T example)
|
||||
throws PersistenceException
|
||||
@@ -216,12 +262,10 @@ public abstract class JORARepository extends SimpleRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a single object from the specified table that matches the
|
||||
* supplied example. <em>Note:</em> the query should match one or zero
|
||||
* records, not more.
|
||||
* Loads a single object from the specified table that matches the supplied example.
|
||||
* <em>Note:</em> the query should match one or zero records, not more.
|
||||
*/
|
||||
protected <T> T loadByExample (
|
||||
final Table<T> table, final T example, final FieldMask mask)
|
||||
protected <T> T loadByExample (final Table<T> table, final T example, final FieldMask mask)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<T>() {
|
||||
@@ -234,9 +278,9 @@ public abstract class JORARepository extends SimpleRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* First attempts to update the supplied object and if that modifies
|
||||
* zero rows, inserts the object into the specified table. The table
|
||||
* must be configured to store items of the supplied type.
|
||||
* First attempts to update the supplied object and if that modifies zero rows, inserts the
|
||||
* object into the specified table. The table must be configured to store items of the supplied
|
||||
* type.
|
||||
*
|
||||
* @return -1 if the object was updated, the last inserted id if it was
|
||||
* inserted.
|
||||
@@ -258,13 +302,12 @@ public abstract class JORARepository extends SimpleRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the specified field in the supplied object (which must
|
||||
* correspond to the supplied table).
|
||||
* Updates the specified field in the supplied object (which must correspond to the supplied
|
||||
* table).
|
||||
*
|
||||
* @return the number of rows modified by the update.
|
||||
*/
|
||||
protected <T> int updateField (
|
||||
final Table<T> table, final T object, String field)
|
||||
protected <T> int updateField (final Table<T> table, final T object, String field)
|
||||
throws PersistenceException
|
||||
{
|
||||
final FieldMask mask = table.getFieldMask();
|
||||
@@ -279,13 +322,12 @@ public abstract class JORARepository extends SimpleRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the specified fields in the supplied object (which must
|
||||
* correspond to the supplied table).
|
||||
* Updates the specified fields in the supplied object (which must correspond to the supplied
|
||||
* table).
|
||||
*
|
||||
* @return the number of rows modified by the update.
|
||||
*/
|
||||
protected <T> int updateFields (
|
||||
final Table<T> table, final T object, String[] fields)
|
||||
protected <T> int updateFields (final Table<T> table, final T object, String[] fields)
|
||||
throws PersistenceException
|
||||
{
|
||||
final FieldMask mask = table.getFieldMask();
|
||||
|
||||
@@ -266,6 +266,34 @@ public class SimpleRepository extends Repository
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the supplied parameterized update query in this repository, returning the number of
|
||||
* rows modified.
|
||||
*
|
||||
* @param query the SQL update/insert/delete statement with ? placeholders.
|
||||
* @param params parameter values to bind to the ? placeholders.
|
||||
*/
|
||||
protected int updateParams (final String query, final Object... params)
|
||||
throws PersistenceException
|
||||
{
|
||||
return executeUpdate(new Operation<Integer>() {
|
||||
public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
PreparedStatement stmt = null;
|
||||
try {
|
||||
stmt = conn.prepareStatement(query);
|
||||
for (int ii = 0; ii < params.length; ii++) {
|
||||
stmt.setObject(ii + 1, params[ii]);
|
||||
}
|
||||
return stmt.executeUpdate();
|
||||
} finally {
|
||||
JDBCUtil.close(stmt);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the supplied update query in this repository, throwing an exception if the
|
||||
* modification count is not equal to the specified count.
|
||||
|
||||
@@ -44,6 +44,13 @@ public class Cursor<V>
|
||||
_table.bindQueryVariables(qbeStmt, _qbeObject, _qbeMask);
|
||||
_result = qbeStmt.executeQuery();
|
||||
_stmt = qbeStmt;
|
||||
} else if (_params != null) {
|
||||
PreparedStatement pstmt = _conn.prepareStatement(_query);
|
||||
for (int ii = 0; ii < _params.length; ii++) {
|
||||
pstmt.setObject(ii + 1, _params[ii]);
|
||||
}
|
||||
_result = pstmt.executeQuery();
|
||||
_stmt = pstmt;
|
||||
} else {
|
||||
if (_stmt == null) {
|
||||
_stmt = _conn.createStatement();
|
||||
@@ -194,8 +201,15 @@ public class Cursor<V>
|
||||
_query = query;
|
||||
}
|
||||
|
||||
protected Cursor (Table<V> table, Connection conn, V obj,
|
||||
FieldMask mask, boolean like)
|
||||
protected Cursor (Table<V> table, Connection conn, String query, Object[] params)
|
||||
{
|
||||
_table = table;
|
||||
_conn = conn;
|
||||
_query = query;
|
||||
_params = params;
|
||||
}
|
||||
|
||||
protected Cursor (Table<V> table, Connection conn, V obj, FieldMask mask, boolean like)
|
||||
{
|
||||
_table = table;
|
||||
_conn = conn;
|
||||
@@ -213,6 +227,7 @@ public class Cursor<V>
|
||||
protected Statement _stmt;
|
||||
protected V _currObject, _qbeObject;
|
||||
protected FieldMask _qbeMask;
|
||||
protected Object[] _params;
|
||||
protected boolean _like;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@ import com.samskivert.util.StringUtil;
|
||||
public class Table<T>
|
||||
{
|
||||
/**
|
||||
* Constructor for table object. Make association between Java class and
|
||||
* database table.
|
||||
* Constructor for table object. Make association between Java class and database table.
|
||||
*
|
||||
* @param clazz the class that represents a row entry.
|
||||
* @param tableName name of database table mapped on this Java class
|
||||
@@ -30,16 +29,14 @@ public class Table<T>
|
||||
* @param mixedCaseConvert whether or not to convert mixed case field
|
||||
* names into underscore separated uppercase column names.
|
||||
*/
|
||||
public Table (Class<T> clazz, String tableName, String key,
|
||||
boolean mixedCaseConvert)
|
||||
public Table (Class<T> clazz, String tableName, String key, boolean mixedCaseConvert)
|
||||
{
|
||||
String[] keys = {key};
|
||||
init(clazz, tableName, keys, mixedCaseConvert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for table object. Make association between Java class and
|
||||
* database table.
|
||||
* Constructor for table object. Make association between Java class and database table.
|
||||
*
|
||||
* @param clazz the class that represents a row entry.
|
||||
* @param tableName name of database table mapped on this Java class
|
||||
@@ -52,8 +49,7 @@ public class Table<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for table object. Make association between Java class and
|
||||
* database table.
|
||||
* Constructor for table object. Make association between Java class and database table.
|
||||
*
|
||||
* @param clazz the class that represents a row entry.
|
||||
* @param tableName name of database table mapped on this Java class
|
||||
@@ -66,8 +62,7 @@ public class Table<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for table object. Make association between Java class and
|
||||
* database table.
|
||||
* Constructor for table object. Make association between Java class and database table.
|
||||
*
|
||||
* @param clazz the class that represents a row entry.
|
||||
* @param tableName name of database table mapped on this Java class
|
||||
@@ -76,8 +71,7 @@ public class Table<T>
|
||||
* @param mixedCaseConvert whether or not to convert mixed case field
|
||||
* names into underscore separated uppercase column names.
|
||||
*/
|
||||
public Table (Class<T> clazz, String tableName, String[] keys,
|
||||
boolean mixedCaseConvert)
|
||||
public Table (Class<T> clazz, String tableName, String[] keys, boolean mixedCaseConvert)
|
||||
{
|
||||
init(clazz, tableName, keys, mixedCaseConvert);
|
||||
}
|
||||
@@ -98,64 +92,85 @@ public class Table<T>
|
||||
*/
|
||||
public final Cursor<T> select (Connection conn, String condition)
|
||||
{
|
||||
String query = "select " + listOfFields + " from " + name +
|
||||
String query = "select " + listOfFields + " from " + name + " " + condition;
|
||||
return new Cursor<T>(this, conn, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select records from database table according to search condition using a parameterized query.
|
||||
*
|
||||
* @param condition valid SQL condition expression started with WHERE, using ? placeholders for
|
||||
* parameters.
|
||||
* @param params parameter values to bind to the ? placeholders.
|
||||
*/
|
||||
public final Cursor<T> selectParams (Connection conn, String condition, Object... params)
|
||||
{
|
||||
String query = "select " + listOfFields + " from " + name + " " + condition;
|
||||
return new Cursor<T>(this, conn, query, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select records from database table according to search condition including the specified
|
||||
* (comma separated) extra tables into the SELECT clause to facilitate a join in determining the
|
||||
* key, using a parameterized query.
|
||||
*
|
||||
* @param tables the (comma separated) names of extra tables to include in the SELECT clause.
|
||||
* @param condition valid SQL condition expression started with WHERE, using ? placeholders for
|
||||
* parameters.
|
||||
* @param params parameter values to bind to the ? placeholders.
|
||||
*/
|
||||
public final Cursor<T> selectParams (Connection conn, String tables, String condition,
|
||||
Object... params)
|
||||
{
|
||||
String query = "select " + qualifiedListOfFields + " from " + name + "," + tables +
|
||||
" " + condition;
|
||||
return new Cursor<T>(this, conn, query, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select records from database table according to search condition including the specified
|
||||
* (comma separated) extra tables into the SELECT clause to facilitate a join in determining the
|
||||
* key.
|
||||
*
|
||||
* @param tables the (comma separated) names of extra tables to include in the SELECT clause.
|
||||
* @param condition valid SQL condition expression started with WHERE.
|
||||
*/
|
||||
public final Cursor<T> select (Connection conn, String tables, String condition)
|
||||
{
|
||||
String query = "select " + qualifiedListOfFields + " from " + name + "," + tables +
|
||||
" " + condition;
|
||||
return new Cursor<T>(this, conn, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select records from database table according to search condition
|
||||
* including the specified (comma separated) extra tables into the SELECT
|
||||
* clause to facilitate a join in determining the key.
|
||||
* Select records from database table according to search condition including the specified
|
||||
* (comma separated) extra tables into the SELECT clause to facilitate a join in determining the
|
||||
* key. To facilitate situations where data from multiple tables is being combined into a single
|
||||
* object, the fields will not be qualified with the primary table name.
|
||||
*
|
||||
* @param tables the (comma separated) names of extra tables to include in
|
||||
* the SELECT clause.
|
||||
* @param tables the (comma separated) names of extra tables to include in the SELECT clause.
|
||||
* @param condition valid SQL condition expression started with WHERE.
|
||||
*/
|
||||
public final Cursor<T> select (Connection conn, String tables,
|
||||
String condition)
|
||||
public final Cursor<T> join (Connection conn, String tables, String condition)
|
||||
{
|
||||
String query = "select " + qualifiedListOfFields +
|
||||
" from " + name + "," + tables + " " + condition;
|
||||
return new Cursor<T>(this, conn, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select records from database table according to search condition
|
||||
* including the specified (comma separated) extra tables into the SELECT
|
||||
* clause to facilitate a join in determining the key. To facilitate
|
||||
* situations where data from multiple tables is being combined into a
|
||||
* single object, the fields will not be qualified with the primary table
|
||||
* name.
|
||||
*
|
||||
* @param tables the (comma separated) names of extra tables to include in
|
||||
* the SELECT clause.
|
||||
* @param condition valid SQL condition expression started with WHERE.
|
||||
*/
|
||||
public final Cursor<T> join (Connection conn, String tables,
|
||||
String condition)
|
||||
{
|
||||
String query = "select " + listOfFields +
|
||||
" from " + name + "," + tables + " " + condition;
|
||||
String query = "select " + listOfFields + " from " + name + "," + tables + " " + condition;
|
||||
return new Cursor<T>(this, conn, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #join} but does a straight join with the specified table.
|
||||
*/
|
||||
public final Cursor<T> straightJoin (Connection conn, String table,
|
||||
String condition)
|
||||
public final Cursor<T> straightJoin (Connection conn, String table, String condition)
|
||||
{
|
||||
String query = "select " + listOfFields +
|
||||
" from " + name + " straight_join " + table + " " + condition;
|
||||
String query = "select " + listOfFields + " from " + name + " straight_join " + table +
|
||||
" " + condition;
|
||||
return new Cursor<T>(this, conn, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select records from database table using <I>obj</I> object as template.
|
||||
*
|
||||
* @param obj example object for search: selected objects should match all
|
||||
* non-null fields.
|
||||
* @param obj example object for search: selected objects should match all non-null fields.
|
||||
*/
|
||||
public final Cursor<T> queryByExample (Connection conn, T obj)
|
||||
{
|
||||
@@ -163,23 +178,20 @@ public class Table<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Select records from database table using <I>obj</I> object as template
|
||||
* for selection.
|
||||
* Select records from database table using <I>obj</I> object as template for selection.
|
||||
*
|
||||
* @param obj example object for search.
|
||||
* @param mask field mask indicating which fields in the example object
|
||||
* should be used when building the query.
|
||||
* @param mask field mask indicating which fields in the example object should be used when
|
||||
* building the query.
|
||||
*/
|
||||
public final Cursor<T> queryByExample (Connection conn, T obj,
|
||||
FieldMask mask)
|
||||
public final Cursor<T> queryByExample (Connection conn, T obj, FieldMask mask)
|
||||
{
|
||||
return new Cursor<T>(this, conn, obj, mask, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The same as the queryByExample, but string fields for the obj are
|
||||
* matched using 'like' instead of equals, which allows you to send % in to
|
||||
* do matching.
|
||||
* The same as the queryByExample, but string fields for the obj are matched using 'like'
|
||||
* instead of equals, which allows you to send % in to do matching.
|
||||
*/
|
||||
public final Cursor<T> queryByLikeExample (Connection conn, T obj)
|
||||
{
|
||||
@@ -187,19 +199,17 @@ public class Table<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* The same as the queryByExample, but string fields for the obj are
|
||||
* matched using 'like' instead of equals, which allows you to send % in to
|
||||
* do matching.
|
||||
* The same as the queryByExample, but string fields for the obj are matched using 'like'
|
||||
* instead of equals, which allows you to send % in to do matching.
|
||||
*/
|
||||
public final Cursor<T> queryByLikeExample (Connection conn, T obj,
|
||||
FieldMask mask)
|
||||
public final Cursor<T> queryByLikeExample (Connection conn, T obj, FieldMask mask)
|
||||
{
|
||||
return new Cursor<T>(this, conn, obj, mask, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert new record in the table. Values of inserted record fields are
|
||||
* taken from specified object.
|
||||
* Insert new record in the table. Values of inserted record fields are taken from specified
|
||||
* object.
|
||||
*
|
||||
* @param obj object specifying values of inserted record fields
|
||||
*/
|
||||
@@ -253,11 +263,10 @@ public class Table<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert several new records in the table. Values of inserted records
|
||||
* fields are taken from objects of specified array.
|
||||
* Insert several new records in the table. Values of inserted records fields are taken from
|
||||
* objects of specified array.
|
||||
*
|
||||
* @param objects array with objects specifying values of inserted record
|
||||
* fields
|
||||
* @param objects array with objects specifying values of inserted record fields
|
||||
*/
|
||||
public synchronized void insert (Connection conn, T[] objects)
|
||||
throws SQLException
|
||||
@@ -278,8 +287,8 @@ public class Table<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a field mask that can be configured and used to update subsets
|
||||
* of entire objects via calls to {@link #update(Connection,Object,FieldMask)}.
|
||||
* Returns a field mask that can be configured and used to update subsets of entire objects via
|
||||
* calls to {@link #update(Connection,Object,FieldMask)}.
|
||||
*/
|
||||
public FieldMask getFieldMask ()
|
||||
{
|
||||
@@ -287,12 +296,10 @@ public class Table<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Update record in the table using table's primary key to locate record in
|
||||
* the table and values of fields of specified object <I>obj</I> to alter
|
||||
* record fields.
|
||||
* Update record in the table using table's primary key to locate record in the table and values
|
||||
* of fields of specified object <I>obj</I> to alter record fields.
|
||||
*
|
||||
* @param obj object specifying value of primary key and new values of
|
||||
* updated record fields
|
||||
* @param obj object specifying value of primary key and new values of updated record fields
|
||||
*
|
||||
* @return number of objects actually updated
|
||||
*/
|
||||
@@ -303,15 +310,13 @@ public class Table<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Update record in the table using table's primary key to locate record in
|
||||
* the table and values of fields of specified object <I>obj</I> to alter
|
||||
* record fields. Only the fields marked as modified in the supplied field
|
||||
* mask will be updated in the database.
|
||||
* Update record in the table using table's primary key to locate record in the table and values
|
||||
* of fields of specified object <I>obj</I> to alter record fields. Only the fields marked as
|
||||
* modified in the supplied field mask will be updated in the database.
|
||||
*
|
||||
* @param obj object specifying value of primary key and new values of
|
||||
* updated record fields
|
||||
* @param mask a {@link FieldMask} instance configured to indicate which of
|
||||
* the object's fields are modified and should be written to the database.
|
||||
* @param obj object specifying value of primary key and new values of updated record fields
|
||||
* @param mask a {@link FieldMask} instance configured to indicate which of the object's fields
|
||||
* are modified and should be written to the database.
|
||||
*
|
||||
* @return number of objects actually updated
|
||||
*/
|
||||
@@ -334,12 +339,11 @@ public class Table<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Update set of records in the table using table's primary key to locate
|
||||
* record in the table and values of fields of objects from specified array
|
||||
* <I>objects</I> to alter record fields.
|
||||
* Update set of records in the table using table's primary key to locate record in the table
|
||||
* and values of fields of objects from specified array <I>objects</I> to alter record fields.
|
||||
*
|
||||
* @param objects array of objects specifying primary keys and and new
|
||||
* values of updated record fields
|
||||
* @param objects array of objects specifying primary keys and and new values of updated record
|
||||
* fields
|
||||
*
|
||||
* @return number of objects actually updated
|
||||
*/
|
||||
@@ -352,15 +356,13 @@ public class Table<T>
|
||||
}
|
||||
|
||||
int nUpdated = 0;
|
||||
String sql = "update " + name + " set " + listOfAssignments +
|
||||
buildUpdateWhere();
|
||||
String sql = "update " + name + " set " + listOfAssignments + buildUpdateWhere();
|
||||
PreparedStatement updateStmt = conn.prepareStatement(sql);
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
int column = bindUpdateVariables(updateStmt, objects[i], null);
|
||||
for (int j = 0; j < primaryKeys.length; j++) {
|
||||
int fidx = primaryKeyIndices[j];
|
||||
fields[fidx].bindVariable(
|
||||
updateStmt, objects[i], column+1+j);
|
||||
fields[fidx].bindVariable(updateStmt, objects[i], column+1+j);
|
||||
}
|
||||
updateStmt.addBatch();
|
||||
}
|
||||
@@ -381,8 +383,7 @@ public class Table<T>
|
||||
throws SQLException
|
||||
{
|
||||
if (primaryKeys == null) {
|
||||
throw new IllegalStateException(
|
||||
"No primary key for table " + name + ".");
|
||||
throw new IllegalStateException("No primary key for table " + name + ".");
|
||||
}
|
||||
int nDeleted = 0;
|
||||
StringBuilder sql = new StringBuilder(
|
||||
@@ -410,8 +411,7 @@ public class Table<T>
|
||||
throws SQLException
|
||||
{
|
||||
if (primaryKeys == null) {
|
||||
throw new IllegalStateException(
|
||||
"No primary key for table " + name + ".");
|
||||
throw new IllegalStateException("No primary key for table " + name + ".");
|
||||
}
|
||||
int nDeleted = 0;
|
||||
StringBuilder sql = new StringBuilder(
|
||||
@@ -422,8 +422,7 @@ public class Table<T>
|
||||
PreparedStatement deleteStmt = conn.prepareStatement(sql.toString());
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
for (int j = 0; j < primaryKeys.length; j++) {
|
||||
fields[primaryKeyIndices[j]].bindVariable(
|
||||
deleteStmt, objects[i], j+1);
|
||||
fields[primaryKeyIndices[j]].bindVariable(deleteStmt, objects[i], j+1);
|
||||
}
|
||||
deleteStmt.addBatch();
|
||||
}
|
||||
@@ -438,15 +437,13 @@ public class Table<T>
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[name=" + name +
|
||||
", primaryKeys=" + StringUtil.toString(primaryKeys) + "]";
|
||||
return "[name=" + name + ", primaryKeys=" + StringUtil.toString(primaryKeys) + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Separator of name components of compound field. For example, if Java
|
||||
* class contains component "location" of Point class, which has two
|
||||
* components "x" and "y", then database table should have columns
|
||||
* "location_x" and "location_y" (if '_' is used as separator).
|
||||
* Separator of name components of compound field. For example, if Java class contains component
|
||||
* "location" of Point class, which has two components "x" and "y", then database table should
|
||||
* have columns "location_x" and "location_y" (if '_' is used as separator).
|
||||
*/
|
||||
public static final String fieldSeparator = "_";
|
||||
|
||||
@@ -460,8 +457,7 @@ public class Table<T>
|
||||
listOfFields = "";
|
||||
qualifiedListOfFields = "";
|
||||
listOfAssignments = "";
|
||||
ArrayList<FieldDescriptor> fieldsVector =
|
||||
new ArrayList<FieldDescriptor>();
|
||||
ArrayList<FieldDescriptor> fieldsVector = new ArrayList<FieldDescriptor>();
|
||||
nFields = buildFieldsList(fieldsVector, _rowClass, "");
|
||||
fields = fieldsVector.toArray(new FieldDescriptor[nFields]);
|
||||
fMask = new FieldMask(fields);
|
||||
@@ -478,16 +474,14 @@ public class Table<T>
|
||||
while (--i >= 0) {
|
||||
if (fields[i].name.equals(keys[j])) {
|
||||
if (!fields[i].isAtomic()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Non-atomic primary key provided");
|
||||
throw new IllegalArgumentException("Non-atomic primary key provided");
|
||||
}
|
||||
primaryKeyIndices[j] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < 0) {
|
||||
throw new NoSuchFieldError("No such field '" + keys[j]
|
||||
+ "' in table " + name);
|
||||
throw new NoSuchFieldError("No such field '" + keys[j] + "' in table " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -502,8 +496,8 @@ public class Table<T>
|
||||
}
|
||||
}
|
||||
|
||||
protected final int buildFieldsList (ArrayList<FieldDescriptor> buf,
|
||||
Class<?> _rowClass, String prefix)
|
||||
protected final int buildFieldsList (ArrayList<FieldDescriptor> buf, Class<?> _rowClass,
|
||||
String prefix)
|
||||
{
|
||||
Field[] f = _rowClass.getDeclaredFields();
|
||||
|
||||
@@ -511,8 +505,7 @@ public class Table<T>
|
||||
while ((superclass = superclass.getSuperclass()) != null) {
|
||||
Field[] inheritedFields = superclass.getDeclaredFields();
|
||||
Field[] allFields = new Field[inheritedFields.length + f.length];
|
||||
System.arraycopy(inheritedFields, 0, allFields, 0,
|
||||
inheritedFields.length);
|
||||
System.arraycopy(inheritedFields, 0, allFields, 0, inheritedFields.length);
|
||||
System.arraycopy(f,0, allFields, inheritedFields.length, f.length);
|
||||
f = allFields;
|
||||
}
|
||||
@@ -529,8 +522,7 @@ public class Table<T>
|
||||
|
||||
int n = 0;
|
||||
for (int i = 0; i < f.length; i++) {
|
||||
if ((f[i].getModifiers()&(Modifier.TRANSIENT|Modifier.STATIC))==0)
|
||||
{
|
||||
if ((f[i].getModifiers()&(Modifier.TRANSIENT|Modifier.STATIC))==0) {
|
||||
String name = f[i].getName();
|
||||
Class<?> fieldClass = f[i].getType();
|
||||
String fullName = prefix + convertName(name);
|
||||
@@ -548,49 +540,29 @@ public class Table<T>
|
||||
else if (c.equals("float")) type = FieldDescriptor.t_float;
|
||||
else if (c.equals("double")) type = FieldDescriptor.t_double;
|
||||
else if (c.equals("boolean")) type = FieldDescriptor.t_boolean;
|
||||
else if (c.equals("java.lang.Byte"))
|
||||
type = FieldDescriptor.tByte;
|
||||
else if (c.equals("java.lang.Short"))
|
||||
type = FieldDescriptor.tShort;
|
||||
else if (c.equals("java.lang.Integer"))
|
||||
type = FieldDescriptor.tInteger;
|
||||
else if (c.equals("java.lang.Long"))
|
||||
type = FieldDescriptor.tLong;
|
||||
else if (c.equals("java.lang.Float"))
|
||||
type = FieldDescriptor.tFloat;
|
||||
else if (c.equals("java.lang.Double"))
|
||||
type = FieldDescriptor.tDouble;
|
||||
else if (c.equals("java.lang.Boolean"))
|
||||
type = FieldDescriptor.tBoolean;
|
||||
else if (c.equals("java.math.BigDecimal"))
|
||||
type = FieldDescriptor.tDecimal;
|
||||
else if (c.equals("java.lang.String"))
|
||||
type = FieldDescriptor.tString;
|
||||
else if (fieldClass.equals(BYTE_PROTO.getClass()))
|
||||
type = FieldDescriptor.tBytes;
|
||||
else if (c.equals("java.sql.Date"))
|
||||
type = FieldDescriptor.tDate;
|
||||
else if (c.equals("java.sql.Time"))
|
||||
type = FieldDescriptor.tTime;
|
||||
else if (c.equals("java.sql.Timestamp"))
|
||||
type = FieldDescriptor.tTimestamp;
|
||||
else if (c.equals("java.lang.InputStream"))
|
||||
type = FieldDescriptor.tStream;
|
||||
else if (c.equals("java.sql.BlobLocator"))
|
||||
type = FieldDescriptor.tBlob;
|
||||
else if (c.equals("java.sql.ClobLocator"))
|
||||
type = FieldDescriptor.tClob;
|
||||
else if (serializableClass.isAssignableFrom(fieldClass))
|
||||
type = FieldDescriptor.tClosure;
|
||||
else if (c.equals("java.lang.Byte")) type = FieldDescriptor.tByte;
|
||||
else if (c.equals("java.lang.Short")) type = FieldDescriptor.tShort;
|
||||
else if (c.equals("java.lang.Integer")) type = FieldDescriptor.tInteger;
|
||||
else if (c.equals("java.lang.Long")) type = FieldDescriptor.tLong;
|
||||
else if (c.equals("java.lang.Float")) type = FieldDescriptor.tFloat;
|
||||
else if (c.equals("java.lang.Double")) type = FieldDescriptor.tDouble;
|
||||
else if (c.equals("java.lang.Boolean")) type = FieldDescriptor.tBoolean;
|
||||
else if (c.equals("java.math.BigDecimal")) type = FieldDescriptor.tDecimal;
|
||||
else if (c.equals("java.lang.String")) type = FieldDescriptor.tString;
|
||||
else if (fieldClass.equals(BYTE_PROTO.getClass())) type = FieldDescriptor.tBytes;
|
||||
else if (c.equals("java.sql.Date")) type = FieldDescriptor.tDate;
|
||||
else if (c.equals("java.sql.Time")) type = FieldDescriptor.tTime;
|
||||
else if (c.equals("java.sql.Timestamp")) type = FieldDescriptor.tTimestamp;
|
||||
else if (c.equals("java.lang.InputStream")) type = FieldDescriptor.tStream;
|
||||
else if (c.equals("java.sql.BlobLocator")) type = FieldDescriptor.tBlob;
|
||||
else if (c.equals("java.sql.ClobLocator")) type = FieldDescriptor.tClob;
|
||||
else if (serializableClass.isAssignableFrom(fieldClass)) type = FieldDescriptor.tClosure;
|
||||
else {
|
||||
int nComponents = buildFieldsList(buf, fieldClass,
|
||||
fd.name+fieldSeparator);
|
||||
fd.inType = fd.outType =
|
||||
FieldDescriptor.tCompound + nComponents;
|
||||
int nComponents = buildFieldsList(buf, fieldClass, fd.name+fieldSeparator);
|
||||
fd.inType = fd.outType = FieldDescriptor.tCompound + nComponents;
|
||||
|
||||
try {
|
||||
fd.constructor =
|
||||
fieldClass.getDeclaredConstructor(new Class<?>[0]);
|
||||
fd.constructor = fieldClass.getDeclaredConstructor(new Class<?>[0]);
|
||||
setBypass.invoke(fd.constructor, bypassFlag);
|
||||
} catch(Exception ex) {}
|
||||
|
||||
@@ -647,20 +619,17 @@ public class Table<T>
|
||||
return obj;
|
||||
}
|
||||
|
||||
protected final int load (
|
||||
Object obj, int i, int end, int column, ResultSet result)
|
||||
protected final int load (Object obj, int i, int end, int column, ResultSet result)
|
||||
throws SQLException
|
||||
{
|
||||
try {
|
||||
while (i < end) {
|
||||
FieldDescriptor fd = fields[i++];
|
||||
if (!fd.loadVariable(result, obj, ++column)) {
|
||||
Object component =
|
||||
fd.constructor.newInstance(constructorArgs);
|
||||
Object component = fd.constructor.newInstance(constructorArgs);
|
||||
fd.field.set(obj, component);
|
||||
int nComponents = fd.inType - FieldDescriptor.tCompound;
|
||||
column = load(component, i, i + nComponents,
|
||||
column-1, result);
|
||||
column = load(component, i, i + nComponents, column-1, result);
|
||||
i += nComponents;
|
||||
}
|
||||
}
|
||||
@@ -673,17 +642,13 @@ public class Table<T>
|
||||
return column;
|
||||
}
|
||||
|
||||
protected final int bindUpdateVariables(PreparedStatement pstmt,
|
||||
T obj,
|
||||
FieldMask mask)
|
||||
protected final int bindUpdateVariables(PreparedStatement pstmt, T obj, FieldMask mask)
|
||||
throws SQLException
|
||||
{
|
||||
return bindUpdateVariables(pstmt, obj, 0, nFields, 0, mask);
|
||||
}
|
||||
|
||||
protected final void bindQueryVariables(PreparedStatement pstmt,
|
||||
T obj,
|
||||
FieldMask mask)
|
||||
protected final void bindQueryVariables(PreparedStatement pstmt, T obj, FieldMask mask)
|
||||
throws SQLException
|
||||
{
|
||||
bindQueryVariables(pstmt, obj, 0, nFields, 0, mask);
|
||||
|
||||
@@ -7,6 +7,7 @@ package com.samskivert.servlet.user;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.Date;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
@@ -86,7 +87,7 @@ public class UserRepository extends JORARepository
|
||||
public User loadUser (String username)
|
||||
throws PersistenceException
|
||||
{
|
||||
return loadUserWhere("where username = " + JDBCUtil.escape(username));
|
||||
return loadUserWhereParams("where username = ?", username);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,8 +110,9 @@ public class UserRepository extends JORARepository
|
||||
public User loadUserBySession (String sessionKey)
|
||||
throws PersistenceException
|
||||
{
|
||||
User user = load(_utable, "sessions", "where authcode = '" + sessionKey + "' " +
|
||||
"AND sessions.userId = users.userId");
|
||||
User user = loadParams(_utable, "sessions",
|
||||
"where authcode = ? AND sessions.userId = users.userId",
|
||||
sessionKey);
|
||||
if (user != null) {
|
||||
user.setDirtyMask(_utable.getFieldMask());
|
||||
}
|
||||
@@ -145,7 +147,7 @@ public class UserRepository extends JORARepository
|
||||
public ArrayList<User> lookupUsersByEmail (String email)
|
||||
throws PersistenceException
|
||||
{
|
||||
return loadAll(_utable, "where email = " + JDBCUtil.escape(email));
|
||||
return loadAllParams(_utable, "where email = ?", email);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -251,14 +253,16 @@ public class UserRepository extends JORARepository
|
||||
throws PersistenceException
|
||||
{
|
||||
// look for an existing session for this user
|
||||
final String query = "select authcode from sessions where userId = " + user.userId;
|
||||
final int userId = user.userId;
|
||||
String authcode = execute(new Operation<String>() {
|
||||
public String invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws PersistenceException, SQLException
|
||||
{
|
||||
Statement stmt = conn.createStatement();
|
||||
PreparedStatement stmt = conn.prepareStatement(
|
||||
"select authcode from sessions where userId = ?");
|
||||
try {
|
||||
ResultSet rs = stmt.executeQuery(query);
|
||||
stmt.setInt(1, userId);
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
while (rs.next()) {
|
||||
return rs.getString(1);
|
||||
}
|
||||
@@ -276,13 +280,12 @@ public class UserRepository extends JORARepository
|
||||
|
||||
// if we found one, update its expires time and reuse it
|
||||
if (authcode != null) {
|
||||
update("update sessions set expires = '" + expires + "' where " +
|
||||
"authcode = '" + authcode + "'");
|
||||
updateParams("update sessions set expires = ? where authcode = ?", expires, authcode);
|
||||
} else {
|
||||
// otherwise create a new one and insert it into the table
|
||||
authcode = UserUtil.genAuthCode(user);
|
||||
update("insert into sessions (authcode, userId, expires) values('" + authcode + "', " +
|
||||
user.userId + ", '" + expires + "')");
|
||||
updateParams("insert into sessions (authcode, userId, expires) values(?, ?, ?)",
|
||||
authcode, user.userId, expires);
|
||||
}
|
||||
|
||||
return authcode;
|
||||
@@ -302,8 +305,8 @@ public class UserRepository extends JORARepository
|
||||
Date expires = new Date(cal.getTime().getTime());
|
||||
|
||||
// attempt to update an existing session row, returning true if we found and updated it
|
||||
return (update("update sessions set expires = '" + expires + "' " +
|
||||
"where authcode = " + JDBCUtil.escape(sessionKey)) == 1);
|
||||
return (updateParams("update sessions set expires = ? where authcode = ?",
|
||||
expires, sessionKey) == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -429,6 +432,23 @@ public class UserRepository extends JORARepository
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads up a user record that matches the specified parameterized where clause. Returns null
|
||||
* if no record matches.
|
||||
*
|
||||
* @param where a WHERE clause using ? placeholders for parameters.
|
||||
* @param params parameter values to bind to the ? placeholders.
|
||||
*/
|
||||
protected User loadUserWhereParams (String where, Object... params)
|
||||
throws PersistenceException
|
||||
{
|
||||
User user = loadParams(_utable, where, params);
|
||||
if (user != null) {
|
||||
user.setDirtyMask(_utable.getFieldMask());
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
protected String[] loadNames (int[] userIds, final String column)
|
||||
throws PersistenceException
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user