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) {
|
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(); }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user