Author: sdumitriu
Date: 2008-02-08 02:02:01 +0100 (Fri, 08 Feb 2008)
New Revision: 7365
Modified:
xwiki-platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/objects/classes/DBListClass.java
xwiki-platform/core/trunk/xwiki-core/src/test/java/com/xpn/xwiki/objects/classes/DBListClassTest.java
Log:
XWIKI-2083: Improve the way DBList and DBTreeList generate queries
Done for DBList
Modified:
xwiki-platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/objects/classes/DBListClass.java
===================================================================
---
xwiki-platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/objects/classes/DBListClass.java
2008-02-08 00:51:07 UTC (rev 7364)
+++
xwiki-platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/objects/classes/DBListClass.java
2008-02-08 01:02:01 UTC (rev 7365)
@@ -45,6 +45,9 @@
public class DBListClass extends ListClass
{
+ private static final String DEFAULT_QUERY =
+ "select doc.name from XWikiDocument doc where 1 = 0";
+
private static final Log LOG = LogFactory.getLog(DBListClass.class);
private List cachedDBList;
@@ -104,7 +107,6 @@
if (query == null)
list = new ArrayList();
else {
-
try {
if ((xwiki.getHibernateStore() != null) &&
(!query.startsWith("/"))) {
list = makeList(xwiki.search(query, context));
@@ -152,59 +154,160 @@
return map;
}
+ /**
+ * <p>
+ * Computes the query corresponding to the current XProperty. The query is
either manually
+ * specified by the XClass creator in the <tt>sql</tt> field, or, if the
query field is blank,
+ * constructed using the <tt>classname</tt>, <tt>idField</tt> and
<tt>valueField</tt>
+ * properties. The query is constructed according to the following rules:
+ * </p>
+ * <ul>
+ * <li>If no classname, id or value fields are selected, return a query
that return no rows.</li>
+ * <li>If only the classname is provided, select all document names which
have an object of
+ * that type.</li>
+ * <li>If only one of id and value is provided, select just one
column.</li>
+ * <li>If id = value, select just one column.</li>
+ * <li>If no classname is provided, assume the fields are document
properties.</li>
+ * <li>If the document is not used at all, don't put it in the query.</li>
+ * <li>If the object is not used at all, don't put it in the query.</li>
+ * </ul>
+ * <p>
+ * If there are two columns selected, use the first one as the stored
value and the second one
+ * as the displayed value.
+ * </p>
+ *
+ * @param context The current [EMAIL PROTECTED] XWikiContext context}.
+ * @return The HQL query corresponding to this property.
+ */
public String getQuery(XWikiContext context)
{
+ // First, get the hql query entered by the user.
String sql = getSql();
try {
+ // TODO Why is it rendered? It is already parsed in the end, and I
don't think it should
+ // also be rendered by Radeox.
sql = context.getDoc().getRenderedContent(sql, context);
} catch (Exception e) {
LOG.warn("Failed to render SQL script [" + sql + "]. Internal
error ["
+ e.getMessage() + "]. Continuing with non-rendered script.");
}
+ // If the query field is blank, construct a query using the classname,
idField and
+ // valueField properties.
if (StringUtils.isBlank(sql)) {
- String classname = getClassname();
- String idField = getIdField();
- String valueField = getValueField();
- if ((valueField == null) || (valueField.trim().equals(""))) {
- valueField = idField;
- }
if (context.getWiki().getHibernateStore() != null) {
- StringBuffer select = new StringBuffer("select ");
- StringBuffer tables =
- new StringBuffer(" from XWikiDocument as doc, BaseObject
as obj");
- StringBuffer where =
- new StringBuffer(" where doc.fullName=obj.name and
obj.className='");
- where.append(classname).append("'");
+ // Extract the 3 properties in non-null variables.
+ String classname = StringUtils.defaultString(getClassname());
+ String idField = StringUtils.defaultString(getIdField());
+ String valueField = StringUtils.defaultString(getValueField());
+ // Check if the properties are specified or not.
+ boolean hasClassname = !StringUtils.isBlank(classname);
+ boolean hasIdField = !StringUtils.isBlank(idField);
+ boolean hasValueField = !StringUtils.isBlank(valueField);
+
+ if (!(hasIdField || hasValueField)) {
+ // If only the classname is specified, return a query that
selects all the
+ // document names which have an object of that type.
+ if (hasClassname) {
+ sql =
+ "select distinct doc.fullName from XWikiDocument
as doc, BaseObject as obj"
+ + " where doc.fullName=obj.name and
obj.className='" + classname
+ + "'";
+ } else {
+ // If none of the 3 properties is specified, return a
query that always
+ // returns no rows.
+ sql = DEFAULT_QUERY;
+ }
+ return sql;
+ }
+
+ // If the value field is specified, but the id isn't, swap
them.
+ if (!hasIdField && hasValueField) {
+ idField = valueField;
+ valueField = "";
+ hasValueField = false;
+ } else if (idField.equals(valueField)) {
+ // If the value field is the same as the id field, ignore
it.
+ hasValueField = false;
+ }
+
+ // Check if the document and object are needed or not.
+ // The object is needed if there is a classname, or if at
least one of the selected
+ // columns is an object property.
+ boolean usesObj =
+ !StringUtils.isBlank(classname) ||
idField.startsWith("obj.")
+ || valueField.startsWith("obj.");
+ // The document is needed if one of the selected columns is a
document property, or
+ // if there is no classname specified and at least one of the
selected columns is a
+ // document property.
+ boolean usesDoc = idField.startsWith("doc.") ||
valueField.startsWith("doc.");
+ if ((!idField.startsWith("obj.") || (hasValueField &&
!valueField
+ .startsWith("obj.")))
+ && !hasClassname) {
+ usesDoc = true;
+ }
+
+ // Build the query in this variable.
+ StringBuffer select = new StringBuffer("select distinct ");
+ // These will hold the components of the from and where parts
of the query.
+ ArrayList fromStatements = new ArrayList();
+ ArrayList whereStatements = new ArrayList();
+
+ // Add the document to the query only if it is needed.
+ if (usesDoc) {
+ fromStatements.add("XWikiDocument as doc");
+ if (usesObj) {
+ whereStatements.add("doc.fullName=obj.name");
+ }
+ }
+ // Add the object to the query only if it is needed.
+ if (usesObj) {
+ fromStatements.add("BaseObject as obj");
+ if (hasClassname) {
+ whereStatements.add("obj.className='" + classname +
"'");
+ }
+ }
+
+ // Add the first column to the query.
if (idField.startsWith("doc.") || idField.startsWith("obj.")) {
select.append(idField);
+ } else if (!hasClassname) {
+ select.append("doc." + idField);
} else {
select.append("idprop.value");
- tables.append(", StringProperty as idprop");
- where.append(" and obj.id=idprop.id.id and
idprop.id.name='").append(idField)
- .append("'");
+ fromStatements.add("StringProperty as idprop");
+ whereStatements.add("obj.id=idprop.id.id and
idprop.id.name='" + idField
+ + "'");
}
- if (valueField.startsWith("doc.") ||
valueField.startsWith("obj.")) {
- select.append(", ").append(valueField);
- } else {
- if (idField.equals(valueField)) {
- select.append(", idprop.value");
+ // If specified, add the second column to the query.
+ if (hasValueField) {
+ if (valueField.startsWith("doc.") ||
valueField.startsWith("obj.")) {
+ select.append(", ").append(valueField);
+ } else if (!hasClassname) {
+ select.append(", doc." + valueField);
} else {
select.append(", valueprop.value");
- tables.append(", StringProperty as valueprop");
- where.append(" and obj.id=valueprop.id.id and
valueprop.id.name='")
- .append(valueField).append("'");
+ fromStatements.add("StringProperty as valueprop");
+ whereStatements.add("obj.id=valueprop.id.id and
valueprop.id.name='"
+ + valueField + "'");
}
}
- // Let's create the sql
- sql = select.append(tables).append(where).toString();
+ // Let's create the complete query
+ select.append(" from ");
+ select.append(StringUtils.join(fromStatements.iterator(), ",
"));
+ if (whereStatements.size() > 0) {
+ select.append(" where ");
+ select.append(StringUtils.join(whereStatements.iterator(),
" and "));
+ }
+ sql = select.toString();
} else {
// TODO: query plugin impl.
// We need to generate the right query for the query plugin
}
-
}
+ // Parse the query, so that it can contain velocity scripts, for
example to use the
+ // current document name, or the current username.
return context.getWiki().parseContent(sql, context);
}
Modified:
xwiki-platform/core/trunk/xwiki-core/src/test/java/com/xpn/xwiki/objects/classes/DBListClassTest.java
===================================================================
---
xwiki-platform/core/trunk/xwiki-core/src/test/java/com/xpn/xwiki/objects/classes/DBListClassTest.java
2008-02-08 00:51:07 UTC (rev 7364)
+++
xwiki-platform/core/trunk/xwiki-core/src/test/java/com/xpn/xwiki/objects/classes/DBListClassTest.java
2008-02-08 01:02:01 UTC (rev 7365)
@@ -29,11 +29,14 @@
/**
* Unit tests for [EMAIL PROTECTED] DBListClass}.
- *
+ *
* @version $Id: $
*/
public class DBListClassTest extends TestCase
{
+ private static final String DEFAULT_QUERY =
+ "select doc.name from XWikiDocument doc where 1 = 0";
+
private XWikiContext context;
protected void setUp() throws Exception
@@ -41,15 +44,185 @@
this.context = new XWikiContext();
this.context.setDoc(new XWikiDocument());
XWikiHibernateStore store = new XWikiHibernateStore("dummy");
- XWiki xwiki = new XWiki(new XWikiConfig(), context);
+ XWiki xwiki = new XWiki(new XWikiConfig(), context);
xwiki.setStore(store);
}
- public void testGetQueryWhenNoSQLSCriptSpecified()
+ public void testGetDefaultQueryWhenNoSqlSCriptSpecified()
{
DBListClass dblc = new DBListClass();
- assertEquals("select idprop.value, idprop.value from XWikiDocument as
doc, BaseObject as obj, "
- + "StringProperty as idprop where doc.fullName=obj.name and
obj.className='' and obj.id=idprop.id.id "
- + "and idprop.id.name=''", dblc.getQuery(this.context));
+ assertEquals("", dblc.getSql());
+ assertEquals(DEFAULT_QUERY, dblc.getQuery(context));
}
+
+ public void testGetQueryWithSqlScriptSpecified()
+ {
+ DBListClass dblc = new DBListClass();
+ assertEquals("", dblc.getSql());
+ String sql = "select doc.creator from XWikiDocument as doc";
+ dblc.setSql(sql);
+ assertEquals(sql, dblc.getQuery(context));
+ }
+
+ public void testGetQueryWithClassSpecified()
+ {
+ DBListClass dblc = new DBListClass();
+ dblc.setClassname("XWiki.XWikiUsers");
+ assertEquals(
+ "select distinct doc.fullName from XWikiDocument as doc,
BaseObject as obj where "
+ + "doc.fullName=obj.name and
obj.className='XWiki.XWikiUsers'", dblc
+ .getQuery(context));
+ }
+
+ public void testGetQueryWithIdSpecified()
+ {
+ DBListClass dblc = new DBListClass();
+ dblc.setIdField("doc.name");
+ assertEquals("select distinct doc.name from XWikiDocument as doc",
dblc.getQuery(context));
+ dblc.setIdField("obj.className");
+ assertEquals("select distinct obj.className from BaseObject as obj",
dblc
+ .getQuery(context));
+ dblc.setIdField("property");
+ assertEquals("select distinct doc.property from XWikiDocument as doc",
dblc
+ .getQuery(context));
+ }
+
+ public void testGetQueryWithValueSpecified()
+ {
+ DBListClass dblc = new DBListClass();
+ dblc.setValueField("doc.name");
+ assertEquals("select distinct doc.name from XWikiDocument as doc",
dblc.getQuery(context));
+ dblc.setValueField("obj.className");
+ assertEquals("select distinct obj.className from BaseObject as obj",
dblc
+ .getQuery(context));
+ dblc.setValueField("property");
+ assertEquals("select distinct doc.property from XWikiDocument as doc",
dblc
+ .getQuery(context));
+ }
+
+ public void testGetQueryWithIdAndClassnameSpecified()
+ {
+ DBListClass dblc = new DBListClass();
+ dblc.setClassname("XWiki.XWikiUsers");
+ dblc.setIdField("doc.name");
+ assertEquals(
+ "select distinct doc.name from XWikiDocument as doc, BaseObject as
obj where doc.fullName=obj.name and obj.className='XWiki.XWikiUsers'",
+ dblc.getQuery(context));
+ dblc.setIdField("obj.className");
+ assertEquals(
+ "select distinct obj.className from BaseObject as obj where
obj.className='XWiki.XWikiUsers'",
+ dblc.getQuery(context));
+ dblc.setIdField("property");
+ assertEquals(
+ "select distinct idprop.value from BaseObject as obj,
StringProperty as idprop where obj.className='XWiki.XWikiUsers' and
obj.id=idprop.id.id and idprop.id.name='property'",
+ dblc.getQuery(context));
+ }
+
+ public void testGetQueryWithIdAndValueSpecified()
+ {
+ DBListClass dblc = new DBListClass();
+ dblc.setIdField("doc.name");
+ dblc.setValueField("doc.name");
+ assertEquals("select distinct doc.name from XWikiDocument as doc",
dblc.getQuery(context));
+ dblc.setValueField("doc.creator");
+ assertEquals("select distinct doc.name, doc.creator from XWikiDocument
as doc", dblc
+ .getQuery(context));
+ dblc.setValueField("obj.className");
+ assertEquals(
+ "select distinct doc.name, obj.className from XWikiDocument as
doc, BaseObject as obj where doc.fullName=obj.name",
+ dblc.getQuery(context));
+ dblc.setValueField("property");
+ assertEquals("select distinct doc.name, doc.property from
XWikiDocument as doc", dblc
+ .getQuery(context));
+
+ dblc.setIdField("obj.className");
+ dblc.setValueField("doc.name");
+ assertEquals(
+ "select distinct obj.className, doc.name from XWikiDocument as
doc, BaseObject as obj where doc.fullName=obj.name",
+ dblc.getQuery(context));
+ dblc.setValueField("obj.className");
+ assertEquals("select distinct obj.className from BaseObject as obj",
dblc
+ .getQuery(context));
+ dblc.setValueField("obj.id");
+ assertEquals("select distinct obj.className, obj.id from BaseObject as
obj", dblc
+ .getQuery(context));
+ dblc.setValueField("property");
+ assertEquals(
+ "select distinct obj.className, doc.property from XWikiDocument as
doc, BaseObject as obj where doc.fullName=obj.name",
+ dblc.getQuery(context));
+
+ dblc.setIdField("property");
+ dblc.setValueField("doc.name");
+ assertEquals("select distinct doc.property, doc.name from
XWikiDocument as doc", dblc
+ .getQuery(context));
+ dblc.setValueField("obj.className");
+ assertEquals(
+ "select distinct doc.property, obj.className from XWikiDocument as
doc, BaseObject as obj where doc.fullName=obj.name",
+ dblc.getQuery(context));
+ dblc.setValueField("property");
+ assertEquals("select distinct doc.property from XWikiDocument as doc",
dblc
+ .getQuery(context));
+ dblc.setValueField("otherProperty");
+ assertEquals("select distinct doc.property, doc.otherProperty from
XWikiDocument as doc",
+ dblc.getQuery(context));
+ }
+
+ public void testGetQueryWithIdValueAndClassSpecified()
+ {
+ DBListClass dblc = new DBListClass();
+ dblc.setClassname("XWiki.XWikiUsers");
+ dblc.setIdField("doc.name");
+ dblc.setValueField("doc.name");
+ assertEquals(
+ "select distinct doc.name from XWikiDocument as doc, BaseObject as
obj where doc.fullName=obj.name and obj.className='XWiki.XWikiUsers'",
+ dblc.getQuery(context));
+ dblc.setValueField("doc.creator");
+ assertEquals(
+ "select distinct doc.name, doc.creator from XWikiDocument as doc,
BaseObject as obj where doc.fullName=obj.name and
obj.className='XWiki.XWikiUsers'",
+ dblc.getQuery(context));
+ dblc.setValueField("obj.className");
+ assertEquals(
+ "select distinct doc.name, obj.className from XWikiDocument as
doc, BaseObject as obj where doc.fullName=obj.name and
obj.className='XWiki.XWikiUsers'",
+ dblc.getQuery(context));
+ dblc.setValueField("property");
+ assertEquals(
+ "select distinct doc.name, valueprop.value from XWikiDocument as
doc, BaseObject as obj, StringProperty as valueprop where doc.fullName=obj.name
and obj.className='XWiki.XWikiUsers' and obj.id=valueprop.id.id and
valueprop.id.name='property'",
+ dblc.getQuery(context));
+
+ dblc.setIdField("obj.className");
+ dblc.setValueField("doc.name");
+ assertEquals(
+ "select distinct obj.className, doc.name from XWikiDocument as
doc, BaseObject as obj where doc.fullName=obj.name and
obj.className='XWiki.XWikiUsers'",
+ dblc.getQuery(context));
+ dblc.setValueField("obj.className");
+ assertEquals(
+ "select distinct obj.className from BaseObject as obj where
obj.className='XWiki.XWikiUsers'",
+ dblc.getQuery(context));
+ dblc.setValueField("obj.id");
+ assertEquals(
+ "select distinct obj.className, obj.id from BaseObject as obj
where obj.className='XWiki.XWikiUsers'",
+ dblc.getQuery(context));
+ dblc.setValueField("property");
+ assertEquals(
+ "select distinct obj.className, valueprop.value from BaseObject as
obj, StringProperty as valueprop where obj.className='XWiki.XWikiUsers' and
obj.id=valueprop.id.id and valueprop.id.name='property'",
+ dblc.getQuery(context));
+
+ dblc.setIdField("property");
+ dblc.setValueField("doc.name");
+ assertEquals(
+ "select distinct idprop.value, doc.name from XWikiDocument as doc,
BaseObject as obj, StringProperty as idprop where doc.fullName=obj.name and
obj.className='XWiki.XWikiUsers' and obj.id=idprop.id.id and
idprop.id.name='property'",
+ dblc.getQuery(context));
+ dblc.setValueField("obj.className");
+ assertEquals(
+ "select distinct idprop.value, obj.className from BaseObject as
obj, StringProperty as idprop where obj.className='XWiki.XWikiUsers' and
obj.id=idprop.id.id and idprop.id.name='property'",
+ dblc.getQuery(context));
+ dblc.setValueField("property");
+ assertEquals(
+ "select distinct idprop.value from BaseObject as obj,
StringProperty as idprop where obj.className='XWiki.XWikiUsers' and
obj.id=idprop.id.id and idprop.id.name='property'",
+ dblc.getQuery(context));
+ dblc.setValueField("otherProperty");
+ assertEquals(
+ "select distinct idprop.value, valueprop.value from BaseObject as
obj, StringProperty as idprop, StringProperty as valueprop where
obj.className='XWiki.XWikiUsers' and obj.id=idprop.id.id and
idprop.id.name='property' and obj.id=valueprop.id.id and
valueprop.id.name='otherProperty'",
+ dblc.getQuery(context));
+ }
}
_______________________________________________
notifications mailing list
[email protected]
http://lists.xwiki.org/mailman/listinfo/notifications