Source

trac-t10425 / default_columns.diff

Full commit
# HG changeset patch
# Parent 71b338ab9fae83825becb932956805ee8ba3a02d

diff --git a/trac/ticket/query.py b/trac/ticket/query.py
--- a/trac/ticket/query.py
+++ b/trac/ticket/query.py
@@ -26,7 +26,7 @@ from StringIO import StringIO
 
 from genshi.builder import tag
 
-from trac.config import Option, IntOption 
+from trac.config import Option, IntOption, ListOption
 from trac.core import *
 from trac.db import get_column_names
 from trac.mimeview.api import IContentConverter, Mimeview
@@ -236,35 +236,42 @@ class Query(object):
         return cols
 
     def get_default_columns(self):
-        cols = self.get_all_columns()
-        
-        # Semi-intelligently remove columns that are restricted to a single
-        # value by a query constraint.
-        for col in [k for k in self.constraint_cols.keys()
-                    if k != 'id' and k in cols]:
-            constraints = self.constraint_cols[col]
-            for constraint in constraints:
-                if not (len(constraint) == 1 and constraint[0]
-                        and not constraint[0][0] in '!~^$' and col in cols
-                        and col not in self.time_fields):
-                    break
-            else:
-                cols.remove(col)
-            if col == 'status' and 'resolution' in cols:
+        cols = QueryModule(self.env).default_columns
+
+        # Nothing in config, try to automatically calculate what to show
+        if not cols:
+            cols = self.get_all_columns()
+
+            # Semi-intelligently remove columns that are restricted to a single
+            # value by a query constraint.
+            for col in [k for k in self.constraint_cols.keys()
+                        if k != 'id' and k in cols]:
+                constraints = self.constraint_cols[col]
                 for constraint in constraints:
-                    if 'closed' in constraint:
+                    if not (len(constraint) == 1 and constraint[0]
+                            and not constraint[0][0] in '!~^$' and col in cols
+                            and col not in self.time_fields):
                         break
                 else:
-                    cols.remove('resolution')
-        if self.group in cols:
+                    cols.remove(col)
+                if col == 'status' and 'resolution' in cols:
+                    for constraint in constraints:
+                        if 'closed' in constraint:
+                            break
+                    else:
+                        cols.remove('resolution')
+
+            # Only display the first seven columns by default
+            cols = cols[:7]
+
+        # Make sure the column we order by is visible.
+        if self.order and self.order not in cols:
+            cols.append(self.order)
+
+        # Make sure to not show the column we group on.
+        if self.group and self.group in cols:
             cols.remove(self.group)
 
-        # Only display the first seven columns by default
-        cols = cols[:7]
-        # Make sure the column we order by is visible, if it isn't also
-        # the column we group by
-        if not self.order in cols and not self.order == self.group:
-            cols[-1] = self.order
         return cols
 
     def count(self, req=None, db=None, cached_ids=None, authname=None,
@@ -838,6 +845,11 @@ class QueryModule(Component):
         """Number of tickets displayed per page in ticket queries,
         by default (''since 0.11'')""")
 
+    default_columns = ListOption('query', 'default_columns',
+        default=None,
+        doc="""List of columns to show in query unless defined by the query.
+            Default is to let Trac calculate this internally. (''since 0.13'')""")
+
     # IContentConverter methods
 
     def get_supported_conversions(self):
diff --git a/trac/ticket/tests/query.py b/trac/ticket/tests/query.py
--- a/trac/ticket/tests/query.py
+++ b/trac/ticket/tests/query.py
@@ -116,7 +116,7 @@ ORDER BY COALESCE(priority.value,'')='' 
         query = Query(self.env, order='version')
         sql, args = query.get_sql()
         self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.version AS version,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.version AS version,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
 FROM ticket AS t
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
   LEFT OUTER JOIN version ON (version.name=version)
@@ -128,7 +128,7 @@ ORDER BY COALESCE(t.version,'')='',COALE
         query = Query(self.env, order='version', desc=1)
         sql, args = query.get_sql()
         self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.version AS version,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.version AS version,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
 FROM ticket AS t
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
   LEFT OUTER JOIN version ON (version.name=version)
@@ -152,7 +152,7 @@ ORDER BY COALESCE(t.id,0)=0,t.id""")
         query = Query(self.env, order='id', group='milestone')
         sql, args = query.get_sql()
         self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.component AS component,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
 FROM ticket AS t
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
   LEFT OUTER JOIN milestone ON (milestone.name=milestone)
@@ -164,7 +164,7 @@ ORDER BY COALESCE(t.milestone,'')='',COA
         query = Query(self.env, order='id', group='milestone', groupdesc=1)
         sql, args = query.get_sql()
         self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.component AS component,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
 FROM ticket AS t
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
   LEFT OUTER JOIN milestone ON (milestone.name=milestone)
@@ -176,7 +176,7 @@ ORDER BY COALESCE(t.milestone,'')='' DES
         query = Query(self.env, group='priority')
         sql, args = query.get_sql()
         self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.milestone AS milestone,t.component AS component,t.priority AS priority,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.milestone AS milestone,t.priority AS priority,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
 FROM ticket AS t
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
 ORDER BY COALESCE(priority.value,'')='',%(cast_priority)s,t.id""" % {
@@ -498,6 +498,52 @@ ORDER BY COALESCE(t.id,0)=0,t.id""")
         self.assertEqual(['anonymous'], args)
         tickets = query.execute(self.req)
 
+    def test_default_cols_with_config_no_request(self):
+        self.env.config.set('query', 'default_columns', 'id,time,changetime,summary,milestone,type')
+        query = Query(self.env)
+        sql, args = query.get_sql()
+        self.assertEqualSQL(sql,
+"""SELECT t.id AS id,t.time AS time,t.changetime AS changetime,t.summary AS summary,t.milestone AS milestone,t.type AS type,t.priority AS priority,t.status AS status,priority.value AS priority_value
+FROM ticket AS t
+  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
+ORDER BY COALESCE(priority.value,'')='',CAST(priority.value AS integer),t.id""")
+        self.assertEqual([], args)
+        tickets = query.execute(self.req)
+
+    def test_default_cols_with_config_with_request(self):
+        self.env.config.set('query', 'default_columns', 'id,time,changetime,summary,milestone,type')
+        query = Query(self.env, cols=['id','time','changetime'])
+        sql, args = query.get_sql()
+        self.assertEqualSQL(sql,
+"""SELECT t.id AS id,t.time AS time,t.changetime AS changetime,t.status AS status,t.priority AS priority,priority.value AS priority_value
+FROM ticket AS t
+  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
+ORDER BY COALESCE(priority.value,'')='',CAST(priority.value AS integer),t.id""")
+        self.assertEqual([], args)
+        tickets = query.execute(self.req)
+
+    def test_default_cols_no_config_no_request(self):
+        query = Query(self.env)
+        sql, args = query.get_sql()
+        self.assertEqualSQL(sql,
+"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
+FROM ticket AS t
+  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
+ORDER BY COALESCE(priority.value,'')='',CAST(priority.value AS integer),t.id""")
+        self.assertEqual([], args)
+        tickets = query.execute(self.req)
+
+    def test_default_cols_no_config_with_request(self):
+        query = Query(self.env, cols=['id','time','changetime'])
+        sql, args = query.get_sql()
+        self.assertEqualSQL(sql,
+"""SELECT t.id AS id,t.time AS time,t.changetime AS changetime,t.status AS status,t.priority AS priority,priority.value AS priority_value
+FROM ticket AS t
+  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
+ORDER BY COALESCE(priority.value,'')='',CAST(priority.value AS integer),t.id""")
+        self.assertEqual([], args)
+        tickets = query.execute(self.req)
+
     def test_csv_escape(self):
         query = Mock(get_columns=lambda: ['col1'],
                      execute=lambda r: [{'id': 1,