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:
mdb
2002-03-28 07:25:31 +00:00
parent fe33ed950e
commit 84061c0ca7
2 changed files with 127 additions and 52 deletions
@@ -62,7 +62,8 @@ public class Cursor {
} }
} }
synchronized(qbeStmt) { synchronized(qbeStmt) {
table.bindQueryVariables(qbeStmt, qbeObject); table.bindQueryVariables(
qbeStmt, qbeObject, qbeMask);
result = qbeStmt.executeQuery(); result = qbeStmt.executeQuery();
qbeStmt.clearParameters(); qbeStmt.clearParameters();
} }
@@ -219,15 +220,17 @@ public class Cursor {
this.query = query; 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) { if (session == null) {
session = ((SessionThread)Thread.currentThread()).session; session = ((SessionThread)Thread.currentThread()).session;
} }
this.table = table; this.table = table;
this.session = session; this.session = session;
this.nTables = nTables; this.nTables = nTables;
qbeObject = obj; qbeObject = obj;
query = table.buildQueryList(obj); qbeMask = mask;
query = table.buildQueryList(obj, mask);
stmt = null; stmt = null;
} }
@@ -239,5 +242,6 @@ public class Cursor {
private Statement stmt; private Statement stmt;
private Object currObject; private Object currObject;
private Object qbeObject; private Object qbeObject;
private FieldMask qbeMask;
} }
@@ -172,38 +172,61 @@ public class Table {
} }
/** Select records from database table using <I>obj</I> object as /** Select records from database table using <I>obj</I> object as
* template for selection. All non-builtin fields of this object, * template.
* which are not null, are compared with correspondent table values.
* *
* @param obj object for construction search condition: selected objects * @param obj example object for search: selected objects should match
* should match all non-null fields of specified object. * all non-null fields.
*/ */
public final Cursor queryByExample(Object obj) { 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 /** Select records from database table using <I>obj</I> object as
* template for selection. All non-builtin fields of this object, * template for selection. All non-builtin fields of this object,
* which are not null, are compared with correspondent table values. * which are not null, are compared with correspondent table values.
* *
* @param obj object for construction search condition: selected objects * @param obj object for construction search condition: selected
* should match all non-null fields of specified object. * objects should match all non-null fields of specified object.
* @param session user database session * @param session user database session.
*/ */
public final Cursor queryByExample(Object obj, Session 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 /** Select records from specified and derived database tables using
* <I>obj</I> object as template for selection. * <I>obj</I> object as template for selection. All non-builtin
* All non-builtin fields of this object, * fields of this object, which are not null, are compared with
* which are not null, are compared with correspondent table values. * correspondent table values.
* *
* @param obj object for construction search condition: selected objects * @param obj object for construction search condition: selected
* should match all non-null fields of specified object. * objects should match all non-null fields of specified object.
*/ */
public final Cursor queryAllByExample(Object obj) { 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 /** Select records from specified and derived database tables using
@@ -216,7 +239,7 @@ public class Table {
* @param session user database session * @param session user database session
*/ */
public final Cursor queryAllByExample(Object obj, Session 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 /** Insert new record in the table. Values of inserted record fields
@@ -972,10 +995,11 @@ public class Table {
} }
protected final void bindQueryVariables(PreparedStatement pstmt, protected final void bindQueryVariables(PreparedStatement pstmt,
Object obj) Object obj,
FieldMask mask)
throws SQLException throws SQLException
{ {
bindQueryVariables(pstmt, obj, 0, nFields, 0); bindQueryVariables(pstmt, obj, 0, nFields, 0, mask);
} }
protected final void updateVariables(ResultSet result, Object obj) protected final void updateVariables(ResultSet result, Object obj)
@@ -995,10 +1019,10 @@ public class Table {
return sql.toString(); return sql.toString();
} }
protected final String buildQueryList(Object qbe) protected final String buildQueryList(Object qbe, FieldMask mask)
{ {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
buildQueryList(buf, qbe, 0, nFields); buildQueryList(buf, qbe, 0, nFields, mask);
if (buf.length() > 0) { if (buf.length() > 0) {
buf.insert(0, " where "); buf.insert(0, " where ");
} }
@@ -1047,8 +1071,9 @@ public class Table {
} }
private final int bindQueryVariables(PreparedStatement pstmt, Object obj, private final int bindQueryVariables(PreparedStatement pstmt, Object obj,
int i, int end, int column) int i, int end, int column,
throws SQLException FieldMask mask)
throws SQLException
{ {
try { try {
while (i < end) { while (i < end) {
@@ -1057,25 +1082,48 @@ public class Table {
if (!fd.field.getDeclaringClass().isInstance(obj)) { if (!fd.field.getDeclaringClass().isInstance(obj)) {
return column; return column;
} }
int nComponents = int nComponents = fd.isCompound() ?
fd.isCompound() ? fd.outType-FieldDescriptor.tCompound : 0; fd.outType-FieldDescriptor.tCompound : 0;
if (!fd.isBuiltin()
&& fd.outType != FieldDescriptor.tClosure try {
&& (comp = fd.field.get(obj)) != null) // 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)) { if (!fd.bindVariable(pstmt, obj, ++column)) {
column = bindQueryVariables(pstmt, comp, column = bindQueryVariables(
i,i+nComponents,column-1); pstmt, comp, i, i+nComponents, column-1, mask);
} }
}
i += nComponents; } finally {
i += nComponents;
}
} }
} catch(IllegalAccessException ex) { throw new IllegalAccessError(); } } catch(IllegalAccessException ex) { throw new IllegalAccessError(); }
return column; return column;
} }
private final void buildQueryList(StringBuffer buf, Object qbe, private final void buildQueryList(StringBuffer buf, Object qbe,
int i, int end) int i, int end, FieldMask mask)
{ {
try { try {
while (i < end) { while (i < end) {
@@ -1083,21 +1131,44 @@ public class Table {
FieldDescriptor fd = fields[i++]; FieldDescriptor fd = fields[i++];
int nComponents = int nComponents =
fd.isCompound() ? fd.outType-FieldDescriptor.tCompound : 0; fd.isCompound() ? fd.outType-FieldDescriptor.tCompound : 0;
if (!fd.isBuiltin()
&& fd.outType != FieldDescriptor.tClosure try {
&& (comp = fd.field.get(qbe)) != null) // skip closure fields (because querying by them makes
{ // no sense)
if (nComponents != 0) { if (fd.outType == FieldDescriptor.tClosure) {
buildQueryList(buf, comp, i, i+nComponents); continue;
} else { }
if (buf.length() != 0) {
buf.append(","); // if a field mask is specified, use that to determine
} // whether or not the field should be skipped
buf.append(fd.name); if (mask != null) {
buf.append("=?"); if (!mask.isModified(i-1)) {
} continue;
} }
i += nComponents; }
// 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(); } } catch(IllegalAccessException ex) { throw new IllegalAccessError(); }
} }