Added support for supplying a field mask along with a query by example
object so that builtin fields can be used with query by example. git-svn-id: https://samskivert.googlecode.com/svn/trunk@682 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -62,7 +62,8 @@ public class Cursor {
|
||||
}
|
||||
}
|
||||
synchronized(qbeStmt) {
|
||||
table.bindQueryVariables(qbeStmt, qbeObject);
|
||||
table.bindQueryVariables(
|
||||
qbeStmt, qbeObject, qbeMask);
|
||||
result = qbeStmt.executeQuery();
|
||||
qbeStmt.clearParameters();
|
||||
}
|
||||
@@ -219,15 +220,17 @@ public class Cursor {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
protected Cursor(Table table, Session session, int nTables, Object obj) {
|
||||
protected Cursor(Table table, Session session, int nTables,
|
||||
Object obj, FieldMask mask) {
|
||||
if (session == null) {
|
||||
session = ((SessionThread)Thread.currentThread()).session;
|
||||
}
|
||||
this.table = table;
|
||||
this.session = session;
|
||||
this.nTables = nTables;
|
||||
qbeObject = obj;
|
||||
query = table.buildQueryList(obj);
|
||||
qbeObject = obj;
|
||||
qbeMask = mask;
|
||||
query = table.buildQueryList(obj, mask);
|
||||
stmt = null;
|
||||
}
|
||||
|
||||
@@ -239,5 +242,6 @@ public class Cursor {
|
||||
private Statement stmt;
|
||||
private Object currObject;
|
||||
private Object qbeObject;
|
||||
private FieldMask qbeMask;
|
||||
}
|
||||
|
||||
|
||||
@@ -172,38 +172,61 @@ public class Table {
|
||||
}
|
||||
|
||||
/** Select records from database table using <I>obj</I> object as
|
||||
* template for selection. All non-builtin fields of this object,
|
||||
* which are not null, are compared with correspondent table values.
|
||||
* template.
|
||||
*
|
||||
* @param obj object for construction search condition: selected objects
|
||||
* should match all non-null fields of specified object.
|
||||
* @param obj example object for search: selected objects should match
|
||||
* all non-null fields.
|
||||
*/
|
||||
public final Cursor queryByExample(Object obj) {
|
||||
return new Cursor(this, session, 1, obj);
|
||||
return new Cursor(this, session, 1, obj, null);
|
||||
}
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
public final Cursor queryByExample(Object obj, FieldMask mask) {
|
||||
return new Cursor(this, session, 1, obj, mask);
|
||||
}
|
||||
|
||||
/** Select records from database table using <I>obj</I> object as
|
||||
* template for selection. All non-builtin fields of this object,
|
||||
* which are not null, are compared with correspondent table values.
|
||||
*
|
||||
* @param obj object for construction search condition: selected objects
|
||||
* should match all non-null fields of specified object.
|
||||
* @param session user database session
|
||||
* @param obj object for construction search condition: selected
|
||||
* objects should match all non-null fields of specified object.
|
||||
* @param session user database session.
|
||||
*/
|
||||
public final Cursor queryByExample(Object obj, Session session) {
|
||||
return new Cursor(this, session, 1, obj);
|
||||
return queryByExample(obj, session, null);
|
||||
}
|
||||
|
||||
/** Select records from database table using <I>obj</I> object as
|
||||
* template for selection.
|
||||
*
|
||||
* @param obj example object for search.
|
||||
* @param session user database session.
|
||||
* @param mask field mask indicating which fields in the example
|
||||
* object should be used when building the query.
|
||||
*/
|
||||
public final Cursor queryByExample(Object obj, Session session,
|
||||
FieldMask mask) {
|
||||
return new Cursor(this, session, 1, obj, mask);
|
||||
}
|
||||
|
||||
/** Select records from specified and derived database tables using
|
||||
* <I>obj</I> object as template for selection.
|
||||
* All non-builtin fields of this object,
|
||||
* which are not null, are compared with correspondent table values.
|
||||
* <I>obj</I> object as template for selection. All non-builtin
|
||||
* fields of this object, which are not null, are compared with
|
||||
* correspondent table values.
|
||||
*
|
||||
* @param obj object for construction search condition: selected objects
|
||||
* should match all non-null fields of specified object.
|
||||
* @param obj object for construction search condition: selected
|
||||
* objects should match all non-null fields of specified object.
|
||||
*/
|
||||
public final Cursor queryAllByExample(Object obj) {
|
||||
return new Cursor(this, session, nDerived+1, obj);
|
||||
return new Cursor(this, session, nDerived+1, obj, null);
|
||||
}
|
||||
|
||||
/** Select records from specified and derived database tables using
|
||||
@@ -216,7 +239,7 @@ public class Table {
|
||||
* @param session user database session
|
||||
*/
|
||||
public final Cursor queryAllByExample(Object obj, Session session) {
|
||||
return new Cursor(this, session, nDerived+1, obj);
|
||||
return new Cursor(this, session, nDerived+1, obj, null);
|
||||
}
|
||||
|
||||
/** Insert new record in the table. Values of inserted record fields
|
||||
@@ -972,10 +995,11 @@ public class Table {
|
||||
}
|
||||
|
||||
protected final void bindQueryVariables(PreparedStatement pstmt,
|
||||
Object obj)
|
||||
Object obj,
|
||||
FieldMask mask)
|
||||
throws SQLException
|
||||
{
|
||||
bindQueryVariables(pstmt, obj, 0, nFields, 0);
|
||||
bindQueryVariables(pstmt, obj, 0, nFields, 0, mask);
|
||||
}
|
||||
|
||||
protected final void updateVariables(ResultSet result, Object obj)
|
||||
@@ -995,10 +1019,10 @@ public class Table {
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
protected final String buildQueryList(Object qbe)
|
||||
protected final String buildQueryList(Object qbe, FieldMask mask)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buildQueryList(buf, qbe, 0, nFields);
|
||||
buildQueryList(buf, qbe, 0, nFields, mask);
|
||||
if (buf.length() > 0) {
|
||||
buf.insert(0, " where ");
|
||||
}
|
||||
@@ -1047,8 +1071,9 @@ public class Table {
|
||||
}
|
||||
|
||||
private final int bindQueryVariables(PreparedStatement pstmt, Object obj,
|
||||
int i, int end, int column)
|
||||
throws SQLException
|
||||
int i, int end, int column,
|
||||
FieldMask mask)
|
||||
throws SQLException
|
||||
{
|
||||
try {
|
||||
while (i < end) {
|
||||
@@ -1057,25 +1082,48 @@ public class Table {
|
||||
if (!fd.field.getDeclaringClass().isInstance(obj)) {
|
||||
return column;
|
||||
}
|
||||
int nComponents =
|
||||
fd.isCompound() ? fd.outType-FieldDescriptor.tCompound : 0;
|
||||
if (!fd.isBuiltin()
|
||||
&& fd.outType != FieldDescriptor.tClosure
|
||||
&& (comp = fd.field.get(obj)) != null)
|
||||
{
|
||||
int nComponents = fd.isCompound() ?
|
||||
fd.outType-FieldDescriptor.tCompound : 0;
|
||||
|
||||
try {
|
||||
// skip closure fields (because querying by them makes
|
||||
// no sense)
|
||||
if (fd.outType == FieldDescriptor.tClosure) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if a field mask is specified, use that to determine
|
||||
// whether or not the field should be skipped
|
||||
if (mask != null) {
|
||||
if (!mask.isModified(i-1)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// look up the value of the field
|
||||
comp = fd.field.get(obj);
|
||||
|
||||
// if no field mask was specified, ignore builtin
|
||||
// fields and those that are null
|
||||
if (mask == null && (fd.isBuiltin() || comp == null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!fd.bindVariable(pstmt, obj, ++column)) {
|
||||
column = bindQueryVariables(pstmt, comp,
|
||||
i,i+nComponents,column-1);
|
||||
column = bindQueryVariables(
|
||||
pstmt, comp, i, i+nComponents, column-1, mask);
|
||||
}
|
||||
}
|
||||
i += nComponents;
|
||||
|
||||
} finally {
|
||||
i += nComponents;
|
||||
}
|
||||
}
|
||||
} catch(IllegalAccessException ex) { throw new IllegalAccessError(); }
|
||||
return column;
|
||||
}
|
||||
|
||||
private final void buildQueryList(StringBuffer buf, Object qbe,
|
||||
int i, int end)
|
||||
int i, int end, FieldMask mask)
|
||||
{
|
||||
try {
|
||||
while (i < end) {
|
||||
@@ -1083,21 +1131,44 @@ public class Table {
|
||||
FieldDescriptor fd = fields[i++];
|
||||
int nComponents =
|
||||
fd.isCompound() ? fd.outType-FieldDescriptor.tCompound : 0;
|
||||
if (!fd.isBuiltin()
|
||||
&& fd.outType != FieldDescriptor.tClosure
|
||||
&& (comp = fd.field.get(qbe)) != null)
|
||||
{
|
||||
if (nComponents != 0) {
|
||||
buildQueryList(buf, comp, i, i+nComponents);
|
||||
} else {
|
||||
if (buf.length() != 0) {
|
||||
buf.append(",");
|
||||
}
|
||||
buf.append(fd.name);
|
||||
buf.append("=?");
|
||||
}
|
||||
}
|
||||
i += nComponents;
|
||||
|
||||
try {
|
||||
// skip closure fields (because querying by them makes
|
||||
// no sense)
|
||||
if (fd.outType == FieldDescriptor.tClosure) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if a field mask is specified, use that to determine
|
||||
// whether or not the field should be skipped
|
||||
if (mask != null) {
|
||||
if (!mask.isModified(i-1)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// look up the value of the field
|
||||
comp = fd.field.get(qbe);
|
||||
|
||||
// if no field mask was specified, ignore builtin
|
||||
// fields and those that are null
|
||||
if (mask == null && (fd.isBuiltin() || comp == null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nComponents != 0) {
|
||||
buildQueryList(buf, comp, i, i+nComponents, mask);
|
||||
} else {
|
||||
if (buf.length() != 0) {
|
||||
buf.append(",");
|
||||
}
|
||||
buf.append(fd.name);
|
||||
buf.append("=?");
|
||||
}
|
||||
|
||||
} finally {
|
||||
i += nComponents;
|
||||
}
|
||||
}
|
||||
} catch(IllegalAccessException ex) { throw new IllegalAccessError(); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user