From e45ef47deeb3301e7259199b2254eda5cc747764 Mon Sep 17 00:00:00 2001 From: hns Date: Thu, 23 Oct 2003 14:33:59 +0000 Subject: [PATCH] Commit parsed filter feature contributed by Juerg Lehni. --- src/helma/objectmodel/db/Relation.java | 170 +++++++++++++++++++++++-- 1 file changed, 162 insertions(+), 8 deletions(-) diff --git a/src/helma/objectmodel/db/Relation.java b/src/helma/objectmodel/db/Relation.java index ab48eb38..220de6a8 100644 --- a/src/helma/objectmodel/db/Relation.java +++ b/src/helma/objectmodel/db/Relation.java @@ -18,11 +18,13 @@ package helma.objectmodel.db; import helma.framework.core.Application; import helma.objectmodel.INode; +import helma.objectmodel.IProperty; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; import java.util.Properties; +import java.util.Enumeration; import java.util.Vector; /** @@ -91,6 +93,8 @@ public final class Relation { String groupbyPrototype; String filter; String additionalTables; + Vector filterFragments; + Vector filterPropertyRefs; int maxSize = 0; /** @@ -107,6 +111,8 @@ public final class Relation { this.reftype = rel.reftype; this.order = rel.order; this.filter = rel.filter; + this.filterFragments = rel.filterFragments; + this.filterPropertyRefs = rel.filterPropertyRefs; this.additionalTables = rel.additionalTables; this.maxSize = rel.maxSize; this.constraints = rel.constraints; @@ -262,17 +268,27 @@ public final class Relation { if (filter != null) { if (filter.trim().length() == 0) { filter = null; + filterFragments = filterPropertyRefs = null; } else { // parenthesise filter - filter = "("+filter+")"; + Vector fragments = new Vector(); + Vector propertyRefs = new Vector(); + parsePropertyString(filter, fragments, propertyRefs); + // if no references where found, just use the filter string + // otherwise use the filter fragments and proeprty refs instead + if (propertyRefs.size() > 0) { + filterFragments = fragments; + filterPropertyRefs = propertyRefs; + } else { + filterFragments = filterPropertyRefs = null; + } } } // get additional tables additionalTables = props.getProperty(propName + ".filter.additionalTables"); - if (additionalTables != null) { - if (additionalTables.trim().length() == 0) + if (additionalTables != null && additionalTables.trim().length() == 0) { additionalTables = null; } @@ -560,6 +576,77 @@ public final class Relation { return columnName; } + /** + * This is taken from org.apache.tools.ant ProjectHelper.java + * distributed under the Apache Software License, Version 1.1 + * + * Parses a string containing ${xxx} style property + * references into two lists. The first list is a collection + * of text fragments, while the other is a set of string property names. + * null entries in the first list indicate a property + * reference from the second list. + * + * @param value Text to parse. Must not be null. + * @param fragments List to add text fragments to. + * Must not be null. + * @param propertyRefs List to add property names to. + * Must not be null. + */ + protected void parsePropertyString(String value, Vector fragments, Vector propertyRefs) { + int prev = 0; + int pos; + //search for the next instance of $ from the 'prev' position + while ((pos = value.indexOf("$", prev)) >= 0) { + + //if there was any text before this, add it as a fragment + //TODO, this check could be modified to go if pos>prev; + //seems like this current version could stick empty strings + //into the list + if (pos > 0) { + fragments.addElement(value.substring(prev, pos)); + } + //if we are at the end of the string, we tack on a $ + //then move past it + if (pos == (value.length() - 1)) { + fragments.addElement("$"); + prev = pos + 1; + } else if (value.charAt(pos + 1) != '{') { + //peek ahead to see if the next char is a property or not + //not a property: insert the char as a literal + /* + fragments.addElement(value.substring(pos + 1, pos + 2)); + prev = pos + 2; + */ + if (value.charAt(pos + 1) == '$') { + //backwards compatibility two $ map to one mode + fragments.addElement("$"); + prev = pos + 2; + } else { + //new behaviour: $X maps to $X for all values of X!='$' + fragments.addElement(value.substring(pos, pos + 2)); + prev = pos + 2; + } + + } else { + //property found, extract its name or bail on a typo + int endName = value.indexOf('}', pos); + if (endName < 0) { + throw new RuntimeException("Syntax error in property: " + + value); + } + String propertyName = value.substring(pos + 2, endName); + fragments.addElement(null); + propertyRefs.addElement(propertyName); + prev = endName + 1; + } + } + //no more $ signs found + //if there is any tail to the file, append it + if (prev < value.length()) { + fragments.addElement(value.substring(prev)); + } + } + /** * get a DbMapping to use for virtual aka collection nodes. */ @@ -701,8 +788,7 @@ public final class Relation { } if (filter != null) { - q.append(prefix); - q.append(filter); + appendFilter(q, nonvirtual, prefix); } if (groupby != null) { @@ -718,6 +804,75 @@ public final class Relation { return q.toString(); } + /** + * Build the filter. + */ + protected void appendFilter(StringBuffer q, INode nonvirtual, String prefix) throws SQLException { + q.append(prefix); + q.append('('); + if (filterFragments == null) { + q.append(filter); + } else { + Enumeration i = filterFragments.elements(); + Enumeration j = filterPropertyRefs.elements(); + while (i.hasMoreElements()) { + String fragment = (String) i.nextElement(); + if (fragment == null) { + /* + // begin property version + String propertyName = (String) j.nextElement(); + Object value = null; + if (propertyName != null) { + if (propertyName.equals("__id__") || propertyName.equals("_id")) { + value = nonvirtual.getID(); + } else if (propertyName.equals("__name__")) { + value = nonvirtual.getName(); + } else if (propertyName.equals("__prototype__") || propertyName.equals("_prototype")) { + value = nonvirtual.getPrototype(); + } else { + IProperty property = nonvirtual.get(propertyName); + if (property != null) { + value = property.getValue(); + } + } + } + // end property version + */ + // begin column version + String columnName = (String) j.nextElement(); + Object value = null; + if (columnName != null) { + DbMapping dbmap = nonvirtual.getDbMapping(); + if (columnName.equals(dbmap.getIDField())) { + value = nonvirtual.getID(); + } else if (columnName.equals(dbmap.getNameField())) { + value = nonvirtual.getName(); + } else if (columnName.equals(dbmap.getPrototypeField())) { + value = nonvirtual.getPrototype(); + } else { + String propertyName = dbmap.columnNameToProperty(columnName); + if (propertyName != null) { + IProperty property = nonvirtual.get(propertyName); + if (property != null) { + value = property.getValue(); + } + } + } + } + // end column version + if (value != null) { + q.append(escape(value.toString())); + } else { + q.append("NULL"); + } + } else { + q.append(fragment); + } + } + } + q.append(')'); + } + /** * * @@ -739,10 +894,9 @@ public final class Relation { } if (filter != null) { - q.append(prefix); - q.append(filter); + appendFilter(q, nonvirtual, prefix); } - + return q.toString(); }