[IMP] [WIP] order_by: now using aliases in _generate_order_by, _generate_o2m_order_by, _inherits_join_add, ... added some tests. Next comits will clean a bit the code, because currently it is a bit messy.
bzr revid: tde@openerp.com-20121207115424-x8gkjcqpi8dz96g2
This commit is contained in:
parent
f810fb0526
commit
e36b44e82f
|
@ -432,7 +432,6 @@ class test_expression(common.TransactionCase):
|
|||
partner_state_id_col._auto_join = False
|
||||
partner_parent_id_col._auto_join = False
|
||||
state_country_id_col._auto_join = False
|
||||
BaseModel._where_calc = self._base_model_where_calc
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest2.main()
|
||||
|
|
|
@ -2,9 +2,10 @@ import unittest2
|
|||
|
||||
import openerp.tests.common as common
|
||||
|
||||
class test_expression(common.TransactionCase):
|
||||
|
||||
def test_search_order(self):
|
||||
class test_search(common.TransactionCase):
|
||||
|
||||
def test_00_search_order(self):
|
||||
|
||||
registry, cr, uid = self.registry, self.cr, self.uid
|
||||
|
||||
|
@ -57,4 +58,28 @@ class test_expression(common.TransactionCase):
|
|||
id_desc_active_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id desc, active desc")
|
||||
self.assertEqual([e, ab, b, a, d, c], id_desc_active_desc, "Search with 'ID DESC, ACTIVE DESC' order failed.")
|
||||
|
||||
def test_10_m2order(self):
|
||||
registry, cr, uid = self.registry, self.cr, self.uid
|
||||
users_obj = registry('res.users')
|
||||
|
||||
# Find Employee group
|
||||
group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user')
|
||||
group_employee_id = group_employee_ref and group_employee_ref[1] or False
|
||||
|
||||
search_user = users_obj.create(cr, uid, {'name': '__search', 'login': '__search', 'groups_id': [(6, 0, [group_employee_id])]})
|
||||
a = users_obj.create(cr, uid, {'name': '__test_A', 'login': '__z_test_A'})
|
||||
b = users_obj.create(cr, uid, {'name': '__test_B', 'login': '__a_test_B'})
|
||||
|
||||
# Do: search on res.users, order on a field on res.partner, then res.users
|
||||
print '\n\n'
|
||||
user_ids = users_obj.search(cr, search_user, [], order='name asc, login desc')
|
||||
self.assertTrue(set([search_user, a, b]).issubset(set(user_ids)), 'cacaprout')
|
||||
|
||||
# DO: order on a many2one
|
||||
print '\n\n'
|
||||
user_ids = users_obj.search(cr, search_user, [], order='state_id asc, country_id desc, name asc, login desc')
|
||||
print user_ids[0:25]
|
||||
# self.assertTrue(set([search_user, a, b]).issubset(set(user_ids)), 'cacaprout')
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest2.main()
|
||||
|
|
|
@ -319,16 +319,18 @@ def _quote(to_quote):
|
|||
return to_quote
|
||||
|
||||
|
||||
def generate_table_alias(src_model, joined_tables=[]):
|
||||
def generate_table_alias(src_table_alias, joined_tables=[]):
|
||||
""" Generate a standard table alias name. An alias is generated as following:
|
||||
- the base is the source model table name
|
||||
- the base is the source table name (that can already be an alias)
|
||||
- then, each joined table is added in the alias using a 'link field name'
|
||||
that is used to render unique aliases for a given path
|
||||
- returns a tuple composed of the alias, and the full table alias to be
|
||||
added in a from condition
|
||||
Examples:
|
||||
- src_model=res.users, join_tables=[]:
|
||||
alias = '"res_users"'
|
||||
- src_model=res.users, join_tables=[(res.partner, 'parent_id')]
|
||||
alias = '"res_partner" as "res_users__parent_id"'
|
||||
- src_table_alias='res_users', join_tables=[]:
|
||||
alias = ('res_users','"res_users"')
|
||||
- src_model='res_users', join_tables=[(res.partner, 'parent_id')]
|
||||
alias = ('res_users__parent_id', '"res_partner" as "res_users__parent_id"')
|
||||
|
||||
:param model src_model: model source of the alias
|
||||
:param list join_tables: list of tuples
|
||||
|
@ -336,12 +338,12 @@ def generate_table_alias(src_model, joined_tables=[]):
|
|||
|
||||
:return tuple: (table alias, alias statement for from clause with quotes added)
|
||||
"""
|
||||
alias = src_model._table
|
||||
alias = src_table_alias
|
||||
if not joined_tables:
|
||||
return ('%s' % alias, '%s' % _quote(alias))
|
||||
for link in joined_tables:
|
||||
alias += '__' + link[1]
|
||||
return ('%s' % alias, '%s as %s' % (_quote(joined_tables[-1][0]._table), _quote(alias)))
|
||||
return ('%s' % alias, '%s as %s' % (_quote(joined_tables[-1][0]), _quote(alias)))
|
||||
|
||||
|
||||
def normalize_leaf(element):
|
||||
|
@ -499,8 +501,8 @@ class ExtendedLeaf(object):
|
|||
# --------------------------------------------------
|
||||
|
||||
def generate_alias(self):
|
||||
links = [(context[1], context[4]) for context in self.context_stack]
|
||||
alias, alias_statement = generate_table_alias(self._tables[0], links)
|
||||
links = [(context[1]._table, context[4]) for context in self.context_stack]
|
||||
alias, alias_statement = generate_table_alias(self._tables[0]._table, links)
|
||||
return alias
|
||||
|
||||
def add_join_context(self, table, lhs_col, table_col, link):
|
||||
|
|
|
@ -58,7 +58,6 @@ import types
|
|||
|
||||
import psycopg2
|
||||
from lxml import etree
|
||||
import warnings
|
||||
|
||||
import fields
|
||||
import openerp
|
||||
|
@ -2720,20 +2719,23 @@ class BaseModel(object):
|
|||
|
||||
return result
|
||||
|
||||
def _inherits_join_add(self, current_table, parent_model_name, query):
|
||||
def _inherits_join_add(self, current_model, parent_model_name, query):
|
||||
"""
|
||||
Add missing table SELECT and JOIN clause to ``query`` for reaching the parent table (no duplicates)
|
||||
:param current_table: current model object
|
||||
:param current_model: current model object
|
||||
:param parent_model_name: name of the parent model for which the clauses should be added
|
||||
:param query: query object on which the JOIN should be added
|
||||
"""
|
||||
inherits_field = current_table._inherits[parent_model_name]
|
||||
inherits_field = current_model._inherits[parent_model_name]
|
||||
parent_model = self.pool.get(parent_model_name)
|
||||
parent_table_name = parent_model._table
|
||||
quoted_parent_table_name = '"%s"' % parent_table_name
|
||||
if quoted_parent_table_name not in query.tables:
|
||||
query.tables.append(quoted_parent_table_name)
|
||||
query.where_clause.append('(%s.%s = %s.id)' % (current_table._table, inherits_field, parent_table_name))
|
||||
parent_alias = query.add_implicit_join((current_model, parent_model, inherits_field, 'id', inherits_field))
|
||||
return parent_alias
|
||||
# table_alias = expression.generate_table_alias(current_model, [(parent_model, inherits_field)])
|
||||
# print '\t... _inherits_join_add trying to add %s in %s' % (table_alias, query.tables)
|
||||
# # query.add_table(table_alias)
|
||||
# if table_alias not in query.tables:
|
||||
# query.tables.append(table_alias)
|
||||
# query.where_clause.append('("%s".%s = %s.id)' % (current_model._table, inherits_field, table_alias))
|
||||
|
||||
def _inherits_join_calc(self, field, query):
|
||||
"""
|
||||
|
@ -2744,13 +2746,15 @@ class BaseModel(object):
|
|||
:param query: query object on which the JOIN should be added
|
||||
:return: qualified name of field, to be used in SELECT clause
|
||||
"""
|
||||
print '\t--> _inherits_join_calc'
|
||||
current_table = self
|
||||
parent_alias = current_table._table
|
||||
while field in current_table._inherit_fields and not field in current_table._columns:
|
||||
parent_model_name = current_table._inherit_fields[field][0]
|
||||
parent_table = self.pool.get(parent_model_name)
|
||||
self._inherits_join_add(current_table, parent_model_name, query)
|
||||
parent_alias = self._inherits_join_add(current_table, parent_model_name, query)
|
||||
current_table = parent_table
|
||||
return '"%s".%s' % (current_table._table, field)
|
||||
return '%s."%s"' % (parent_alias, field)
|
||||
|
||||
def _parent_store_compute(self, cr):
|
||||
if not self._parent_store:
|
||||
|
@ -4659,28 +4663,49 @@ class BaseModel(object):
|
|||
:param query: the current query object
|
||||
"""
|
||||
def apply_rule(added_clause, added_params, added_tables, parent_model=None, child_object=None):
|
||||
""" :param string parent_model: string of the parent model
|
||||
:param model child_object: model object, base of the rule application
|
||||
"""
|
||||
if added_clause:
|
||||
print '--> _apply_ir_rules.apply_rule,', added_clause, added_params, added_tables, parent_model, child_object
|
||||
if parent_model and child_object:
|
||||
print '\t... calling inherits-Join_add with parent_model %s, child_object %s' % (parent_model, child_object)
|
||||
# as inherited rules are being applied, we need to add the missing JOIN
|
||||
# to reach the parent table (if it was not JOINed yet in the query)
|
||||
child_object._inherits_join_add(child_object, parent_model, query)
|
||||
parent_alias = child_object._inherits_join_add(child_object, parent_model, query)
|
||||
# inherited rules are applied on the external table -> need to get the alias and replace
|
||||
parent_table = self.pool.get(parent_model)._table
|
||||
print parent_table, parent_alias
|
||||
added_clause = [clause.replace('"%s"' % parent_table, '"%s"' % parent_alias) for clause in added_clause]
|
||||
# not sure of myself here (in the ORM, this statment is quite cool)
|
||||
new_tables = []
|
||||
for table in added_tables:
|
||||
if table == '"%s"' % (parent_table):
|
||||
new_table = '"%s" as "%s"' % (parent_table, parent_alias)
|
||||
else:
|
||||
new_table = table.replace('"%s"' % parent_table, '"%s"' % parent_alias)
|
||||
new_tables.append(new_table)
|
||||
added_tables = new_tables
|
||||
print '\t... adding tables %s, clause %s (params %s)' % (added_tables, added_clause, added_params)
|
||||
query.where_clause += added_clause
|
||||
query.where_clause_params += added_params
|
||||
for table in added_tables:
|
||||
quoted_table_name = '%s' % (table)
|
||||
if quoted_table_name not in query.tables:
|
||||
query.tables.append(quoted_table_name)
|
||||
print '\t... adding table %s in %s' % (table, query.tables)
|
||||
if table not in query.tables:
|
||||
query.tables.append(table)
|
||||
return True
|
||||
return False
|
||||
|
||||
# apply main rules on the object
|
||||
rule_obj = self.pool.get('ir.rule')
|
||||
apply_rule(*rule_obj.domain_get(cr, uid, self._name, mode, context=context))
|
||||
rule_where_clause, rule_where_clause_params, rule_tables = rule_obj.domain_get(cr, uid, self._name, mode, context=context)
|
||||
apply_rule(rule_where_clause, rule_where_clause_params, rule_tables)
|
||||
|
||||
# apply ir.rules from the parents (through _inherits)
|
||||
for inherited_model in self._inherits:
|
||||
kwargs = dict(parent_model=inherited_model, child_object=self) #workaround for python2.5
|
||||
apply_rule(*rule_obj.domain_get(cr, uid, inherited_model, mode, context=context), **kwargs)
|
||||
rule_where_clause, rule_where_clause_params, rule_tables = rule_obj.domain_get(cr, uid, inherited_model, mode, context=context)
|
||||
apply_rule(rule_where_clause, rule_where_clause_params, rule_tables,
|
||||
parent_model=inherited_model, child_object=self)
|
||||
|
||||
def _generate_m2o_order_by(self, order_field, query):
|
||||
"""
|
||||
|
@ -4690,6 +4715,7 @@ class BaseModel(object):
|
|||
|
||||
:return: the qualified field name to use in an ORDER BY clause to sort by ``order_field``
|
||||
"""
|
||||
print '_generate_m2o_order_by'
|
||||
if order_field not in self._columns and order_field in self._inherit_fields:
|
||||
# also add missing joins for reaching the table containing the m2o field
|
||||
qualified_field = self._inherits_join_calc(order_field, query)
|
||||
|
@ -4721,11 +4747,10 @@ class BaseModel(object):
|
|||
# Join the dest m2o table if it's not joined yet. We use [LEFT] OUTER join here
|
||||
# as we don't want to exclude results that have NULL values for the m2o
|
||||
src_table, src_field = qualified_field.replace('"', '').split('.', 1)
|
||||
query.join((src_table, dest_model._table, src_field, 'id'), outer=True)
|
||||
qualify = lambda field: '"%s"."%s"' % (dest_model._table, field)
|
||||
dst_alias = query.add_join((src_table, dest_model._table, src_field, 'id'), outer=True)
|
||||
qualify = lambda field: '"%s"."%s"' % (dst_alias, field)
|
||||
return map(qualify, m2o_order) if isinstance(m2o_order, list) else qualify(m2o_order)
|
||||
|
||||
|
||||
def _generate_order_by(self, order_spec, query):
|
||||
"""
|
||||
Attempt to consruct an appropriate ORDER BY clause based on order_spec, which must be
|
||||
|
@ -4742,9 +4767,9 @@ class BaseModel(object):
|
|||
subelems.append(' ')
|
||||
order_list.append('"%s"."%s" %s' % (table, subelems[0], subelems[1]))
|
||||
return order_list
|
||||
|
||||
order_by_clause = ','.join(_split_order(self._order, self._table))
|
||||
if order_spec:
|
||||
print '-->_generate_order_by beginning'
|
||||
order_by_elements = []
|
||||
self._check_qorder(order_spec)
|
||||
for order_part in order_spec.split(','):
|
||||
|
@ -4779,6 +4804,7 @@ class BaseModel(object):
|
|||
order_by_elements.append("%s %s" % (inner_clause, order_direction))
|
||||
if order_by_elements:
|
||||
order_by_clause = ",".join(order_by_elements)
|
||||
print '-->_generate_order_by ending'
|
||||
|
||||
return order_by_clause and (' ORDER BY %s ' % order_by_clause) or ''
|
||||
|
||||
|
|
|
@ -21,12 +21,21 @@
|
|||
|
||||
#.apidoc title: Query object
|
||||
|
||||
|
||||
def _quote(to_quote):
|
||||
if '"' not in to_quote:
|
||||
return '"%s"' % to_quote
|
||||
return to_quote
|
||||
|
||||
|
||||
def _get_alias_from_statement(string):
|
||||
if len(string.split(' as ')) > 1:
|
||||
alias = string.split(' as ')[1].replace('"', '')
|
||||
else:
|
||||
alias = string.replace('"', '')
|
||||
return alias
|
||||
|
||||
|
||||
class Query(object):
|
||||
"""
|
||||
Dumb implementation of a Query object, using 3 string lists so far
|
||||
|
@ -44,6 +53,9 @@ class Query(object):
|
|||
# holds the list of tables joined using default JOIN.
|
||||
# the table names are stored double-quoted (backwards compatibility)
|
||||
self.tables = tables or []
|
||||
# holds a mapping of table aliases:
|
||||
# self._table_alias_mapping = {'alias_1': 'table_name'}
|
||||
self._table_alias_mapping = {}
|
||||
|
||||
# holds the list of WHERE clause elements, to be joined with
|
||||
# 'AND' when generating the final query
|
||||
|
@ -67,14 +79,44 @@ class Query(object):
|
|||
# LEFT JOIN "table_c" ON ("table_a"."table_a_col2" = "table_c"."table_c_col")
|
||||
self.joins = joins or {}
|
||||
|
||||
def join(self, connection, outer=False):
|
||||
"""Adds the JOIN specified in ``connection``.
|
||||
def _add_table_alias(self, table_alias):
|
||||
pass
|
||||
|
||||
:param connection: a tuple ``(lhs, table, lhs_col, col)``.
|
||||
def _get_table_aliases(self):
|
||||
aliases = []
|
||||
for table in self.tables:
|
||||
if len(table.split(' as ')) > 1:
|
||||
aliases.append(table.split(' as ')[1].replace('"', ''))
|
||||
else:
|
||||
aliases.append(table.replace('"', ''))
|
||||
# print '--', aliases
|
||||
return aliases
|
||||
|
||||
def _get_alias_mapping(self):
|
||||
mapping = {}
|
||||
aliases = self._get_table_aliases()
|
||||
for alias in aliases:
|
||||
for table in self.tables:
|
||||
if '"%s"' % (alias) in table:
|
||||
mapping.setdefault(alias, table)
|
||||
return mapping
|
||||
|
||||
def add_new_join(self, connection, implicit=True, outer=False):
|
||||
""" Join a destination table to the current table.
|
||||
|
||||
:param implicit: False if the join is an explicit join. This allows
|
||||
to fall back on the previous implementation of ``join`` before
|
||||
OpenERP 7.0. It therefore adds the JOIN specified in ``connection``
|
||||
If True, the join is done implicitely, by adding the table alias
|
||||
in the from clause and the join condition in the where clause
|
||||
of the query.
|
||||
:param connection: a tuple ``(lhs, table, lhs_col, col, link)``.
|
||||
The join corresponds to the SQL equivalent of::
|
||||
|
||||
(lhs.lhs_col = table.col)
|
||||
|
||||
Note that all connection elements are strings. Please refer to expression.py for more details about joins.
|
||||
|
||||
:param outer: True if a LEFT OUTER JOIN should be used, if possible
|
||||
(no promotion to OUTER JOIN is supported in case the JOIN
|
||||
was already present in the query, as for the moment
|
||||
|
@ -83,10 +125,32 @@ class Query(object):
|
|||
``_inherits`` or when a domain criterion explicitly
|
||||
adds filtering)
|
||||
"""
|
||||
from openerp.osv.expression import generate_table_alias
|
||||
(lhs, table, lhs_col, col, link) = connection
|
||||
alias, alias_statement = generate_table_alias(lhs._table, [(table._table, link)])
|
||||
|
||||
if implicit:
|
||||
print '\t\t... Query: trying to add %s in %s (received %s)' % (alias_statement, self.tables, connection)
|
||||
if alias_statement not in self.tables:
|
||||
self.tables.append(alias_statement)
|
||||
condition = '("%s"."%s" = "%s"."%s")' % (lhs._table, lhs_col, alias, col)
|
||||
print '\t\t... added %s' % (condition)
|
||||
self.where_clause.append(condition)
|
||||
return alias
|
||||
else:
|
||||
(lhs, table, lhs_col, col) = connection
|
||||
lhs = _quote(lhs)
|
||||
table = _quote(table)
|
||||
assert lhs in self.tables, "Left-hand-side table must already be part of the query!"
|
||||
print connection
|
||||
aliases = []
|
||||
for table in self.tables:
|
||||
if len(table.split(' as ')) > 1:
|
||||
aliases.append(table.split(' as ')[1])
|
||||
else:
|
||||
aliases.append(table)
|
||||
print '--', aliases
|
||||
aliases = [table.split(' as ') for table in self.tables]
|
||||
assert lhs in self.aliases, "Left-hand-side table %s must already be part of the query tables %s!" % (lhs, str(self.tables))
|
||||
if table in self.tables:
|
||||
# already joined, must ignore (promotion to outer and multiple joins not supported yet)
|
||||
pass
|
||||
|
@ -96,23 +160,92 @@ class Query(object):
|
|||
self.joins.setdefault(lhs, []).append((table, lhs_col, col, outer and 'LEFT JOIN' or 'JOIN'))
|
||||
return self
|
||||
|
||||
def add_implicit_join(self, connection):
|
||||
""" Adds an implicit join. This means that left-hand table is added to the
|
||||
Query.tables (adding a table in the from clause), and that a join
|
||||
condition is added in Query.where_clause.
|
||||
|
||||
Implicit joins use expression.generate_table_alias to generate the
|
||||
alias the the joined table.
|
||||
|
||||
:param connection: a tuple``(lhs, table, lhs_col, col, link)`` Please
|
||||
refer to expression.py for more details about joins.
|
||||
"""
|
||||
from openerp.osv.expression import generate_table_alias
|
||||
(lhs, table, lhs_col, col, link) = connection
|
||||
alias, alias_statement = generate_table_alias(lhs._table, [(table._table, link)])
|
||||
print '\t\t... Query: trying to add %s in %s (received %s)' % (alias_statement, self.tables, connection)
|
||||
if alias_statement not in self.tables:
|
||||
self.tables.append(alias_statement)
|
||||
condition = '("%s"."%s" = "%s"."%s")' % (lhs._table, lhs_col, alias, col)
|
||||
print '\t\t... added %s' % (condition)
|
||||
self.where_clause.append(condition)
|
||||
return alias
|
||||
|
||||
def add_join(self, connection, outer=False):
|
||||
"""Adds the JOIN specified in ``connection``.
|
||||
|
||||
:param connection: a tuple ``(lhs, table, lhs_col, col)``.
|
||||
The join corresponds to the SQL equivalent of::
|
||||
|
||||
(lhs.lhs_col = table.col)
|
||||
|
||||
Note that all connection elements are strings.
|
||||
|
||||
:param outer: True if a LEFT OUTER JOIN should be used, if possible
|
||||
(no promotion to OUTER JOIN is supported in case the JOIN
|
||||
was already present in the query, as for the moment
|
||||
implicit INNER JOINs are only connected from NON-NULL
|
||||
columns so it would not be correct (e.g. for
|
||||
``_inherits`` or when a domain criterion explicitly
|
||||
adds filtering)
|
||||
"""
|
||||
from openerp.osv.expression import generate_table_alias
|
||||
(lhs, table, lhs_col, col) = connection
|
||||
# lhs = _quote(lhs)
|
||||
# table = _quote(table)
|
||||
print '\t\t... Query.add_join(): adding connection %s' % str(connection)
|
||||
|
||||
aliases = self._get_table_aliases()
|
||||
|
||||
assert lhs in aliases, "Left-hand-side table %s must already be part of the query tables %s!" % (lhs, str(self.tables))
|
||||
|
||||
rhs, rhs_statement = generate_table_alias(lhs, [(connection[1], connection[2])])
|
||||
print rhs, rhs_statement
|
||||
|
||||
if rhs_statement in self.tables:
|
||||
# already joined, must ignore (promotion to outer and multiple joins not supported yet)
|
||||
pass
|
||||
else:
|
||||
# add JOIN
|
||||
self.tables.append(rhs_statement)
|
||||
self.joins.setdefault(lhs, []).append((rhs, lhs_col, col, outer and 'LEFT JOIN' or 'JOIN'))
|
||||
return rhs
|
||||
|
||||
def get_sql(self):
|
||||
"""Returns (query_from, query_where, query_params)"""
|
||||
query_from = ''
|
||||
tables_to_process = list(self.tables)
|
||||
|
||||
alias_mapping = self._get_alias_mapping()
|
||||
|
||||
# print 'tables_to_process %s' % (tables_to_process)
|
||||
# print 'self.joins %s' % (self.joins)
|
||||
# print 'alias_mapping %s' % (alias_mapping)
|
||||
|
||||
def add_joins_for_table(table, query_from):
|
||||
for (dest_table, lhs_col, col, join) in self.joins.get(table, []):
|
||||
tables_to_process.remove(dest_table)
|
||||
query_from += ' %s %s ON (%s."%s" = %s."%s")' % \
|
||||
(join, dest_table, table, lhs_col, dest_table, col)
|
||||
# print dest_table
|
||||
tables_to_process.remove(alias_mapping[dest_table])
|
||||
query_from += ' %s %s ON ("%s"."%s" = "%s"."%s")' % \
|
||||
(join, alias_mapping[dest_table], table, lhs_col, dest_table, col)
|
||||
query_from = add_joins_for_table(dest_table, query_from)
|
||||
return query_from
|
||||
|
||||
for table in tables_to_process:
|
||||
query_from += table
|
||||
if table in self.joins:
|
||||
query_from = add_joins_for_table(table, query_from)
|
||||
if _get_alias_from_statement(table) in self.joins:
|
||||
query_from = add_joins_for_table(_get_alias_from_statement(table), query_from)
|
||||
query_from += ','
|
||||
query_from = query_from[:-1] # drop last comma
|
||||
return (query_from, " AND ".join(self.where_clause), self.where_clause_params)
|
||||
|
|
|
@ -28,8 +28,8 @@ class QueryTestCase(unittest.TestCase):
|
|||
query = Query()
|
||||
query.tables.extend(['"product_product"','"product_template"'])
|
||||
query.where_clause.append("product_product.template_id = product_template.id")
|
||||
query.join(("product_template", "product_category", "categ_id", "id"), outer=False) # add normal join
|
||||
query.join(("product_product", "res_user", "user_id", "id"), outer=True) # outer join
|
||||
query.add_join(("product_template", "product_category", "categ_id", "id"), outer=False) # add normal join
|
||||
query.add_join(("product_product", "res_user", "user_id", "id"), outer=True) # outer join
|
||||
self.assertEquals(query.get_sql()[0].strip(),
|
||||
""""product_product" LEFT JOIN "res_user" ON ("product_product"."user_id" = "res_user"."id"),"product_template" JOIN "product_category" ON ("product_template"."categ_id" = "product_category"."id") """.strip())
|
||||
self.assertEquals(query.get_sql()[1].strip(), """product_product.template_id = product_template.id""".strip())
|
||||
|
@ -38,8 +38,8 @@ class QueryTestCase(unittest.TestCase):
|
|||
query = Query()
|
||||
query.tables.extend(['"product_product"','"product_template"'])
|
||||
query.where_clause.append("product_product.template_id = product_template.id")
|
||||
query.join(("product_template", "product_category", "categ_id", "id"), outer=False) # add normal join
|
||||
query.join(("product_category", "res_user", "user_id", "id"), outer=True) # CHAINED outer join
|
||||
query.add_join(("product_template", "product_category", "categ_id", "id"), outer=False) # add normal join
|
||||
query.add_join(("product_category", "res_user", "user_id", "id"), outer=True) # CHAINED outer join
|
||||
self.assertEquals(query.get_sql()[0].strip(),
|
||||
""""product_product","product_template" JOIN "product_category" ON ("product_template"."categ_id" = "product_category"."id") LEFT JOIN "res_user" ON ("product_category"."user_id" = "res_user"."id")""".strip())
|
||||
self.assertEquals(query.get_sql()[1].strip(), """product_product.template_id = product_template.id""".strip())
|
||||
|
@ -48,8 +48,8 @@ class QueryTestCase(unittest.TestCase):
|
|||
query = Query()
|
||||
query.tables.extend(['"product_product"','"product_template"'])
|
||||
query.where_clause.append("product_product.template_id = product_template.id")
|
||||
query.join(("product_template", "product_category", "categ_id", "id"), outer=False) # add normal join
|
||||
query.join(("product_category", "res_user", "user_id", "id"), outer=True) # CHAINED outer join
|
||||
query.add_join(("product_template", "product_category", "categ_id", "id"), outer=False) # add normal join
|
||||
query.add_join(("product_category", "res_user", "user_id", "id"), outer=True) # CHAINED outer join
|
||||
query.tables.append('"account.account"')
|
||||
query.where_clause.append("product_category.expense_account_id = account_account.id") # additional implicit join
|
||||
self.assertEquals(query.get_sql()[0].strip(),
|
||||
|
|
Loading…
Reference in New Issue