~crass/tryton/server

« back to all changes in this revision

Viewing changes to trytond/model/fields/property.py

  • Committer: Mathias Behrle
  • Date: 2013-11-24 16:28:54 UTC
  • Revision ID: git-v1:182d6cce169eab1682eeacbad4323efa1136a1a0
MergingĀ upstreamĀ versionĀ 3.0.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
#this repository contains the full copyright notices and license terms.
3
3
 
4
4
import copy
5
 
from trytond.model.fields.function import Function
6
 
from trytond.model.fields.field import Field
7
 
from trytond import backend
8
 
from trytond.transaction import Transaction
9
 
from trytond.pool import Pool
 
5
from sql import Cast, Literal
 
6
from sql.functions import Substring, Position
 
7
from sql.conditionals import Case
 
8
 
 
9
from .function import Function
 
10
from .field import Field, SQL_OPERATORS
 
11
from .numeric import Numeric
 
12
from ...transaction import Transaction
 
13
from ...pool import Pool
10
14
 
11
15
 
12
16
class Property(Function):
60
64
            prop_value = None
61
65
        Property.set(name, model.__name__, ids, prop_value)
62
66
 
63
 
    def search(self, model, name, clause):
64
 
        '''
65
 
        :param model: The model.
66
 
        :param clause: The search domain clause. See ModelStorage.search
67
 
        :return: New list of domain.
68
 
        '''
 
67
    def convert_domain(self, domain, tables, Model):
69
68
        pool = Pool()
70
69
        Rule = pool.get('ir.rule')
71
70
        Property = pool.get('ir.property')
72
 
        Model = pool.get('ir.model')
 
71
        IrModel = pool.get('ir.model')
73
72
        Field = pool.get('ir.model.field')
74
73
        cursor = Transaction().cursor
75
74
 
76
 
        field_class = backend.FIELDS[self._type]
77
 
        if not field_class:
78
 
            return []
79
 
        sql_type = field_class.sql_type(model._fields[name])
80
 
        if not sql_type:
81
 
            return []
82
 
        sql_type = sql_type[0]
83
 
 
84
 
        property_query, property_val = Rule.domain_get('ir.property')
85
 
 
86
 
        property_clause = ''
87
 
        if property_query:
88
 
            property_clause = 'AND ' + property_query
 
75
        name, operator, value = domain
 
76
 
 
77
        sql_type = self._field.sql_type().base
 
78
 
 
79
        property_cond = Rule.domain_get('ir.property')
 
80
 
 
81
        property_ = Property.__table__()
 
82
        model_field = Field.__table__()
 
83
        model = IrModel.__table__()
89
84
 
90
85
        #Fetch res ids that comply with the domain
91
 
        cursor.execute(
92
 
            'SELECT CAST('
93
 
                'SUBSTR("' + Property._table + '".res, '
94
 
                    'POSITION(\',\' IN "' + Property._table + '".res) + 1) '
95
 
                    'AS INTEGER), '
96
 
                '"' + Property._table + '".id '
97
 
            'FROM "' + Property._table + '" '
98
 
                'JOIN "' + Field._table + '" ON '
99
 
                    '("' + Field._table + '"' +
100
 
                        '.id = "' + Property._table + '".field) '
101
 
                'JOIN "' + Model._table + '" ON '
102
 
                    '("' + Model._table +
103
 
                        '".id = "' + Field._table + '".model) '
104
 
            'WHERE '
105
 
                'CASE WHEN "' +
106
 
                    Model._table + '".model = %s '
107
 
                    'AND "' + Field._table + '".name = %s '
108
 
                    + property_clause +
109
 
                ' THEN ' +
110
 
                    self.get_condition(sql_type, clause) +
111
 
                ' ELSE '
112
 
                    '%s '
113
 
                'END',
114
 
            [model.__name__, name] + property_val +
115
 
            self.get_condition_args(clause) + [False])
 
86
        join = property_.join(model_field,
 
87
            condition=model_field.id == property_.field)
 
88
        join = join.join(model,
 
89
            condition=model.id == model_field.model)
 
90
        cond = ((model.model == Model.__name__)
 
91
            & (model_field.name == name))
 
92
        if property_cond:
 
93
            cond &= property_.id.in_(property_cond)
 
94
        cursor.execute(*join.select(
 
95
                Cast(Substring(property_.res,
 
96
                        Position(',', property_.res) + Literal(1)),
 
97
                    Model.id.sql_type().base),
 
98
                property_.id,
 
99
                where=Case((cond, self.get_condition(sql_type, domain,
 
100
                            property_)),
 
101
                    else_=False)))
116
102
 
117
103
        props = cursor.fetchall()
118
104
        default = None
121
107
                default = prop[1]
122
108
                break
123
109
 
124
 
        if not default \
125
 
                or ((clause[2] is False or clause[2] is None)
126
 
                    and clause[1] in ['=', '!=']) \
127
 
                or (clause[1] in ['not like', 'not ilike', 'not in', '!=']):
128
 
            operator = 'in'  # default operator
129
 
            if (((clause[2] is False or clause[2] is None)
130
 
                        and clause[1] == '=')
131
 
                    or ((clause[2] is not False and clause[2] is not None)
132
 
                        and clause[1] in [
 
110
        if (not default
 
111
                or ((value is False or value is None)
 
112
                    and operator in ['=', '!='])
 
113
                or (operator in ['not like', 'not ilike', 'not in', '!='])):
 
114
            dom_operator = 'in'  # default operator
 
115
            if (((value is False or value is None) and operator == '=')
 
116
                    or ((value is not False and value is not None)
 
117
                        and operator in [
133
118
                            'not like', 'not ilike', 'not in', '!='])):
134
 
                operator = 'not in'
135
 
            return [('id', operator, [x[0] for x in props])]
 
119
                dom_operator = 'not in'
 
120
            return [('id', dom_operator, [x[0] for x in props])]
136
121
 
137
122
        #Fetch the res ids that doesn't use the default value
138
 
        cursor.execute(
139
 
            "SELECT CAST(SUBSTR(res, POSITION(',' IN res) + 1) AS integer) "
140
 
            'FROM "' + Property._table + '"'
141
 
            'WHERE ' + property_query + ' AND res is not null',
142
 
            property_val)
 
123
        cursor.execute(*property_.select(
 
124
                Cast(Substring(property_.res,
 
125
                        Position(',', property_.res) + Literal(1)),
 
126
                    Model.id.sql_type().base),
 
127
                where=property_cond & (property_.res != None)))
143
128
 
144
129
        fetchall = cursor.fetchall()
145
130
        if not fetchall:
148
133
        else:
149
134
            other_ids = [x[0] for x in cursor.fetchall()]
150
135
 
151
 
            res_ids = model.search(['OR',
 
136
            res_ids = Model.search(['OR',
152
137
                ('id', 'in', [x[0] for x in props]),
153
138
                ('id', 'not in', other_ids)
154
139
                ])
156
141
            return [('id', 'in', res_ids)]
157
142
 
158
143
    @staticmethod
159
 
    def get_condition(sql_type, clause):
160
 
        operator = '%s'
161
 
        if sql_type == 'NUMERIC':
162
 
            operator = 'CAST(%s AS NUMERIC)'
163
 
 
164
 
        value = "SUBSTR(value, POSITION(',' IN value) + 1)"
 
144
    def get_condition(sql_type, clause, table):
 
145
        operator = clause[1]
 
146
        value = clause[2]
 
147
 
 
148
        numeric = Numeric('numeric')
 
149
        if sql_type == numeric.sql_type().base and value:
 
150
            if isinstance(value, (list, tuple)):
 
151
                value = [Cast(v, sql_type) for v in value]
 
152
            else:
 
153
                value = Cast(value, sql_type)
 
154
 
 
155
        if value is None:
 
156
            value = False
 
157
 
 
158
        column = Cast(Substring(table.value,
 
159
                Position(',', table.value) + Literal(1)),
 
160
            sql_type)
 
161
        Operator = SQL_OPERATORS[operator]
 
162
 
165
163
        # All negative clauses will be negated later
166
 
        if clause[1] in ('in', 'not in'):
167
 
            operator = operator % '%%s'
168
 
            return ("(CAST(" + value + " AS %s) IN ("
169
 
                + ",".join((operator,) * len(clause[2])) + ")) ") % sql_type
170
 
        elif ((clause[2] is False or clause[2] is None)
171
 
                and clause[1] in ['=', '!=']):
172
 
            return "((CAST(" + value + " AS %s) IS NULL) = %%s) " % sql_type
173
 
        elif clause[1] in ['not like', 'not ilike']:
174
 
            return "(CAST(" + value + " AS %s) %s %s) " % \
175
 
                (sql_type, clause[1].split()[1], operator)
176
 
        elif clause[1] == '!=':
177
 
            return "(CAST(" + value + " AS %s) = %s) " % (sql_type, operator)
178
 
        else:
179
 
            return "(CAST(" + value + " AS %s) %s %s) " % \
180
 
                (sql_type, clause[1], operator)
181
 
 
182
 
    @staticmethod
183
 
    def get_condition_args(clause):
184
 
        res = []
185
 
        if clause[1] in ('in', 'not in'):
186
 
            res.extend(clause[2])
187
 
        elif clause[2] is None:
188
 
            res.append(False)
189
 
        else:
190
 
            res.append(clause[2])
191
 
        return res
 
164
        if operator in ('in', 'not in'):
 
165
            return column.in_(value)
 
166
        elif ((value is False or value is None)
 
167
                and operator in ('=', '!=')):
 
168
            return (column == None) == value
 
169
        elif operator == 'not like':
 
170
            return column.like(value)
 
171
        elif operator == 'not ilike':
 
172
            return column.ilike(value)
 
173
        elif operator == '!=':
 
174
            return column == value
 
175
        return Operator(column, value)