Improve where clause for issue232

It allows to have now this kind of query:
['OR', ('a', '=', 'b'), ('c', 'in', ['d', 'e']), ['AND', ('f', 'like, 'test'), ('g', '>', 'h')]]
This commit is contained in:
Cédric Krier committed 2008-08-09 11:51:21 +02:00
1 parent 3cddb6989b
commit 0dab027b97
2 files changed
+90 -71

No files matched your search

+12 -42
View File
@@ -160,39 +160,11 @@ class Rule(OSV):
user), 'time': time})
if rule.rule_group['global_p']:
clause_global.setdefault(rule.rule_group.id, [])
clause_global[rule.rule_group.id].append(
obj._where_calc(cursor, user, dom, active_test=False))
clause_global.setdefault(rule.rule_group.id, ['OR'])
clause_global[rule.rule_group.id].append(dom)
else:
clause.setdefault(rule.rule_group.id, [])
clause[rule.rule_group.id].append(
obj._where_calc(cursor, user, dom, active_test=False))
def _query(clauses, test):
query = ''
val = []
for groups in clauses.values():
if not groups:
continue
if len(query):
query += ' '+test+' '
query += '('
first = True
for group in groups:
if not first:
query += ' OR '
first = False
query += '('
first2 = True
for clause in group[0]:
if not first2:
query += ' AND '
first2 = False
query += clause
query += ')'
val += group[1]
query += ')'
return query, val
clause.setdefault(rule.rule_group.id, ['OR'])
clause[rule.rule_group.id].append(dom)
query = ''
val = []
@@ -211,17 +183,15 @@ class Rule(OSV):
WHERE u_rel.uid = %s))""", (model_name, user, user))
if cursor.rowcount:
group_id = cursor.fetchone()[0]
clause[group_id] = [(['(True)'], '', '', '')]
query, val = _query(clause, 'OR')
clause[group_id] = []
clause = clause.values()
clause.insert(0, 'OR')
query_global, val_global = _query(clause_global, 'AND')
if query_global:
if query:
query = '('+query+') AND '+query_global
val.extend(val_global)
else:
query = query_global
val = val_global
clause_global = clause_global.values()
clause_global.insert(0, 'AND')
query, val, _, _ = obj._where_calc(cursor, user,
['AND', clause_global, clause], active_test=False)
return query, val
+78 -29
View File
@@ -1999,14 +1999,61 @@ class ORM(object):
if not active_found:
args.append(('active', '=', 1))
i = 0
table_query = ''
table_args = []
if self.table_query(context):
table_query, table_args = self.table_query(context)
table_query = '(' + table_query + ') AS '
tables = [table_query + '"' + self._table + '"']
tables_args = table_args
qu1, qu2 = self.__where_calc_oper(cursor, user, args, tables,
tables_args, context=context)
return qu1, qu2, tables, tables_args
def __where_calc_oper(self, cursor, user, args, tables, tables_args,
context=None):
operator = 'AND'
if len(args) and isinstance(args[0], basestring):
if args[0] not in ('AND', 'OR'):
raise Exception('ValidateError', 'Operator "%s" not supported' \
% args[0])
operator = args[0]
args = args[1:]
tuple_args = []
list_args = []
for arg in args:
if isinstance(arg, list):
list_args.append(arg)
elif isinstance(arg, tuple):
tuple_args.append(arg)
qu1, qu2 = self.__where_calc(cursor, user,
tuple_args, tables, tables_args, context=context)
if len(qu1):
qu1 = (' ' + operator + ' ').join(qu1)
else:
qu1 = ''
for args2 in list_args:
qu1b, qu2b = self.__where_calc_oper(cursor,
user, args2, tables, tables_args, context=context)
if qu1 and qu1b:
qu1 += ' ' + operator + ' ' + qu1b
elif qu1b:
qu1 = qu1b
qu2 += qu2b
if qu1:
qu1 = '(' + qu1 + ')'
return qu1, qu2
def __where_calc(self, cursor, user, args, tables, tables_args,
context=None):
if context is None:
context = {}
i = 0
joins = []
while i < len(args):
if args[i][1] not in (
@@ -2348,7 +2395,7 @@ class ORM(object):
if add_null:
qu1[-1] = '('+qu1[-1]+' or '+arg[0]+' is null)'
return (qu1, qu2, tables, tables_args)
return qu1, qu2
def search_count(self, cursor, user, args, context=None):
'''
@@ -2458,21 +2505,26 @@ class ORM(object):
context=None, count=False, query_string=False):
'''
Return a list of id that match the clause defined in args.
args is a list of tuple that are construct like this:
('field name', 'operator', value)
field name: is the name of a field of the object
or a relational field by using '.' as separator.
operator can be:
child_of (all the child of a relation field)
=
like
ilike (case insensitive)
!=
in
<=
>=
<
>
args is a list of tuples or lists
lists are construct like this:
['operator', args, args, ...]
operator can be 'AND' or 'OR', if it is missing the
default value will be 'AND'
tuples are construct like this:
('field name', 'operator', value)
field name: is the name of a field of the object
or a relational field by using '.' as separator.
operator can be:
child_of (all the childs of a relation field)
=
like
ilike (case insensitive)
!=
in
<=
>=
<
>
offset can be used to specify a offset in the result
limit can be used to limit the number of ids return
order is a list of tupe that are construct like this:
@@ -2482,15 +2534,9 @@ class ORM(object):
if query_string is True, the function will return a tuple with
the SQL query string and the arguments.
'''
# compute the where, order by, limit and offset clauses
(qu1, qu2, tables, tables_args) = self._where_calc(cursor, user, args,
context=context)
if len(qu1):
qu1 = ' WHERE ' + ' AND '.join(qu1)
else:
qu1 = ''
order_by = []
for field, otype in (order or self._order):
if otype.upper() not in ('DESC', 'ASC'):
@@ -2505,7 +2551,7 @@ class ORM(object):
if qu1:
qu1 += ' AND ' + clause
else:
qu1 += 'WHERE ' + clause
qu1 = clause
order_by = ','.join(order_by)
@@ -2519,19 +2565,22 @@ class ORM(object):
domain1, domain2 = self.pool.get('ir.rule').domain_get(cursor, user,
self._name)
if domain1:
qu1 = qu1 and qu1 + ' AND ' + domain1 or ' WHERE ' + domain1
if qu1:
qu1 += ' AND ' + domain1
else:
qu1 = domain1
qu2 += domain2
if count:
cursor.execute('SELECT COUNT(%s.id) FROM ' % self._table +
','.join(tables) + qu1 + limit_str + offset_str,
tables_args + qu2)
','.join(tables) + ' WHERE ' + (qu1 or 'True') +
limit_str + offset_str, tables_args + qu2)
res = cursor.fetchall()
return res[0][0]
# execute the "main" query to fetch the ids we were searching for
query_str = 'SELECT %s.id FROM ' % self._table + \
','.join(tables) + qu1 + ' order by ' + order_by + \
limit_str + offset_str
','.join(tables) + ' WHERE ' + (qu1 or 'True') + \
' ORDER BY ' + order_by + limit_str + offset_str
if query_string:
return (query_str, tables_args + qu2)
cursor.execute(query_str, tables_args + qu2)