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

Reply via email to