Author: matevz Date: Thu Aug 8 13:19:01 2013 New Revision: 1511771 URL: http://svn.apache.org/r1511771 Log: #596 - pagination on /dashboard confused
Added: bloodhound/trunk/bloodhound_multiproduct/multiproduct/ticket/batch.py Modified: bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/query.py bloodhound/trunk/bloodhound_multiproduct/multiproduct/env.py bloodhound/trunk/bloodhound_multiproduct/multiproduct/hooks.py bloodhound/trunk/bloodhound_multiproduct/multiproduct/ticket/query.py bloodhound/trunk/bloodhound_multiproduct/setup.py bloodhound/trunk/bloodhound_multiproduct/tests/product-query-link-tests.txt bloodhound/trunk/bloodhound_multiproduct/tests/wikisyntax.py bloodhound/trunk/bloodhound_theme/bhtheme/theme.py bloodhound/trunk/trac/trac/ticket/tests/query.py Modified: bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/query.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/query.py?rev=1511771&r1=1511770&r2=1511771&view=diff ============================================================================== --- bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/query.py (original) +++ bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/query.py Thu Aug 8 13:19:01 2013 @@ -42,7 +42,6 @@ from bhdashboard.util import WidgetBase, trac_tags from multiproduct.env import ProductEnvironment -from multiproduct.ticket.query import ProductQueryModule class TicketQueryWidget(WidgetBase): """Display tickets matching a TracQuery using a grid @@ -94,12 +93,11 @@ class TicketQueryWidget(WidgetBase): more_link_href = req.href('query', args) args.update({'page' : page, 'max': maxrows}) - qrymdl = self.env[QueryModule - if isinstance(self.env, ProductEnvironment) - else ProductQueryModule] + qrymdl = self.env[QueryModule] if qrymdl is None : raise TracError('Query module not available (disabled?)') - data = qrymdl.process_request(fakereq)[1] + + data = qrymdl.process_request(fakereq, self.env)[1] except TracError, exc: if data is not None: exc.title = data.get('title', 'TracQuery') Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/env.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/multiproduct/env.py?rev=1511771&r1=1511770&r2=1511771&view=diff ============================================================================== --- bloodhound/trunk/bloodhound_multiproduct/multiproduct/env.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/multiproduct/env.py Thu Aug 8 13:19:01 2013 @@ -892,6 +892,10 @@ class ProductEnvironment(Component, Comp # Multi-product API extensions @classmethod + def lookup_global_env(cls, env): + return env.parent if isinstance(env, ProductEnvironment) else env + + @classmethod def lookup_env(cls, env, prefix=None, name=None): """Instantiate environment according to product prefix or name Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/hooks.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/multiproduct/hooks.py?rev=1511771&r1=1511770&r2=1511771&view=diff ============================================================================== --- bloodhound/trunk/bloodhound_multiproduct/multiproduct/hooks.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/multiproduct/hooks.py Thu Aug 8 13:19:01 2013 @@ -20,6 +20,8 @@ import multiproduct.env import multiproduct.dbcursor import multiproduct.versioncontrol +import multiproduct.ticket.query +import multiproduct.ticket.batch import re @@ -31,7 +33,7 @@ from trac.web.main import RequestWithSes PRODUCT_RE = re.compile(r'^/products(?:/(?P<pid>[^/]*)(?P<pathinfo>.*))?') REDIRECT_DEFAULT_RE = \ - re.compile(r'^/(?P<section>milestone|roadmap|query|report|newticket|' + re.compile(r'^/(?P<section>milestone|roadmap|report|newticket|' r'ticket|qct|timeline|diff|batchmodify|search|' r'(raw-|zip-)?attachment/(ticket|milestone))(?P<pathinfo>.*)') Added: bloodhound/trunk/bloodhound_multiproduct/multiproduct/ticket/batch.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/multiproduct/ticket/batch.py?rev=1511771&view=auto ============================================================================== --- bloodhound/trunk/bloodhound_multiproduct/multiproduct/ticket/batch.py (added) +++ bloodhound/trunk/bloodhound_multiproduct/multiproduct/ticket/batch.py Thu Aug 8 13:19:01 2013 @@ -0,0 +1,40 @@ +from trac.ticket.batch import BatchModifyModule +from trac.util.translation import _ +from trac.web.chrome import add_script_data +from multiproduct.env import ProductEnvironment + + +class ProductBatchModifyModule(BatchModifyModule): + def add_template_data(self, req, data, tickets): + if isinstance(self.env, ProductEnvironment): + super(ProductBatchModifyModule, self).add_template_data( + req, data, tickets) + return + + data['batch_modify'] = True + data['query_href'] = req.session['query_href'] or req.href.query() + + tickets_by_product = {} + for t in tickets: + tickets_by_product.setdefault(t['product'], []).append(t) + + data['action_controls'] = [] + global_env = ProductEnvironment.lookup_global_env(self.env) + tmpenv = self.env + for k,v in tickets_by_product.iteritems(): + self.env = ProductEnvironment(global_env, k) + data['action_controls'] += self._get_action_controls(req, v) + self.env = tmpenv + batch_list_modes = [ + {'name': _("add"), 'value': "+"}, + {'name': _("remove"), 'value': "-"}, + {'name': _("add / remove"), 'value': "+-"}, + {'name': _("set to"), 'value': "="}, + ] + add_script_data(req, batch_list_modes=batch_list_modes, + batch_list_properties=self._get_list_fields()) + +import trac.ticket.batch +trac.ticket.batch.BatchModifyModule = ProductBatchModifyModule +trac.ticket.BatchModifyModule = ProductBatchModifyModule + Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/ticket/query.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/multiproduct/ticket/query.py?rev=1511771&r1=1511770&r2=1511771&view=diff ============================================================================== --- bloodhound/trunk/bloodhound_multiproduct/multiproduct/ticket/query.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/multiproduct/ticket/query.py Thu Aug 8 13:19:01 2013 @@ -20,6 +20,8 @@ from __future__ import with_statement +import re + from itertools import groupby from math import ceil from datetime import datetime, timedelta @@ -52,6 +54,9 @@ class ProductQuery(Query): """ def _count(self, sql, args): + if isinstance(self.env, ProductEnvironment): + return super(ProductQuery, self)._count(sql, args) + cnt = self.env.db_direct_query("SELECT COUNT(*) FROM (%s) AS x" % sql, args)[0][0] # "AS x" is needed for MySQL ("Subqueries in the FROM Clause") @@ -79,6 +84,10 @@ class ProductQuery(Query): :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ + if isinstance(self.env, ProductEnvironment): + return super(ProductQuery, self).execute(req, db, cached_ids, authname, + tzinfo, href, locale) + if req is not None: href = req.href with self.env.db_direct_query as db: @@ -142,184 +151,68 @@ class ProductQuery(Query): cursor.close() return results +import trac.ticket.query +trac.ticket.query.Query = ProductQuery +trac.ticket.Query = ProductQuery -class ProductQueryModule(QueryModule): - def process_request(self, req): - req.perm.assert_permission('TICKET_VIEW') - - constraints = self._get_constraints(req) - args = req.args - if not constraints and not 'order' in req.args: - # If no constraints are given in the URL, use the default ones. - if req.authname and req.authname != 'anonymous': - qstring = self.default_query - user = req.authname - else: - email = req.session.get('email') - name = req.session.get('name') - qstring = self.default_anonymous_query - user = email or name or None - - self.log.debug('QueryModule: Using default query: %s', str(qstring)) - if qstring.startswith('?'): - arg_list = parse_arg_list(qstring[1:]) - args = arg_list_to_args(arg_list) - constraints = self._get_constraints(arg_list=arg_list) - else: - query = ProductQuery.from_string(self.env, qstring) - args = {'order': query.order, 'group': query.group, - 'col': query.cols, 'max': query.max} - if query.desc: - args['desc'] = '1' - if query.groupdesc: - args['groupdesc'] = '1' - constraints = query.constraints - - # Substitute $USER, or ensure no field constraints that depend - # on $USER are used if we have no username. - for clause in constraints: - for field, vals in clause.items(): - for (i, val) in enumerate(vals): - if user: - vals[i] = val.replace('$USER', user) - elif val.endswith('$USER'): - del clause[field] - break - - cols = args.get('col') - if isinstance(cols, basestring): - cols = [cols] - # Since we don't show 'id' as an option to the user, - # we need to re-insert it here. - if cols and 'id' not in cols: - cols.insert(0, 'id') - rows = args.get('row', []) - if isinstance(rows, basestring): - rows = [rows] - format = req.args.get('format') - max = args.get('max') - if max is None and format in ('csv', 'tab'): - max = 0 # unlimited unless specified explicitly - query = ProductQuery(self.env, req.args.get('report'), - constraints, cols, args.get('order'), - 'desc' in args, args.get('group'), - 'groupdesc' in args, 'verbose' in args, - rows, - args.get('page'), - max) - - if 'update' in req.args: - # Reset session vars - for var in ('query_constraints', 'query_time', 'query_tickets'): - if var in req.session: - del req.session[var] - req.redirect(query.get_href(req.href)) - - # Add registered converters - for conversion in Mimeview(self.env).get_supported_conversions( - 'trac.ticket.Query'): - add_link(req, 'alternate', - query.get_href(req.href, format=conversion[0]), - conversion[1], conversion[4], conversion[0]) - - if format: - filename = 'query' if format != 'rss' else None - Mimeview(self.env).send_converted(req, 'trac.ticket.Query', query, - format, filename=filename) - - return self.display_html(req, query) - - def display_html(self, req, query): - # The most recent query is stored in the user session; - orig_list = None - orig_time = datetime.now(utc) - query_time = int(req.session.get('query_time', 0)) - query_time = datetime.fromtimestamp(query_time, utc) - query_constraints = unicode(query.constraints) - try: - if query_constraints != req.session.get('query_constraints') \ - or query_time < orig_time - timedelta(hours=1): - tickets = query.execute(req) - # New or outdated query, (re-)initialize session vars - req.session['query_constraints'] = query_constraints - req.session['query_tickets'] = ' '.join([str(t['id']) - for t in tickets]) - else: - orig_list = [int(id) for id - in req.session.get('query_tickets', '').split()] - tickets = query.execute(req, cached_ids=orig_list) - orig_time = query_time - except QueryValueError, e: - tickets = [] - for error in e.errors: - add_warning(req, error) - - context = web_context(req, 'query') - owner_field = [f for f in query.fields if f['name'] == 'owner'] - if owner_field: - TicketSystem(self.env).eventually_restrict_owner(owner_field[0]) - data = query.template_data(context, tickets, orig_list, orig_time, req) - - req.session['query_href'] = query.get_href(context.href) - req.session['query_time'] = to_timestamp(orig_time) - req.session['query_tickets'] = ' '.join([str(t['id']) - for t in tickets]) - title = _('Custom Query') - - # Only interact with the report module if it is actually enabled. - # - # Note that with saved custom queries, there will be some convergence - # between the report module and the query module. - from trac.ticket.report import ReportModule - if 'REPORT_VIEW' in req.perm and \ - self.env.is_component_enabled(ReportModule): - data['report_href'] = req.href.report() - add_ctxtnav(req, _('Available Reports'), req.href.report()) - add_ctxtnav(req, _('Custom Query'), req.href.query()) - if query.id: - for title, description in self.env.db_query(""" - SELECT title, description FROM report WHERE id=%s - """, (query.id,)): - data['report_resource'] = Resource('report', query.id) - data['description'] = description - else: - data['report_href'] = None - # Only interact with the batch modify module it it is enabled - # TODO: fix this for multiproduct - """ - from trac.ticket.batch import BatchModifyModule - if 'TICKET_BATCH_MODIFY' in req.perm and \ - self.env.is_component_enabled(BatchModifyModule): - self.env[BatchModifyModule].add_template_data(req, data, tickets) - """ - - data.setdefault('report', None) - data.setdefault('description', None) - data['title'] = title - - data['all_columns'] = query.get_all_columns() - # Don't allow the user to remove the id column - data['all_columns'].remove('id') - data['all_textareas'] = query.get_all_textareas() - - properties = dict((name, dict((key, field[key]) - for key in ('type', 'label', 'options', - 'optgroups') - if key in field)) - for name, field in data['fields'].iteritems()) - add_script_data(req, properties=properties, modes=data['modes']) - - add_stylesheet(req, 'common/css/report.css') - Chrome(self.env).add_jquery_ui(req) - add_script(req, 'common/js/query.js') +class ProductQueryModule(QueryModule): + def process_request(self, req, env=None): + tmpenv = self.env + if isinstance(self.env, ProductEnvironment) and env is not None: + self.env = env + result = super(ProductQueryModule, self).process_request(req) + self.env = tmpenv + return result - return 'query.html', data, None +trac.ticket.query.QueryModule = ProductQueryModule +trac.ticket.QueryModule = ProductQueryModule class ProductTicketQueryMacro(TicketQueryMacro): """TracQuery macro retrieving results across product boundaries. """ + @staticmethod + def parse_args(content): + """Parse macro arguments and translate them to a query string.""" + clauses = [{}] + argv = [] + kwargs = {} + for arg in TicketQueryMacro._comma_splitter.split(content): + arg = arg.replace(r'\,', ',') + m = re.match(r'\s*[^=]+=', arg) + if m: + kw = arg[:m.end() - 1].strip() + value = arg[m.end():] + if kw in ('order', 'max', 'format', 'col', 'product'): + kwargs[kw] = value + else: + clauses[-1][kw] = value + elif arg.strip() == 'or': + clauses.append({}) + else: + argv.append(arg) + clauses = filter(None, clauses) + + if len(argv) > 0 and not 'format' in kwargs: # 0.10 compatibility hack + kwargs['format'] = argv[0] + if 'order' not in kwargs: + kwargs['order'] = 'id' + if 'max' not in kwargs: + kwargs['max'] = '0' # unlimited by default + + format = kwargs.pop('format', 'list').strip().lower() + if format in ('list', 'compact'): # we need 'status' and 'summary' + if 'col' in kwargs: + kwargs['col'] = 'status|summary|' + kwargs['col'] + else: + kwargs['col'] = 'status|summary' + + query_string = '&or&'.join('&'.join('%s=%s' % item + for item in clause.iteritems()) + for clause in clauses) + return query_string, kwargs, format + def expand_macro(self, formatter, name, content): req = formatter.req query_string, kwargs, format = self.parse_args(content) @@ -327,7 +220,9 @@ class ProductTicketQueryMacro(TicketQuer query_string += '&' query_string += '&'.join('%s=%s' % item for item in kwargs.iteritems()) - query = ProductQuery.from_string(self.env, query_string) + + env = ProductEnvironment.lookup_global_env(self.env) + query = ProductQuery.from_string(env, query_string) if format == 'count': cnt = query.count(req) @@ -342,7 +237,7 @@ class ProductTicketQueryMacro(TicketQuer add_stylesheet(req, 'common/css/report.css') - return Chrome(self.env).render_template( + return Chrome(env).render_template( req, 'query_results.html', data, None, fragment=True) if format == 'progress': @@ -354,7 +249,7 @@ class ProductTicketQueryMacro(TicketQuer add_stylesheet(req, 'common/css/roadmap.css') def query_href(extra_args, group_value = None): - q = Query.from_string(self.env, query_string) + q = ProductQuery.from_string(env, query_string) if q.group: extra_args[q.group] = group_value q.group = None @@ -363,9 +258,9 @@ class ProductTicketQueryMacro(TicketQuer if not q.constraints: q.constraints.append(extra_args) return q.get_href(formatter.context) - chrome = Chrome(self.env) - tickets = apply_ticket_permissions(self.env, req, tickets) - stats_provider = RoadmapModule(self.env).stats_provider + chrome = Chrome(env) + tickets = apply_ticket_permissions(env, req, tickets) + stats_provider = RoadmapModule(env).stats_provider by = query.group if not by: stat = get_ticket_stats(stats_provider, tickets) @@ -393,7 +288,7 @@ class ProductTicketQueryMacro(TicketQuer 'legend': False, } - groups = grouped_stats_data(self.env, stats_provider, tickets, by, + groups = grouped_stats_data(env, stats_provider, tickets, by, per_group_stats_data) data = { 'groups': groups, 'grouped_by': by, @@ -438,7 +333,7 @@ class ProductTicketQueryMacro(TicketQuer def ticket_groups(): groups = [] for v, g in groupby(tickets, lambda t: t[query.group]): - q = Query.from_string(self.env, query_string) + q = ProductQuery.from_string(env, query_string) # produce the hint for the group q.group = q.groupdesc = None order = q.order Modified: bloodhound/trunk/bloodhound_multiproduct/setup.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/setup.py?rev=1511771&r1=1511770&r2=1511771&view=diff ============================================================================== --- bloodhound/trunk/bloodhound_multiproduct/setup.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/setup.py Thu Aug 8 13:19:01 2013 @@ -17,10 +17,22 @@ # under the License. """setup for multi product plugin""" -import sys +import sys, codecs from pkg_resources import parse_version from setuptools import setup + +# Force UTF-8 for stdout/err if --utf8 option is specified. +# For some reason python doesn't obey LANG/LC_CTYPE settings +# if output is not a terminal (e.g. pipes don't work). +if __name__ == '__main__': + for ac,av in enumerate(sys.argv): + if av == '--utf8': + sys.stdout = codecs.getwriter('utf8')(sys.stdout) + sys.stderr = codecs.getwriter('utf8')(sys.stderr) + del sys.argv[ac] + break + setup( name = 'BloodhoundMultiProduct', version = '0.7.0', Modified: bloodhound/trunk/bloodhound_multiproduct/tests/product-query-link-tests.txt URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/product-query-link-tests.txt?rev=1511771&r1=1511770&r2=1511771&view=diff ============================================================================== --- bloodhound/trunk/bloodhound_multiproduct/tests/product-query-link-tests.txt (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/product-query-link-tests.txt Thu Aug 8 13:19:01 2013 @@ -52,7 +52,7 @@ ============================== %(tc_title_prefix)s - ProductTicketQuery macro: no results, list form Reopened tickets: [[ProductTicketQuery(status=reopened)]] -Reopened tickets: [[ProductTicketQuery(status=reopened, product=%(setup_product_name)s)]] +Reopened tickets: [[ProductTicketQuery(status=reopened, product=%(setup_product)s)]] ------------------------------ <p> Reopened tickets: <span class="query_no_results">No results</span> @@ -64,19 +64,19 @@ Reopened tickets: <span class="query_no_ ============================== %(tc_title_prefix)s - ProductTicketQuery macro: no results, count 0 Reopened tickets: [[ProductTicketQuery(status=reopened, format=count)]] -Reopened tickets: [[ProductTicketQuery(status=reopened, format=count, product=%(setup_product_name)s)]] +Reopened tickets: [[ProductTicketQuery(status=reopened, format=count, product=%(setup_product)s)]] ------------------------------ <p> Reopened tickets: <span class="query_count" title="0 tickets for which status=reopened&max=0&order=id">0</span> </p> <p> -Reopened tickets: <span class="query_count" title="0 tickets for which status=reopened&product=%(setup_product_name)s&max=0&order=id">0</span> +Reopened tickets: <span class="query_count" title="0 tickets for which status=reopened&max=0&product=%(setup_product)s&order=id">0</span> </p> ------------------------------ ============================== %(tc_title_prefix)s - ProductTicketQuery macro: no results, compact form Reopened tickets: [[ProductTicketQuery(status=reopened, format=compact)]] -Reopened tickets: [[ProductTicketQuery(status=reopened, format=compact, product=%(setup_product_name)s)]] +Reopened tickets: [[ProductTicketQuery(status=reopened, format=compact, product=%(setup_product)s)]] ------------------------------ <p> Reopened tickets: <span class="query_no_results">No results</span> @@ -88,7 +88,7 @@ Reopened tickets: <span class="query_no_ ============================== %(tc_title_prefix)s - ProductTicketQuery macro: one result, list form New tickets: [[ProductTicketQuery(status=new)]] -New tickets: [[ProductTicketQuery(status=new, product=%(setup_product_name)s)]] +New tickets: [[ProductTicketQuery(status=new, product=%(setup_product)s)]] ------------------------------ <p> New tickets: </p><div><dl class="wiki compact"><dt><a class="new" href="%(path_prefix)s/ticket/1" title="This is the summary">#1</a></dt><dd>This is the summary</dd></dl></div><p> @@ -100,19 +100,19 @@ New tickets: </p><div><dl class="wiki co ============================== %(tc_title_prefix)s - ProductTicketQuery macro: one result, count 1 New tickets: [[ProductTicketQuery(status=new, format=count)]] -New tickets: [[ProductTicketQuery(status=new, format=count, product=%(setup_product_name)s)]] +New tickets: [[ProductTicketQuery(status=new, format=count, product=%(setup_product)s)]] ------------------------------ <p> New tickets: <span class="query_count" title="1 tickets for which status=new&max=0&order=id">1</span> </p> <p> -New tickets: <span class="query_count" title="1 tickets for which status=new&product=%(setup_product_name)s&max=0&order=id">1</span> +New tickets: <span class="query_count" title="1 tickets for which status=new&max=0&product=%(setup_product)s&order=id">1</span> </p> ------------------------------ ============================== %(tc_title_prefix)s - ProductTicketQuery macro: one result, compact form New tickets: [[ProductTicketQuery(status=new, format=compact)]] -New tickets: [[ProductTicketQuery(status=new, format=compact, product=%(setup_product_name)s)]] +New tickets: [[ProductTicketQuery(status=new, format=compact, product=%(setup_product)s)]] ------------------------------ <p> New tickets: <span><a class="new" href="%(path_prefix)s/ticket/1" title="This is the summary">#1</a></span> Modified: bloodhound/trunk/bloodhound_multiproduct/tests/wikisyntax.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/wikisyntax.py?rev=1511771&r1=1511770&r2=1511771&view=diff ============================================================================== --- bloodhound/trunk/bloodhound_multiproduct/tests/wikisyntax.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/wikisyntax.py Thu Aug 8 13:19:01 2013 @@ -65,7 +65,7 @@ def ticket_setup(tc): 'status': 'new'}) # FIXME : UGLY ! Should not be explicit for product environments - ticket['product'] = (tc.env.product.name + ticket['product'] = (tc.env.product.prefix if isinstance(tc.env, ProductEnvironment) else '') Modified: bloodhound/trunk/bloodhound_theme/bhtheme/theme.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_theme/bhtheme/theme.py?rev=1511771&r1=1511770&r2=1511771&view=diff ============================================================================== --- bloodhound/trunk/bloodhound_theme/bhtheme/theme.py (original) +++ bloodhound/trunk/bloodhound_theme/bhtheme/theme.py Thu Aug 8 13:19:01 2013 @@ -430,7 +430,8 @@ class BloodhoundTheme(ThemeBase): def _add_products_general_breadcrumb(self, req, template, data, content_type, is_active): - data['resourcepath_template'] = 'bh_path_general.html' + if isinstance(req.perm.env, ProductEnvironment): + data['resourcepath_template'] = 'bh_path_general.html' # INavigationContributor methods Modified: bloodhound/trunk/trac/trac/ticket/tests/query.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/trac/trac/ticket/tests/query.py?rev=1511771&r1=1511770&r2=1511771&view=diff ============================================================================== --- bloodhound/trunk/trac/trac/ticket/tests/query.py (original) +++ bloodhound/trunk/trac/trac/ticket/tests/query.py Thu Aug 8 13:19:01 2013 @@ -110,7 +110,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.product AS product,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 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) @@ -122,7 +122,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.product AS product,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 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) @@ -134,7 +134,7 @@ ORDER BY COALESCE(t.version,'')='' DESC, query = Query.from_string(self.env, 'milestone=milestone1', order='id') 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.time AS time,t.changetime AS changetime,t.milestone AS milestone,priority.value AS priority_value +"""SELECT t.product AS product,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.time AS time,t.changetime AS changetime,t.milestone AS milestone,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) WHERE ((COALESCE(t.milestone,'')=%s)) @@ -146,7 +146,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.product AS product,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 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) @@ -158,7 +158,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.product AS product,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 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) @@ -170,7 +170,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.product AS product,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 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""" % { @@ -182,7 +182,7 @@ ORDER BY COALESCE(priority.value,'')='', query = Query.from_string(self.env, 'milestone!=milestone1', order='id') sql, args = query.get_sql() self.assertEqualSQL(sql, -"""SELECT t.id AS id,t.summary AS summary,t.milestone AS milestone,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.time AS time,t.changetime AS changetime,priority.value AS priority_value +"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.milestone AS milestone,t.owner AS owner,t.type AS type,t.status AS status,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) WHERE ((COALESCE(t.milestone,'')!=%s)) @@ -357,7 +357,7 @@ ORDER BY COALESCE(t.id,0)=0,t.id""") query = Query.from_string(self.env, 'created=2008-08-01..2008-09-01', order='id') sql, args = query.get_sql(self.req) self.assertEqualSQL(sql, -"""SELECT t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.changetime AS changetime,priority.value AS priority_value +"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,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) WHERE (((%(cast_time)s>=%%s AND %(cast_time)s<%%s))) @@ -370,7 +370,7 @@ ORDER BY COALESCE(t.id,0)=0,t.id""" % { query = Query.from_string(self.env, 'created!=2008-08-01..2008-09-01', order='id') sql, args = query.get_sql(self.req) self.assertEqualSQL(sql, -"""SELECT t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.changetime AS changetime,priority.value AS priority_value +"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,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) WHERE ((NOT (%(cast_time)s>=%%s AND %(cast_time)s<%%s))) @@ -383,7 +383,7 @@ ORDER BY COALESCE(t.id,0)=0,t.id""" % { query = Query.from_string(self.env, 'created=2008-08-01..', order='id') sql, args = query.get_sql(self.req) self.assertEqualSQL(sql, -"""SELECT t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.changetime AS changetime,priority.value AS priority_value +"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,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) WHERE ((%(cast_time)s>=%%s)) @@ -396,7 +396,7 @@ ORDER BY COALESCE(t.id,0)=0,t.id""" % { query = Query.from_string(self.env, 'created=..2008-09-01', order='id') sql, args = query.get_sql(self.req) self.assertEqualSQL(sql, -"""SELECT t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.changetime AS changetime,priority.value AS priority_value +"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,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) WHERE ((%(cast_time)s<%%s)) @@ -409,7 +409,7 @@ ORDER BY COALESCE(t.id,0)=0,t.id""" % { query = Query.from_string(self.env, 'modified=2008-08-01..2008-09-01', order='id') sql, args = query.get_sql(self.req) self.assertEqualSQL(sql, -"""SELECT t.id AS id,t.summary AS summary,t.changetime AS changetime,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.time AS time,priority.value AS priority_value +"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.changetime AS changetime,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.time AS time,priority.value AS priority_value FROM ticket AS t LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) WHERE (((%(cast_changetime)s>=%%s AND %(cast_changetime)s<%%s))) @@ -423,7 +423,7 @@ ORDER BY COALESCE(t.id,0)=0,t.id""" % { order='id') sql, args = query.get_sql() self.assertEqualSQL(sql, -"""SELECT t.id AS id,t.summary AS summary,t.keywords AS keywords,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.time AS time,t.changetime AS changetime,priority.value AS priority_value +"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.keywords AS keywords,t.owner AS owner,t.type AS type,t.status AS status,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) WHERE (((COALESCE(t.keywords,'') %(like)s AND COALESCE(t.keywords,'') NOT %(like)s AND COALESCE(t.keywords,'') %(like)s)))