~camptocamp/openobject-server/trunk-deprecate-osv_osv

« back to all changes in this revision

Viewing changes to openerp/osv/query.py

  • Committer: Alexandre Fayolle @ camptocamp
  • Date: 2012-12-20 10:26:40 UTC
  • mfrom: (4440.1.272 trunk)
  • Revision ID: alexandre.fayolle@camptocamp.com-20121220102640-z203u1jka5xmvjir
[MRG] updated to current trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 
22
22
#.apidoc title: Query object
23
23
 
 
24
 
24
25
def _quote(to_quote):
25
26
    if '"' not in to_quote:
26
27
        return '"%s"' % to_quote
67
68
        #                                 LEFT JOIN "table_c" ON ("table_a"."table_a_col2" = "table_c"."table_c_col")
68
69
        self.joins = joins or {}
69
70
 
70
 
    def join(self, connection, outer=False):
71
 
        """Adds the JOIN specified in ``connection``.
72
 
 
73
 
        :param connection: a tuple ``(lhs, table, lhs_col, col)``.
74
 
                           The join corresponds to the SQL equivalent of::
75
 
 
76
 
                                ``(lhs.lhs_col = table.col)``
77
 
 
78
 
        :param outer: True if a LEFT OUTER JOIN should be used, if possible
 
71
    def _get_table_aliases(self):
 
72
        from openerp.osv.expression import get_alias_from_query
 
73
        return [get_alias_from_query(from_statement)[1] for from_statement in self.tables]
 
74
 
 
75
    def _get_alias_mapping(self):
 
76
        from openerp.osv.expression import get_alias_from_query
 
77
        mapping = {}
 
78
        for table in self.tables:
 
79
            alias, statement = get_alias_from_query(table)
 
80
            mapping[statement] = table
 
81
        return mapping
 
82
 
 
83
    def add_join(self, connection, implicit=True, outer=False):
 
84
        """ Join a destination table to the current table.
 
85
 
 
86
            :param implicit: False if the join is an explicit join. This allows
 
87
                to fall back on the previous implementation of ``join`` before
 
88
                OpenERP 7.0. It therefore adds the JOIN specified in ``connection``
 
89
                If True, the join is done implicitely, by adding the table alias
 
90
                in the from clause and the join condition in the where clause
 
91
                of the query. Implicit joins do not handle outer parameter.
 
92
            :param connection: a tuple ``(lhs, table, lhs_col, col, link)``.
 
93
                The join corresponds to the SQL equivalent of::
 
94
 
 
95
                (lhs.lhs_col = table.col)
 
96
 
 
97
                Note that all connection elements are strings. Please refer to expression.py for more details about joins.
 
98
 
 
99
            :param outer: True if a LEFT OUTER JOIN should be used, if possible
79
100
                      (no promotion to OUTER JOIN is supported in case the JOIN
80
 
                       was already present in the query, as for the moment
81
 
                       implicit INNER JOINs are only connected from NON-NULL
82
 
                       columns so it would not be correct (e.g. for
83
 
                       ``_inherits`` or when a domain criterion explicitly
84
 
                       adds filtering)
 
101
                      was already present in the query, as for the moment
 
102
                      implicit INNER JOINs are only connected from NON-NULL
 
103
                      columns so it would not be correct (e.g. for
 
104
                      ``_inherits`` or when a domain criterion explicitly
 
105
                      adds filtering)
85
106
        """
86
 
        (lhs, table, lhs_col, col) = connection
87
 
        lhs = _quote(lhs)
88
 
        table = _quote(table)
89
 
        assert lhs in self.tables, "Left-hand-side table must already be part of the query!"
90
 
        if table in self.tables:
91
 
            # already joined, must ignore (promotion to outer and multiple joins not supported yet)
92
 
            pass
 
107
        from openerp.osv.expression import generate_table_alias
 
108
        (lhs, table, lhs_col, col, link) = connection
 
109
        alias, alias_statement = generate_table_alias(lhs, [(table, link)])
 
110
 
 
111
        if implicit:
 
112
            if alias_statement not in self.tables:
 
113
                self.tables.append(alias_statement)
 
114
                condition = '("%s"."%s" = "%s"."%s")' % (lhs, lhs_col, alias, col)
 
115
                self.where_clause.append(condition)
 
116
            else:
 
117
                # already joined
 
118
                pass
 
119
            return alias, alias_statement
93
120
        else:
94
 
            # add JOIN
95
 
            self.tables.append(table)
96
 
            self.joins.setdefault(lhs, []).append((table, lhs_col, col, outer and 'LEFT JOIN' or 'JOIN'))
97
 
        return self
 
121
            aliases = self._get_table_aliases()
 
122
            assert lhs in aliases, "Left-hand-side table %s must already be part of the query tables %s!" % (lhs, str(self.tables))
 
123
            if alias_statement in self.tables:
 
124
                # already joined, must ignore (promotion to outer and multiple joins not supported yet)
 
125
                pass
 
126
            else:
 
127
                # add JOIN
 
128
                self.tables.append(alias_statement)
 
129
                self.joins.setdefault(lhs, []).append((alias, lhs_col, col, outer and 'LEFT JOIN' or 'JOIN'))
 
130
            return alias, alias_statement
98
131
 
99
132
    def get_sql(self):
100
 
        """Returns (query_from, query_where, query_params)"""
 
133
        """ Returns (query_from, query_where, query_params). """
 
134
        from openerp.osv.expression import get_alias_from_query
101
135
        query_from = ''
102
136
        tables_to_process = list(self.tables)
 
137
        alias_mapping = self._get_alias_mapping()
103
138
 
104
139
        def add_joins_for_table(table, query_from):
105
 
            for (dest_table, lhs_col, col, join) in self.joins.get(table,[]):
106
 
                tables_to_process.remove(dest_table)
107
 
                query_from += ' %s %s ON (%s."%s" = %s."%s")' % \
108
 
                    (join, dest_table, table, lhs_col, dest_table, col)
 
140
            for (dest_table, lhs_col, col, join) in self.joins.get(table, []):
 
141
                tables_to_process.remove(alias_mapping[dest_table])
 
142
                query_from += ' %s %s ON ("%s"."%s" = "%s"."%s")' % \
 
143
                    (join, alias_mapping[dest_table], table, lhs_col, dest_table, col)
109
144
                query_from = add_joins_for_table(dest_table, query_from)
110
145
            return query_from
111
146
 
112
147
        for table in tables_to_process:
113
148
            query_from += table
114
 
            if table in self.joins:
115
 
                query_from = add_joins_for_table(table, query_from)
 
149
            table_alias = get_alias_from_query(table)[1]
 
150
            if table_alias in self.joins:
 
151
                query_from = add_joins_for_table(table_alias, query_from)
116
152
            query_from += ','
117
 
        query_from = query_from[:-1] # drop last comma
118
 
        return (query_from, " AND ".join(self.where_clause), self.where_clause_params)
 
153
        query_from = query_from[:-1]  # drop last comma
 
154
        return query_from, " AND ".join(self.where_clause), self.where_clause_params
119
155
 
120
156
    def __str__(self):
121
157
        return '<osv.Query: "SELECT ... FROM %s WHERE %s" with params: %r>' % self.get_sql()
122
158
 
123
 
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
 
 
b'\\ No newline at end of file'
 
159
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: