A whole heap of new Depot stuff from Zell. Clauses, operators, expressions, oh
my!
This commit is contained in:
@@ -30,7 +30,7 @@ import java.lang.annotation.Target;
|
||||
* correspond to a column in a table, and thus its value must be overridden in the {@link Query}.
|
||||
*/
|
||||
@Retention(value=RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE })
|
||||
public @interface Computed
|
||||
{
|
||||
/** If this value is false, the field is not populated by Depot at all. */
|
||||
|
||||
@@ -27,12 +27,14 @@ import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javax.persistence.GeneratedValue;
|
||||
@@ -41,7 +43,8 @@ import javax.persistence.TableGenerator;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import com.samskivert.jdbc.JDBCUtil;
|
||||
import com.samskivert.jdbc.depot.expression.ColumnExpression;
|
||||
import com.samskivert.jdbc.depot.clause.Where;
|
||||
import com.samskivert.jdbc.depot.expression.ColumnExp;
|
||||
import com.samskivert.util.ArrayUtil;
|
||||
import com.samskivert.util.ListUtil;
|
||||
import com.samskivert.util.StringUtil;
|
||||
@@ -66,9 +69,13 @@ public class DepotMarshaller<T>
|
||||
{
|
||||
_pclass = pclass;
|
||||
|
||||
// determine our table name
|
||||
_tableName = _pclass.getName();
|
||||
_tableName = _tableName.substring(_tableName.lastIndexOf(".")+1);
|
||||
// see if this is a computed entity
|
||||
Computed computed = pclass.getAnnotation(Computed.class);
|
||||
if (computed == null) {
|
||||
// if not, this class has a corresponding SQL table
|
||||
_tableName = _pclass.getName();
|
||||
_tableName = _tableName.substring(_tableName.lastIndexOf(".")+1);
|
||||
}
|
||||
|
||||
// if the entity defines a new TableGenerator, map that in our static table as those are
|
||||
// shared across all entities
|
||||
@@ -172,8 +179,13 @@ public class DepotMarshaller<T>
|
||||
// generate our full list of fields/columns for use in queries
|
||||
_allFields = fields.toArray(new String[fields.size()]);
|
||||
|
||||
// figure out the list of fields that correspond to actual table columns and create the SQL
|
||||
// used to create and migrate our table
|
||||
// if we're a computed entity, stop here
|
||||
if (_tableName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// figure out the list of fields that correspond to actual table columns and generate the
|
||||
// SQL used to create and migrate our table (unless we're a computed entity)
|
||||
_columnFields = new String[_allFields.length];
|
||||
_columnDefinitions = new String[_allFields.length];
|
||||
int jj = 0;
|
||||
@@ -261,10 +273,10 @@ public class DepotMarshaller<T>
|
||||
"Argument count (" + values.length + ") must match primary key size (" +
|
||||
_pkColumns.size() + ")");
|
||||
}
|
||||
ColumnExpression[] columns = new ColumnExpression[_pkColumns.size()];
|
||||
ColumnExp[] columns = new ColumnExp[_pkColumns.size()];
|
||||
for (int ii = 0; ii < _pkColumns.size(); ii++) {
|
||||
FieldMarshaller field = _pkColumns.get(ii);
|
||||
columns[ii] = new ColumnExpression(_pclass, field.getColumnName());
|
||||
columns[ii] = new ColumnExp(_pclass, field.getColumnName());
|
||||
}
|
||||
return new Key(columns, values);
|
||||
}
|
||||
@@ -277,6 +289,11 @@ public class DepotMarshaller<T>
|
||||
public void init (Connection conn)
|
||||
throws SQLException
|
||||
{
|
||||
// if we have no table (i.e. we're a computed entity), we have nothing to create
|
||||
if (getTableName() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check to see if our schema version table exists, create it if not
|
||||
JDBCUtil.createTableIfMissing(conn, SCHEMA_VERSION_TABLE,
|
||||
new String[] { "persistentClass VARCHAR(255) NOT NULL",
|
||||
@@ -358,10 +375,22 @@ public class DepotMarshaller<T>
|
||||
throws SQLException
|
||||
{
|
||||
try {
|
||||
T po = (T)_pclass.newInstance();
|
||||
// first, build a set of the fields that we actually received
|
||||
Set<String> fields = new HashSet<String>();
|
||||
ResultSetMetaData metadata = rs.getMetaData();
|
||||
for (int ii = 1; ii <= metadata.getColumnCount(); ii ++) {
|
||||
fields.add(metadata.getColumnName(ii));
|
||||
}
|
||||
|
||||
// then create and populate the persistent object
|
||||
T po = _pclass.newInstance();
|
||||
for (FieldMarshaller fm : _fields.values()) {
|
||||
if (fm.getComputed() != null && !fm.getComputed().required()) {
|
||||
continue;
|
||||
if (!fields.contains(fm.getField().getName())) {
|
||||
// this field was not in the result set, make sure that's OK
|
||||
if (fm.getComputed() != null && !fm.getComputed().required()) {
|
||||
continue;
|
||||
}
|
||||
throw new SQLException("ResultSet missing field: " + fm.getField().getName());
|
||||
}
|
||||
fm.getValue(rs, po);
|
||||
}
|
||||
@@ -384,6 +413,8 @@ public class DepotMarshaller<T>
|
||||
public PreparedStatement createInsert (Connection conn, Object po)
|
||||
throws SQLException
|
||||
{
|
||||
requireNotComputed("insert rows into");
|
||||
|
||||
try {
|
||||
StringBuilder insert = new StringBuilder();
|
||||
insert.append("insert into ").append(getTableName());
|
||||
@@ -449,7 +480,7 @@ public class DepotMarshaller<T>
|
||||
/**
|
||||
* Creates a statement that will update the supplied persistent object using the supplied key.
|
||||
*/
|
||||
public PreparedStatement createUpdate (Connection conn, Object po, Key key)
|
||||
public PreparedStatement createUpdate (Connection conn, Object po, Where key)
|
||||
throws SQLException
|
||||
{
|
||||
return createUpdate(conn, po, key, _columnFields);
|
||||
@@ -460,9 +491,11 @@ public class DepotMarshaller<T>
|
||||
* using the supplied key.
|
||||
*/
|
||||
public PreparedStatement createUpdate (
|
||||
Connection conn, Object po, Key key, String[] modifiedFields)
|
||||
Connection conn, Object po, Where key, String[] modifiedFields)
|
||||
throws SQLException
|
||||
{
|
||||
requireNotComputed("update rows in");
|
||||
|
||||
StringBuilder update = new StringBuilder();
|
||||
update.append("update ").append(getTableName()).append(" set ");
|
||||
int idx = 0;
|
||||
@@ -501,9 +534,11 @@ public class DepotMarshaller<T>
|
||||
* that match the supplied key.
|
||||
*/
|
||||
public PreparedStatement createPartialUpdate (
|
||||
Connection conn, Key key, String[] modifiedFields, Object[] modifiedValues)
|
||||
Connection conn, Where key, String[] modifiedFields, Object[] modifiedValues)
|
||||
throws SQLException
|
||||
{
|
||||
requireNotComputed("update rows in");
|
||||
|
||||
StringBuilder update = new StringBuilder();
|
||||
update.append("update ").append(getTableName()).append(" set ");
|
||||
int idx = 0;
|
||||
@@ -530,9 +565,11 @@ public class DepotMarshaller<T>
|
||||
/**
|
||||
* Creates a statement that will delete all rows matching the supplied key.
|
||||
*/
|
||||
public PreparedStatement createDelete (Connection conn, Key key)
|
||||
public PreparedStatement createDelete (Connection conn, Where key)
|
||||
throws SQLException
|
||||
{
|
||||
requireNotComputed("delete rows from");
|
||||
|
||||
StringBuilder query = new StringBuilder("delete from " + getTableName());
|
||||
key.appendClause(null, query);
|
||||
PreparedStatement pstmt = conn.prepareStatement(query.toString());
|
||||
@@ -545,9 +582,11 @@ public class DepotMarshaller<T>
|
||||
* SQL values, for all persistent objects that match the supplied key.
|
||||
*/
|
||||
public PreparedStatement createLiteralUpdate (
|
||||
Connection conn, Key key, String[] modifiedFields, Object[] modifiedValues)
|
||||
Connection conn, Where key, String[] modifiedFields, Object[] modifiedValues)
|
||||
throws SQLException
|
||||
{
|
||||
requireNotComputed("update rows in");
|
||||
|
||||
StringBuilder update = new StringBuilder();
|
||||
update.append("update ").append(getTableName()).append(" set ");
|
||||
for (int ii = 0; ii < modifiedFields.length; ii++) {
|
||||
@@ -595,6 +634,15 @@ public class DepotMarshaller<T>
|
||||
}
|
||||
}
|
||||
|
||||
protected void requireNotComputed (String action)
|
||||
throws SQLException
|
||||
{
|
||||
if (getTableName() == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't " + action + " computed entities [class=" + _pclass + "]");
|
||||
}
|
||||
}
|
||||
|
||||
/** The persistent object class that we manage. */
|
||||
protected Class<T> _pclass;
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ import java.util.Collection;
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.jdbc.ConnectionProvider;
|
||||
import com.samskivert.jdbc.depot.clause.QueryClause;
|
||||
import com.samskivert.jdbc.depot.clause.Where;
|
||||
import com.samskivert.util.ArrayUtil;
|
||||
|
||||
/**
|
||||
* Provides a base for classes that provide access to persistent objects. Also defines the
|
||||
@@ -61,17 +63,18 @@ public class DepotRepository
|
||||
protected <T> T load (Class<T> type, Comparable primaryKey, QueryClause... clauses)
|
||||
throws PersistenceException
|
||||
{
|
||||
return load(type, _ctx.getMarshaller(type).makePrimaryKey(primaryKey), clauses);
|
||||
clauses = ArrayUtil.append(clauses, _ctx.getMarshaller(type).makePrimaryKey(primaryKey));
|
||||
return load(type, clauses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the first persistent object that matches the supplied key.
|
||||
*/
|
||||
protected <T> T load (Class<T> type, Key key, QueryClause... clauses)
|
||||
protected <T> T load (Class<T> type, QueryClause... clauses)
|
||||
throws PersistenceException
|
||||
{
|
||||
final DepotMarshaller<T> marsh = _ctx.getMarshaller(type);
|
||||
return _ctx.invoke(new Query<T>(_ctx, type, key, clauses) {
|
||||
return _ctx.invoke(new Query<T>(_ctx, type, clauses) {
|
||||
public T invoke (Connection conn) throws SQLException {
|
||||
PreparedStatement stmt = createQuery(conn);
|
||||
try {
|
||||
@@ -91,24 +94,15 @@ public class DepotRepository
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all persistent objects of the specified type.
|
||||
*/
|
||||
protected <T,C extends Collection<T>> Collection<T> findAll (Class<T> type)
|
||||
throws PersistenceException
|
||||
{
|
||||
return findAll(type, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all persistent objects that match the specified key.
|
||||
*/
|
||||
protected <T,C extends Collection<T>> Collection<T> findAll (
|
||||
Class<T> type, Key key, QueryClause... clauses)
|
||||
Class<T> type, QueryClause... clauses)
|
||||
throws PersistenceException
|
||||
{
|
||||
final DepotMarshaller<T> marsh = _ctx.getMarshaller(type);
|
||||
return _ctx.invoke(new Query<ArrayList<T>>(_ctx, type, key, clauses) {
|
||||
return _ctx.invoke(new Query<ArrayList<T>>(_ctx, type, clauses) {
|
||||
public ArrayList<T> invoke (Connection conn) throws SQLException {
|
||||
PreparedStatement stmt = createQuery(conn);
|
||||
try {
|
||||
@@ -130,8 +124,7 @@ public class DepotRepository
|
||||
* Inserts the supplied persistent object into the database, assigning its primary key (if it
|
||||
* has one) in the process.
|
||||
*
|
||||
* @return the number of rows modified by this action, this should always
|
||||
* be one.
|
||||
* @return the number of rows modified by this action, this should always be one.
|
||||
*/
|
||||
protected int insert (final Object record)
|
||||
throws PersistenceException
|
||||
@@ -182,7 +175,7 @@ public class DepotRepository
|
||||
*
|
||||
* @return the number of rows modified by this action.
|
||||
*/
|
||||
protected int update (final Object record, final String ... modifiedFields)
|
||||
protected int update (final Object record, final String... modifiedFields)
|
||||
throws PersistenceException
|
||||
{
|
||||
final DepotMarshaller marsh = _ctx.getMarshaller(record.getClass());
|
||||
@@ -208,7 +201,7 @@ 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> int updatePartial (Class<T> type, Comparable primaryKey, Object... fieldsValues)
|
||||
throws PersistenceException
|
||||
{
|
||||
return updatePartial(
|
||||
@@ -225,7 +218,7 @@ public class DepotRepository
|
||||
*
|
||||
* @return the number of rows modified by this action.
|
||||
*/
|
||||
protected <T> int updatePartial (Class<T> type, Key key, Object ... fieldsValues)
|
||||
protected <T> int updatePartial (Class<T> type, Where key, Object... fieldsValues)
|
||||
throws PersistenceException
|
||||
{
|
||||
// separate the arguments into keys and values
|
||||
@@ -266,7 +259,7 @@ 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> int updateLiteral (Class<T> type, Comparable primaryKey, String... fieldsValues)
|
||||
throws PersistenceException
|
||||
{
|
||||
return updateLiteral(
|
||||
@@ -290,7 +283,7 @@ public class DepotRepository
|
||||
*
|
||||
* @return the number of rows modified by this action.
|
||||
*/
|
||||
protected <T> int updateLiteral (Class<T> type, Key key, String ... fieldsValues)
|
||||
protected <T> int updateLiteral (Class<T> type, Where key, String... fieldsValues)
|
||||
throws PersistenceException
|
||||
{
|
||||
// separate the arguments into keys and values
|
||||
@@ -387,7 +380,7 @@ public class DepotRepository
|
||||
*
|
||||
* @return the number of rows deleted by this action.
|
||||
*/
|
||||
protected <T> int deleteAll (Class<T> type, Key key)
|
||||
protected <T> int deleteAll (Class<T> type, Where key)
|
||||
throws PersistenceException
|
||||
{
|
||||
final DepotMarshaller marsh = _ctx.getMarshaller(type);
|
||||
|
||||
@@ -20,91 +20,68 @@
|
||||
|
||||
package com.samskivert.jdbc.depot;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.samskivert.jdbc.depot.clause.QueryClause;
|
||||
import com.samskivert.jdbc.depot.expression.ColumnExpression;
|
||||
|
||||
import com.samskivert.jdbc.depot.clause.Where;
|
||||
import com.samskivert.jdbc.depot.expression.ColumnExp;
|
||||
import com.samskivert.jdbc.depot.expression.ValueExp;
|
||||
import com.samskivert.jdbc.depot.operator.Conditionals.Equals;
|
||||
import com.samskivert.jdbc.depot.operator.Logic.And;
|
||||
import com.samskivert.jdbc.depot.operator.SQLOperator;
|
||||
|
||||
/**
|
||||
* Encapsulates a key used to match persistent objects in a query.
|
||||
*
|
||||
* TODO: Is it useful for this to implement QueryClause? Can it be meaningfully put on a peer level
|
||||
* with the other clauses?
|
||||
* Encapsulates a key used to match persistent objects in a query. This is a special form of
|
||||
* where clause that is meant to uniquely identify a specific row for caching purposes. It is
|
||||
* generated by the update/insert code, as well as instantiated directly by users.
|
||||
*/
|
||||
public class Key
|
||||
implements QueryClause
|
||||
public class Key extends Where
|
||||
{
|
||||
public ColumnExpression[] columns;
|
||||
public Comparable[] values;
|
||||
|
||||
public Key (String index, Comparable value)
|
||||
{
|
||||
this(new ColumnExpression(index), value);
|
||||
this(new ColumnExp(index), value);
|
||||
}
|
||||
|
||||
public Key (ColumnExpression column, Comparable value)
|
||||
public Key (ColumnExp column, Comparable value)
|
||||
{
|
||||
this(new ColumnExpression[] { column }, new Comparable[] { value });
|
||||
this(new ColumnExp[] { column }, new Comparable[] { value });
|
||||
}
|
||||
|
||||
public Key (ColumnExp index1, Comparable value1,
|
||||
ColumnExp index2, Comparable value2)
|
||||
{
|
||||
this(new ColumnExp[] { index1, index2 },
|
||||
new Comparable[] { value1, value2 });
|
||||
}
|
||||
|
||||
public Key (ColumnExp index1, Comparable value1,
|
||||
ColumnExp index2, Comparable value2,
|
||||
ColumnExp index3, Comparable value3)
|
||||
{
|
||||
this(new ColumnExp[] { index1, index2, index3 },
|
||||
new Comparable[] { value1, value2, value3 });
|
||||
}
|
||||
|
||||
public Key (String index1, Comparable value1, String index2, Comparable value2)
|
||||
{
|
||||
this(new ColumnExpression[] { new ColumnExpression(index1),
|
||||
new ColumnExpression(index2) },
|
||||
new Comparable[] { value1, value2 });
|
||||
this(new ColumnExp(index1), value1, new ColumnExp(index2), value2);
|
||||
}
|
||||
|
||||
public Key (String index1, Comparable value1, String index2, Comparable value2,
|
||||
String index3, Comparable value3)
|
||||
{
|
||||
this(new ColumnExpression[] { new ColumnExpression(index1),
|
||||
new ColumnExpression(index2),
|
||||
new ColumnExpression(index3) },
|
||||
new Comparable[] { value1, value2, value3 });
|
||||
this(new ColumnExp(index1), value1, new ColumnExp(index2), value2,
|
||||
new ColumnExp(index3), value3);
|
||||
}
|
||||
|
||||
public Key (String[] columns, Comparable[] values)
|
||||
public Key (ColumnExp[] columns, Comparable[] values)
|
||||
{
|
||||
ColumnExpression[] colExp = new ColumnExpression[columns.length];
|
||||
super(toCondition(columns, values));
|
||||
}
|
||||
|
||||
protected static SQLOperator toCondition (ColumnExp[] columns, Comparable[] values)
|
||||
{
|
||||
SQLOperator[] comparisons = new Equals[columns.length];
|
||||
for (int ii = 0; ii < columns.length; ii ++) {
|
||||
colExp[ii] = new ColumnExpression(columns[ii]);
|
||||
comparisons[ii] = new Equals(columns[ii], new ValueExp(values[ii]));
|
||||
}
|
||||
this.columns = colExp;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public Key (ColumnExpression[] columns, Comparable[] values)
|
||||
{
|
||||
this.columns = columns;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public List<Class> getClassSet() {
|
||||
return Arrays.asList(new Class[] { });
|
||||
}
|
||||
|
||||
public void appendClause (Query query, StringBuilder builder)
|
||||
{
|
||||
builder.append(" where ");
|
||||
for (int ii = 0; ii < columns.length; ii++) {
|
||||
if (ii > 0) {
|
||||
builder.append(" and ");
|
||||
}
|
||||
columns[ii].appendExpression(query, builder);
|
||||
builder.append(" = ?");
|
||||
}
|
||||
}
|
||||
|
||||
public int bindArguments (PreparedStatement stmt, int startIdx)
|
||||
throws SQLException
|
||||
{
|
||||
for (int ii = 0; ii < values.length; ii++) {
|
||||
stmt.setObject(startIdx++, values[ii]);
|
||||
}
|
||||
return startIdx;
|
||||
return new And(comparisons);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,19 +23,16 @@ package com.samskivert.jdbc.depot;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.samskivert.jdbc.depot.clause.Where;
|
||||
|
||||
/**
|
||||
* Encapsulates a modification of persistent objects.
|
||||
*/
|
||||
public abstract class Modifier
|
||||
{
|
||||
public Key getKey ()
|
||||
{
|
||||
return _key;
|
||||
}
|
||||
|
||||
public abstract int invoke (Connection conn) throws SQLException;
|
||||
|
||||
protected Modifier (Key key)
|
||||
protected Modifier (Where key)
|
||||
{
|
||||
_key = key;
|
||||
}
|
||||
@@ -47,5 +44,5 @@ public abstract class Modifier
|
||||
}
|
||||
}
|
||||
|
||||
protected Key _key;
|
||||
protected Where _key;
|
||||
}
|
||||
|
||||
@@ -32,13 +32,15 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.jdbc.depot.clause.FieldOverrideClause;
|
||||
import com.samskivert.jdbc.depot.clause.ForUpdateClause;
|
||||
import com.samskivert.jdbc.depot.clause.GroupByClause;
|
||||
import com.samskivert.jdbc.depot.clause.JoinClause;
|
||||
import com.samskivert.jdbc.depot.clause.LimitClause;
|
||||
import com.samskivert.jdbc.depot.clause.OrderByClause;
|
||||
import com.samskivert.jdbc.depot.clause.FieldOverride;
|
||||
import com.samskivert.jdbc.depot.clause.ForUpdate;
|
||||
import com.samskivert.jdbc.depot.clause.FromOverride;
|
||||
import com.samskivert.jdbc.depot.clause.GroupBy;
|
||||
import com.samskivert.jdbc.depot.clause.Join;
|
||||
import com.samskivert.jdbc.depot.clause.Limit;
|
||||
import com.samskivert.jdbc.depot.clause.OrderBy;
|
||||
import com.samskivert.jdbc.depot.clause.QueryClause;
|
||||
import com.samskivert.jdbc.depot.clause.Where;
|
||||
|
||||
/**
|
||||
* Encapsulates a non-modifying query of persistent objects.
|
||||
@@ -68,9 +70,6 @@ public abstract class Query<T>
|
||||
*/
|
||||
public String getTableAbbreviation (Class cl)
|
||||
{
|
||||
if (cl.equals(_mainType)) {
|
||||
return "T";
|
||||
}
|
||||
int ix = _classList.indexOf(cl);
|
||||
if (ix < 0) {
|
||||
throw new IllegalArgumentException("Unknown persistence class: " + cl);
|
||||
@@ -102,17 +101,23 @@ public abstract class Query<T>
|
||||
}
|
||||
skip = false;
|
||||
|
||||
FieldOverrideClause clause = _disMap.get(fields[ii]);
|
||||
FieldOverride clause = _disMap.get(fields[ii]);
|
||||
if (clause != null) {
|
||||
clause.appendClause(this, query);
|
||||
continue;
|
||||
}
|
||||
|
||||
Computed computed = mainMarshaller._fields.get(fields[ii]).getComputed();
|
||||
Computed computed = mainMarshaller._fields.get(fields[ii]).getComputed();
|
||||
if (computed == null) {
|
||||
// if it's neither overridden nor computed, it's a standard field
|
||||
query.append("T.").append(fields[ii]);
|
||||
continue;
|
||||
// make sure the object corresponds to a table, otherwise the whole thing is
|
||||
// computed
|
||||
if (mainMarshaller.getTableName() != null) {
|
||||
// if it's neither overridden nor computed, it's a standard field
|
||||
query.append(getTableAbbreviation(_mainType)).append(".").append(fields[ii]);
|
||||
continue;
|
||||
}
|
||||
throw new SQLException(
|
||||
"@Computed entity field without definition [field=" + fields[ii] + "]");
|
||||
}
|
||||
|
||||
// check if the computed field has a literal SQL definition
|
||||
@@ -128,13 +133,21 @@ public abstract class Query<T>
|
||||
"@Computed(required) field without definition [field=" + fields[ii] + "]");
|
||||
}
|
||||
}
|
||||
query.append(" from " + mainMarshaller.getTableName() + " as T ");
|
||||
|
||||
for (JoinClause clause : _joinClauses) {
|
||||
if (_fromOverride != null) {
|
||||
_fromOverride.appendClause(this, query);
|
||||
} else if (mainMarshaller.getTableName() != null) {
|
||||
query.append(" from ").append(mainMarshaller.getTableName());
|
||||
query.append(" as ").append(getTableAbbreviation(_mainType));
|
||||
} else {
|
||||
throw new SQLException("Query on @Computed entity with no FromOverrideClause.");
|
||||
}
|
||||
|
||||
for (Join clause : _joinClauses) {
|
||||
clause.appendClause(this, query);
|
||||
}
|
||||
if (_key != null) {
|
||||
_key.appendClause(this, query);
|
||||
if (_where != null) {
|
||||
_where.appendClause(this, query);
|
||||
}
|
||||
if (_groupBy != null) {
|
||||
_groupBy.appendClause(this, query);
|
||||
@@ -151,8 +164,8 @@ public abstract class Query<T>
|
||||
|
||||
PreparedStatement pstmt = conn.prepareStatement(query.toString());
|
||||
int argIdx = 1;
|
||||
if (_key != null) {
|
||||
argIdx = _key.bindArguments(pstmt, argIdx);
|
||||
if (_where != null) {
|
||||
argIdx = _where.bindArguments(pstmt, argIdx);
|
||||
}
|
||||
if (_groupBy != null) {
|
||||
argIdx = _groupBy.bindArguments(pstmt, argIdx);
|
||||
@@ -175,55 +188,66 @@ public abstract class Query<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 Query (PersistenceContext ctx, Class type, Key key, QueryClause... clauses)
|
||||
protected Query (PersistenceContext ctx, Class type, QueryClause... clauses)
|
||||
throws PersistenceException
|
||||
{
|
||||
_key = key;
|
||||
_mainType = type;
|
||||
Set<Class> classSet = new HashSet<Class>();
|
||||
if (type != null) {
|
||||
classSet.add(type);
|
||||
}
|
||||
if (_key != null) {
|
||||
classSet.addAll(_key.getClassSet());
|
||||
}
|
||||
|
||||
for (QueryClause clause : clauses) {
|
||||
if (clause instanceof JoinClause) {
|
||||
_joinClauses.add((JoinClause) clause);
|
||||
classSet.addAll(((JoinClause) clause).getClassSet());
|
||||
if (clause instanceof Where) {
|
||||
if (_where != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Query can't contain multiple Where clauses.");
|
||||
}
|
||||
_where = (Where) clause;
|
||||
|
||||
} else if (clause instanceof FieldOverrideClause) {
|
||||
_disMap.put(((FieldOverrideClause) clause).getField(),
|
||||
((FieldOverrideClause) clause));
|
||||
} else if (clause instanceof FromOverride) {
|
||||
if (_fromOverride != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Query can't contain multiple FromOverride clauses.");
|
||||
}
|
||||
_fromOverride = (FromOverride) clause;
|
||||
classSet.addAll(_fromOverride.getClassSet());
|
||||
|
||||
} else if (clause instanceof OrderByClause) {
|
||||
} else if (clause instanceof Join) {
|
||||
_joinClauses.add((Join) clause);
|
||||
classSet.addAll(((Join) clause).getClassSet());
|
||||
|
||||
} else if (clause instanceof FieldOverride) {
|
||||
_disMap.put(((FieldOverride) clause).getField(),
|
||||
((FieldOverride) clause));
|
||||
|
||||
} else if (clause instanceof OrderBy) {
|
||||
if (_orderBy != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Query can't contain multiple OrderBy clauses.");
|
||||
}
|
||||
_orderBy = (OrderByClause) clause;
|
||||
_orderBy = (OrderBy) clause;
|
||||
|
||||
} else if (clause instanceof GroupByClause) {
|
||||
} else if (clause instanceof GroupBy) {
|
||||
if (_groupBy != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Query can't contain multiple GroupBy clauses.");
|
||||
}
|
||||
_groupBy = (GroupByClause) clause;
|
||||
_groupBy = (GroupBy) clause;
|
||||
|
||||
} else if (clause instanceof LimitClause) {
|
||||
} else if (clause instanceof Limit) {
|
||||
if (_limit != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Query can't contain multiple Limit clauses.");
|
||||
}
|
||||
_limit = (LimitClause) clause;
|
||||
_limit = (Limit) clause;
|
||||
|
||||
} else if (clause instanceof ForUpdateClause) {
|
||||
} else if (clause instanceof ForUpdate) {
|
||||
if (_forUpdate != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Query can't contain multiple For Update clauses.");
|
||||
}
|
||||
_forUpdate = (ForUpdateClause) clause;
|
||||
_forUpdate = (ForUpdate) clause;
|
||||
}
|
||||
}
|
||||
_classMap = new HashMap<Class, DepotMarshaller>();
|
||||
@@ -234,9 +258,6 @@ public abstract class Query<T>
|
||||
_classList = new ArrayList<Class>(classSet);
|
||||
}
|
||||
|
||||
/** The key to this query, or null. Translated into a WHERE clause. */
|
||||
protected Key _key;
|
||||
|
||||
/** The persistent class to instantiate for the results. */
|
||||
protected Class _mainType;
|
||||
|
||||
@@ -247,20 +268,26 @@ public abstract class Query<T>
|
||||
protected Map<Class, DepotMarshaller> _classMap;
|
||||
|
||||
/** Persistent class fields mapped to field override clauses. */
|
||||
protected Map<String, FieldOverrideClause> _disMap = new HashMap<String, FieldOverrideClause>();
|
||||
protected Map<String, FieldOverride> _disMap = new HashMap<String, FieldOverride>();
|
||||
|
||||
/** The from override clause, if any. */
|
||||
protected FromOverride _fromOverride;
|
||||
|
||||
/** The where clause. */
|
||||
protected Where _where;
|
||||
|
||||
/** A list of join clauses, each potentially referencing a new class. */
|
||||
protected List<JoinClause> _joinClauses = new ArrayList<JoinClause>();
|
||||
protected List<Join> _joinClauses = new ArrayList<Join>();
|
||||
|
||||
/** The order by clause, if any. */
|
||||
protected OrderByClause _orderBy;
|
||||
protected OrderBy _orderBy;
|
||||
|
||||
/** The group by clause, if any. */
|
||||
protected GroupByClause _groupBy;
|
||||
protected GroupBy _groupBy;
|
||||
|
||||
/** The limit clause, if any. */
|
||||
protected LimitClause _limit;
|
||||
|
||||
protected Limit _limit;
|
||||
|
||||
/** The For Update clause, if any. */
|
||||
protected ForUpdateClause _forUpdate;
|
||||
protected ForUpdate _forUpdate;
|
||||
}
|
||||
|
||||
+24
-9
@@ -26,28 +26,43 @@ import java.util.Collection;
|
||||
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
import com.samskivert.jdbc.depot.expression.ColumnExp;
|
||||
import com.samskivert.jdbc.depot.expression.LiteralExp;
|
||||
import com.samskivert.jdbc.depot.expression.SQLExpression;
|
||||
|
||||
/**
|
||||
* Redirects one field of the persistent object we're creating from its default associated column
|
||||
* to a general {@link SQLExpression}.
|
||||
*
|
||||
*
|
||||
* Thus the select portion of a query can include a reference to a different column in a different
|
||||
* table through a {@link ColumnExpression}, or a literal expression such as COUNT(*) through a
|
||||
* {@link LiteralExpression}.
|
||||
*/
|
||||
public class FieldOverrideClause
|
||||
* table through a {@link ColumnExp}, or a literal expression such as COUNT(*) through a
|
||||
* {@link LiteralExp}.
|
||||
*/
|
||||
public class FieldOverride
|
||||
implements QueryClause
|
||||
{
|
||||
public FieldOverrideClause (String field, SQLExpression override)
|
||||
public FieldOverride (String field, String str)
|
||||
throws PersistenceException
|
||||
{
|
||||
this(field, new LiteralExp(str));
|
||||
}
|
||||
|
||||
public FieldOverride (String field, Class pClass, String pCol)
|
||||
throws PersistenceException
|
||||
{
|
||||
this(field, new ColumnExp(pClass, pCol));
|
||||
}
|
||||
|
||||
public FieldOverride (String field, SQLExpression override)
|
||||
throws PersistenceException
|
||||
{
|
||||
super();
|
||||
_field = field;
|
||||
_override = override;
|
||||
}
|
||||
|
||||
/** The field we're overriding. The Query object uses this for indexing. */
|
||||
/**
|
||||
* The field we're overriding. The Query object uses this for indexing.
|
||||
*/
|
||||
public String getField ()
|
||||
{
|
||||
return _field;
|
||||
@@ -72,7 +87,7 @@ public class FieldOverrideClause
|
||||
{
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
|
||||
/** The name of the field on the persistent object to override. */
|
||||
protected String _field;
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ import com.samskivert.jdbc.depot.Query;
|
||||
/**
|
||||
* Represents a FOR UPDATE clause.
|
||||
*/
|
||||
public class ForUpdateClause
|
||||
public class ForUpdate
|
||||
implements QueryClause
|
||||
{
|
||||
// from QueryClause
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 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.clause;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
|
||||
/**
|
||||
* Completely overrides the FROM clause, if it exists.
|
||||
*/
|
||||
public class FromOverride
|
||||
implements QueryClause
|
||||
{
|
||||
public FromOverride (Class... fromClasses)
|
||||
throws PersistenceException
|
||||
{
|
||||
_fromClasses = fromClasses;
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public Collection<Class> getClassSet ()
|
||||
{
|
||||
return Arrays.asList(_fromClasses);
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public void appendClause (Query query, StringBuilder builder)
|
||||
{
|
||||
builder.append(" from " );
|
||||
for (int ii = 0; ii < _fromClasses.length; ii++) {
|
||||
if (ii > 0) {
|
||||
builder.append(", ");
|
||||
}
|
||||
builder.append(query.getTableName(_fromClasses[ii])).
|
||||
append(" as ").
|
||||
append(query.getTableAbbreviation(_fromClasses[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;
|
||||
}
|
||||
+2
-3
@@ -30,12 +30,11 @@ import com.samskivert.jdbc.depot.expression.SQLExpression;
|
||||
/**
|
||||
* Represents a GROUP BY clause.
|
||||
*/
|
||||
public class GroupByClause
|
||||
public class GroupBy
|
||||
implements QueryClause
|
||||
{
|
||||
public GroupByClause (SQLExpression... values)
|
||||
public GroupBy (SQLExpression... values)
|
||||
{
|
||||
super();
|
||||
_values = values;
|
||||
}
|
||||
|
||||
+27
-15
@@ -27,24 +27,39 @@ import java.util.Collection;
|
||||
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
import com.samskivert.jdbc.depot.expression.ColumnExp;
|
||||
import com.samskivert.jdbc.depot.operator.SQLOperator;
|
||||
import com.samskivert.jdbc.depot.operator.Conditionals.*;
|
||||
|
||||
/**
|
||||
* Represents a JOIN -- currently just an INNER one.
|
||||
*/
|
||||
public class JoinClause
|
||||
public class Join
|
||||
implements QueryClause
|
||||
{
|
||||
public JoinClause (String pCol, Class joinClass, String jCol)
|
||||
public Join (Class pClass, String pCol, Class joinClass, String jCol)
|
||||
throws PersistenceException
|
||||
{
|
||||
super();
|
||||
_primaryColumn = pCol;
|
||||
_joinClass = joinClass;
|
||||
_joinColumn = jCol;
|
||||
_joinCondition = new Equals(new ColumnExp(joinClass, jCol), new ColumnExp(pClass, pCol));
|
||||
}
|
||||
|
||||
public Join (ColumnExp primary, ColumnExp join)
|
||||
throws PersistenceException
|
||||
{
|
||||
_joinClass = join.pClass;
|
||||
_joinCondition = new Equals(primary, join);
|
||||
}
|
||||
|
||||
public Join (Class joinClass, SQLOperator joinCondition)
|
||||
{
|
||||
_joinClass = joinClass;
|
||||
_joinCondition = joinCondition;
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public Collection<Class> getClassSet () {
|
||||
public Collection<Class> getClassSet ()
|
||||
{
|
||||
return Arrays.asList(new Class[] { _joinClass });
|
||||
}
|
||||
|
||||
@@ -52,24 +67,21 @@ public class JoinClause
|
||||
public void appendClause (Query query, StringBuilder builder)
|
||||
{
|
||||
builder.append(" inner join " );
|
||||
String jAbbrev = query.getTableAbbreviation(_joinClass);
|
||||
builder.append(query.getTableName(_joinClass) + " as " + jAbbrev + " on T." +
|
||||
_primaryColumn + " = " + jAbbrev + "." + _joinColumn);
|
||||
builder.append(query.getTableName(_joinClass)).append(" as ");
|
||||
builder.append(query.getTableAbbreviation(_joinClass)).append(" on ");
|
||||
_joinCondition.appendExpression(query, builder);
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException
|
||||
{
|
||||
return argIdx;
|
||||
return _joinCondition.bindArguments(pstmt, argIdx);
|
||||
}
|
||||
|
||||
/** The column on which to join. */
|
||||
protected String _primaryColumn;
|
||||
|
||||
/** The class of the table we're to join against. */
|
||||
protected Class _joinClass;
|
||||
|
||||
/** The column we're joining against. */
|
||||
protected String _joinColumn;
|
||||
/** The condition used to join in the new table. */
|
||||
protected SQLOperator _joinCondition;
|
||||
}
|
||||
+3
-4
@@ -29,12 +29,11 @@ import com.samskivert.jdbc.depot.Query;
|
||||
/**
|
||||
* Represents a LIMIT/OFFSET clause, for pagination.
|
||||
*/
|
||||
public class LimitClause
|
||||
public class Limit
|
||||
implements QueryClause
|
||||
{
|
||||
public LimitClause (int offset, int count)
|
||||
public Limit (int offset, int count)
|
||||
{
|
||||
super();
|
||||
_offset = offset;
|
||||
_count = count;
|
||||
}
|
||||
@@ -59,7 +58,7 @@ public class LimitClause
|
||||
pstmt.setObject(argIdx++, _offset);
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
|
||||
/** The first row of the result set to return. */
|
||||
protected int _offset;
|
||||
|
||||
+4
-5
@@ -30,15 +30,14 @@ import com.samskivert.jdbc.depot.expression.SQLExpression;
|
||||
/**
|
||||
* Represents an ORDER BY clause.
|
||||
*/
|
||||
public class OrderByClause
|
||||
public class OrderBy
|
||||
implements QueryClause
|
||||
{
|
||||
public OrderByClause (SQLExpression... values)
|
||||
public OrderBy (SQLExpression... values)
|
||||
{
|
||||
super();
|
||||
_values = values;
|
||||
}
|
||||
|
||||
|
||||
// from QueryClause
|
||||
public Collection<Class> getClassSet ()
|
||||
{
|
||||
@@ -67,7 +66,7 @@ public class OrderByClause
|
||||
}
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
|
||||
/** The expressions that are generated for the clause. */
|
||||
protected SQLExpression[] _values;
|
||||
|
||||
@@ -38,8 +38,8 @@ public interface QueryClause
|
||||
public Collection<Class> getClassSet ();
|
||||
|
||||
/**
|
||||
* Construct the SQL form of this query clause The implementor is invited to call methods on
|
||||
* the Query object to e.g. resolve the 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 (Query query, StringBuilder builder);
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 Michael Bayne
|
||||
//
|
||||
// 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.clause;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
import com.samskivert.jdbc.depot.clause.QueryClause;
|
||||
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 Where (SQLOperator condition)
|
||||
{
|
||||
_condition = condition;
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public List<Class> getClassSet()
|
||||
{
|
||||
return Arrays.asList(new Class[] { });
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public void appendClause (Query query, StringBuilder builder)
|
||||
{
|
||||
builder.append(" where ");
|
||||
_condition.appendExpression(query, builder);
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException
|
||||
{
|
||||
return _condition.bindArguments(pstmt, argIdx);
|
||||
}
|
||||
|
||||
protected SQLOperator _condition;
|
||||
}
|
||||
+17
-16
@@ -26,32 +26,38 @@ import java.sql.SQLException;
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
|
||||
/**
|
||||
* An expression identifying a column of a class, e.g. GameRecord.itemId. If no class is given, no
|
||||
* disambiguation occurs in the generated SQL.
|
||||
* An expression identifying a column of a class, e.g. GameRecord.itemId. If no class is given,
|
||||
* no disambiguation occurs in the generated SQL.
|
||||
*/
|
||||
public class ColumnExpression
|
||||
public class ColumnExp
|
||||
implements SQLExpression
|
||||
{
|
||||
public ColumnExpression (String column)
|
||||
/** The table that hosts the column we reference, or null. */
|
||||
final public Class pClass;
|
||||
|
||||
/** The name of the column we reference. */
|
||||
final public String pColumn;
|
||||
|
||||
public ColumnExp (String column)
|
||||
{
|
||||
this(null, column);
|
||||
}
|
||||
|
||||
public ColumnExpression (Class c, String column)
|
||||
public ColumnExp (Class c, String column)
|
||||
{
|
||||
super();
|
||||
_class = c;
|
||||
_column = column;
|
||||
pClass = c;
|
||||
this.pColumn = column;
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void appendExpression (Query query, StringBuilder builder)
|
||||
{
|
||||
if (_class == null || query == null) {
|
||||
builder.append(_column);
|
||||
if (pClass == null || query == null) {
|
||||
builder.append(pColumn);
|
||||
} else {
|
||||
String tRef = query.getTableAbbreviation(_class);
|
||||
builder.append(tRef).append(".").append(_column);
|
||||
String tRef = query.getTableAbbreviation(pClass);
|
||||
builder.append(tRef).append(".").append(pColumn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,9 +68,4 @@ public class ColumnExpression
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
/** The table that hosts the column we reference, or null. */
|
||||
protected Class _class;
|
||||
|
||||
/** The name of the column we reference. */
|
||||
protected String _column;
|
||||
}
|
||||
+2
-2
@@ -28,10 +28,10 @@ import com.samskivert.jdbc.depot.Query;
|
||||
/**
|
||||
* An expression for things we don't support natively, e.g. COUNT(*).
|
||||
*/
|
||||
public class LiteralExpression
|
||||
public class LiteralExp
|
||||
implements SQLExpression
|
||||
{
|
||||
public LiteralExpression (String text)
|
||||
public LiteralExp (String text)
|
||||
{
|
||||
super();
|
||||
_text = text;
|
||||
+2
-3
@@ -28,12 +28,11 @@ import com.samskivert.jdbc.depot.Query;
|
||||
/**
|
||||
* A Java value that is bound as a parameter to the query, e.g. 1 or 'abc'.
|
||||
*/
|
||||
public class ValueExpression
|
||||
public class ValueExp
|
||||
implements SQLExpression
|
||||
{
|
||||
public ValueExpression (Comparable _value)
|
||||
public ValueExp (Comparable _value)
|
||||
{
|
||||
super();
|
||||
this._value = _value;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 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.operator;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
import com.samskivert.jdbc.depot.expression.ColumnExp;
|
||||
import com.samskivert.jdbc.depot.expression.SQLExpression;
|
||||
import com.samskivert.jdbc.depot.expression.ValueExp;
|
||||
|
||||
/**
|
||||
* A convenient container for implementations of conditional operators. Classes that value brevity
|
||||
* over disambiguation will import Conditionals.* and construct queries with Equals() and In();
|
||||
* classes that feel otherwise will use Conditionals.Equals() and Conditionals.In().
|
||||
*/
|
||||
public abstract class Conditionals
|
||||
{
|
||||
/** The SQL '=' operator. */
|
||||
public static class Equals extends BinaryOperator
|
||||
{
|
||||
public Equals (SQLExpression column, Comparable value)
|
||||
{
|
||||
super(column, value);
|
||||
}
|
||||
|
||||
public Equals (SQLExpression column, SQLExpression value)
|
||||
{
|
||||
super(column, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String operator()
|
||||
{
|
||||
return "=";
|
||||
}
|
||||
}
|
||||
|
||||
/** The SQL 'in (...)' operator. */
|
||||
public static class In
|
||||
implements SQLOperator
|
||||
{
|
||||
public In (Class pClass, String pColumn, Comparable... values)
|
||||
{
|
||||
this(new ColumnExp(pClass, pColumn), values);
|
||||
}
|
||||
|
||||
public In (ColumnExp column, Comparable... values)
|
||||
{
|
||||
if (values.length == 0) {
|
||||
throw new IllegalArgumentException("In() condition needs at least one value.");
|
||||
}
|
||||
_column = column;
|
||||
_values = values;
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void appendExpression (Query query, StringBuilder builder)
|
||||
{
|
||||
_column.appendExpression(query, builder);
|
||||
builder.append(" in (");
|
||||
for (int ii = 0; ii < _values.length; ii ++) {
|
||||
if (ii > 0) {
|
||||
builder.append(", ");
|
||||
}
|
||||
builder.append("?");
|
||||
}
|
||||
builder.append(")");
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException
|
||||
{
|
||||
for (int ii = 0; ii < _values.length; ii++) {
|
||||
pstmt.setObject(argIdx ++, _values[ii]);
|
||||
}
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
protected ColumnExp _column;
|
||||
protected Comparable[] _values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the real work for simple binary operators such as Equals.
|
||||
*/
|
||||
protected abstract static class BinaryOperator implements SQLOperator
|
||||
{
|
||||
public BinaryOperator (SQLExpression lhs, SQLExpression rhs)
|
||||
{
|
||||
_lhs = lhs;
|
||||
_rhs = rhs;
|
||||
}
|
||||
|
||||
public BinaryOperator (SQLExpression lhs, Comparable rhs)
|
||||
{
|
||||
this(lhs, new ValueExp(rhs));
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void appendExpression (Query query, StringBuilder builder)
|
||||
{
|
||||
_lhs.appendExpression(query, builder);
|
||||
builder.append(operator());
|
||||
_rhs.appendExpression(query, builder);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException
|
||||
{
|
||||
argIdx = _lhs.bindArguments(pstmt, argIdx);
|
||||
argIdx = _rhs.bindArguments(pstmt, argIdx);
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string representation of the operator.
|
||||
*/
|
||||
protected abstract String operator();
|
||||
|
||||
protected SQLExpression _lhs;
|
||||
protected SQLExpression _rhs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 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.operator;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
|
||||
/**
|
||||
* A convenient container for implementations of logical operators. Classes that value brevity
|
||||
* over disambiguation will import Logic.* and construct queries with And() and Not(); classes that
|
||||
* feel otherwise will use Logic.And() and Logic.Not().
|
||||
*/
|
||||
public abstract class Logic
|
||||
{
|
||||
/**
|
||||
* Represents a condition that is false iff all its subconditions are false.
|
||||
*/
|
||||
public static class Or extends MultiOperator
|
||||
{
|
||||
public Or (SQLOperator... conditions)
|
||||
{
|
||||
super(conditions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String operator()
|
||||
{
|
||||
return "or";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a condition that is true iff all its subconditions are true.
|
||||
*/
|
||||
public static class And extends MultiOperator
|
||||
{
|
||||
public And (SQLOperator... conditions)
|
||||
{
|
||||
super(conditions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String operator()
|
||||
{
|
||||
return "and";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents the truth negation of another conditon.
|
||||
*/
|
||||
public static class Not
|
||||
implements SQLOperator
|
||||
{
|
||||
public Not (SQLOperator condition)
|
||||
{
|
||||
super();
|
||||
_condition = condition;
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void appendExpression (Query query, StringBuilder builder)
|
||||
{
|
||||
builder.append(" not (");
|
||||
_condition.appendExpression(query, builder);
|
||||
builder.append(")");
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException
|
||||
{
|
||||
return _condition.bindArguments(pstmt, argIdx);
|
||||
}
|
||||
|
||||
protected SQLOperator _condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an operator with any number of operands.
|
||||
*/
|
||||
protected abstract static class MultiOperator
|
||||
implements SQLOperator
|
||||
{
|
||||
public MultiOperator (SQLOperator... conditions)
|
||||
{
|
||||
super();
|
||||
_conditions = conditions;
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void appendExpression (Query query, StringBuilder builder)
|
||||
{
|
||||
for (int ii = 0; ii < _conditions.length; ii++) {
|
||||
if (ii > 0) {
|
||||
builder.append(" ").append(operator()).append(" ");
|
||||
}
|
||||
builder.append("(");
|
||||
_conditions[ii].appendExpression(query, builder);
|
||||
builder.append(")");
|
||||
}
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException
|
||||
{
|
||||
for (int ii = 0; ii < _conditions.length; ii++) {
|
||||
argIdx = _conditions[ii].bindArguments(pstmt, argIdx);
|
||||
}
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text infix to be used to join expressions together.
|
||||
*/
|
||||
protected abstract String operator ();
|
||||
|
||||
protected SQLOperator[] _conditions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 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.operator;
|
||||
|
||||
import com.samskivert.jdbc.depot.expression.SQLExpression;
|
||||
|
||||
/**
|
||||
* A common interface for operator hierarchies in SQL. The main purpose of breaking this out from
|
||||
* SQLExpression is to capture the recursive nature of e.g. the logical operators, which work on
|
||||
* other SQLOperators but not general SQLExpressions.
|
||||
*/
|
||||
public interface SQLOperator extends SQLExpression
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user