2
2
#this repository contains the full copyright notices and license terms.
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
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
12
16
class Property(Function):
61
65
Property.set(name, model.__name__, ids, prop_value)
63
def search(self, model, name, clause):
65
:param model: The model.
66
:param clause: The search domain clause. See ModelStorage.search
67
:return: New list of domain.
67
def convert_domain(self, domain, tables, Model):
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
76
field_class = backend.FIELDS[self._type]
79
sql_type = field_class.sql_type(model._fields[name])
82
sql_type = sql_type[0]
84
property_query, property_val = Rule.domain_get('ir.property')
88
property_clause = 'AND ' + property_query
75
name, operator, value = domain
77
sql_type = self._field.sql_type().base
79
property_cond = Rule.domain_get('ir.property')
81
property_ = Property.__table__()
82
model_field = Field.__table__()
83
model = IrModel.__table__()
90
85
#Fetch res ids that comply with the domain
93
'SUBSTR("' + Property._table + '".res, '
94
'POSITION(\',\' IN "' + Property._table + '".res) + 1) '
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) '
106
Model._table + '".model = %s '
107
'AND "' + Field._table + '".name = %s '
110
self.get_condition(sql_type, clause) +
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))
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),
99
where=Case((cond, self.get_condition(sql_type, domain,
117
103
props = cursor.fetchall()
121
107
default = prop[1]
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)
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)
133
118
'not like', 'not ilike', '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])]
137
122
#Fetch the res ids that doesn't use the default value
139
"SELECT CAST(SUBSTR(res, POSITION(',' IN res) + 1) AS integer) "
140
'FROM "' + Property._table + '"'
141
'WHERE ' + property_query + ' AND res is not null',
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)))
144
129
fetchall = cursor.fetchall()
156
141
return [('id', 'in', res_ids)]
159
def get_condition(sql_type, clause):
161
if sql_type == 'NUMERIC':
162
operator = 'CAST(%s AS NUMERIC)'
164
value = "SUBSTR(value, POSITION(',' IN value) + 1)"
144
def get_condition(sql_type, clause, table):
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]
153
value = Cast(value, sql_type)
158
column = Cast(Substring(table.value,
159
Position(',', table.value) + Literal(1)),
161
Operator = SQL_OPERATORS[operator]
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)
179
return "(CAST(" + value + " AS %s) %s %s) " % \
180
(sql_type, clause[1], operator)
183
def get_condition_args(clause):
185
if clause[1] in ('in', 'not in'):
186
res.extend(clause[2])
187
elif clause[2] is None:
190
res.append(clause[2])
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)