[IMP] Make wizard work
[odoo/odoo.git] / openerp / osv / query.py
index ab4f414..04a0ec5 100644 (file)
@@ -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 '<osv.Query: "SELECT ... FROM %s WHERE %s" with params: %r>' % 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: