X-Git-Url: http://git.inspyration.org/?a=blobdiff_plain;f=openerp%2Fosv%2Fquery.py;h=04a0ec5509b5ed88dc207b1dc0b4c602f6233d19;hb=23068e6afb63c172936eb70f7cce608c4dcaa338;hp=ab4f4143634a35566956d3fc0e1bbc30a9e939bf;hpb=f8572e5c602798f37c2a94d54ab5e3ac79ff0185;p=odoo%2Fodoo.git diff --git a/openerp/osv/query.py b/openerp/osv/query.py index ab4f414..04a0ec5 100644 --- a/openerp/osv/query.py +++ b/openerp/osv/query.py @@ -19,6 +19,8 @@ # ############################################################################## +#.apidoc title: Query object + def _quote(to_quote): if '"' not in to_quote: @@ -66,57 +68,92 @@ 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 _get_table_aliases(self): + from openerp.osv.expression import get_alias_from_query + return [get_alias_from_query(from_statement)[1] for from_statement in self.tables] + + def _get_alias_mapping(self): + from openerp.osv.expression import get_alias_from_query + mapping = {} + for table in self.tables: + alias, statement = get_alias_from_query(table) + mapping[statement] = table + return mapping + + def add_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. Implicit joins do not handle outer parameter. + :param connection: a tuple ``(lhs, table, lhs_col, col, link)``. + The join corresponds to the SQL equivalent of:: - :param connection: a tuple ``(lhs, table, lhs_col, col)``. - The join corresponds to the SQL equivalent of:: + (lhs.lhs_col = table.col) - ``(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 + :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) + 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) """ - (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!" - if table in self.tables: - # already joined, must ignore (promotion to outer and multiple joins not supported yet) - pass + from openerp.osv.expression import generate_table_alias + (lhs, table, lhs_col, col, link) = connection + alias, alias_statement = generate_table_alias(lhs, [(table, link)]) + + if implicit: + if alias_statement not in self.tables: + self.tables.append(alias_statement) + condition = '("%s"."%s" = "%s"."%s")' % (lhs, lhs_col, alias, col) + self.where_clause.append(condition) + else: + # already joined + pass + return alias, alias_statement else: - # add JOIN - self.tables.append(table) - self.joins.setdefault(lhs, []).append((table, lhs_col, col, outer and 'LEFT JOIN' or 'JOIN')) - return self + 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)) + if alias_statement in self.tables: + # already joined, must ignore (promotion to outer and multiple joins not supported yet) + pass + else: + # add JOIN + self.tables.append(alias_statement) + self.joins.setdefault(lhs, []).append((alias, lhs_col, col, outer and 'LEFT JOIN' or 'JOIN')) + return alias, alias_statement def get_sql(self): - """Returns (query_from, query_where, query_params)""" + """ Returns (query_from, query_where, query_params). """ + from openerp.osv.expression import get_alias_from_query query_from = '' tables_to_process = list(self.tables) + alias_mapping = self._get_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) + for (dest_table, lhs_col, col, join) in self.joins.get(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) + table_alias = get_alias_from_query(table)[1] + if table_alias in self.joins: + query_from = add_joins_for_table(table_alias, query_from) query_from += ',' - query_from = query_from[:-1] # drop last comma - return (query_from, " AND ".join(self.where_clause), self.where_clause_params) + query_from = query_from[:-1] # drop last comma + return query_from, " AND ".join(self.where_clause), self.where_clause_params def __str__(self): return '' % self.get_sql() -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: