summaryrefslogtreecommitdiff
path: root/odoo/osv
diff options
context:
space:
mode:
authorRaphael Collet <rco@odoo.com>2018-01-25 15:08:16 +0100
committerRaphael Collet <rco@odoo.com>2018-02-28 10:33:44 +0100
commite724858d508a2a7a938455a49f7dc509f6eac4c6 (patch)
tree612611d67a4d44991b3757ad1dcd94d872c7de9b /odoo/osv
parent80f1ac3599ee630e7556ff4fcf3eb192931eccd8 (diff)
[REF] models: use `parent_path` to implement parent_store
This replaces the former modified preorder tree traversal (MPTT) with the fields `parent_left`/`parent_right`. Each record is associated to a string `parent_path`, that represents the path from its root node to itself. The path is made of the node ids suffixed with a slash: a node | id | parent_path / \ a | 42 | 42/ ... b b | 63 | 42/63/ / \ c | 84 | 42/63/84/ c d d | 85 | 42/63/85/ This field provides an efficient implementation for parent_of/child_of queries: the nodes in the subtree of record are the ones where `parent_path` starts with the `parent_path` of record. It is also more efficient to maintain than the MPTT fields, and less sensitive to concurrent updates, because the value of `parent_path` does not depend on sibling nodes.
Diffstat (limited to 'odoo/osv')
-rw-r--r--odoo/osv/expression.py29
1 files changed, 13 insertions, 16 deletions
diff --git a/odoo/osv/expression.py b/odoo/osv/expression.py
index d9719740edb..9e2bb7228e2 100644
--- a/odoo/osv/expression.py
+++ b/odoo/osv/expression.py
@@ -737,18 +737,15 @@ class expression(object):
def child_of_domain(left, ids, left_model, parent=None, prefix=''):
""" Return a domain implementing the child_of operator for [(left,child_of,ids)],
- either as a range using the parent_left/right tree lookup fields
+ either as a range using the parent_path tree lookup field
(when available), or as an expanded [(left,in,child_ids)] """
if not ids:
return FALSE_DOMAIN
if left_model._parent_store:
- # TODO: Improve where joins are implemented for many with '.', replace by:
- # doms += ['&',(prefix+'.parent_left','<',rec.parent_right),(prefix+'.parent_left','>=',rec.parent_left)]
- doms = []
- for rec in left_model.browse(ids):
- if doms:
- doms.insert(0, OR_OPERATOR)
- doms += [AND_OPERATOR, ('parent_left', '<', rec.parent_right), ('parent_left', '>=', rec.parent_left)]
+ doms = OR([
+ [('parent_path', '=like', rec.parent_path + '%')]
+ for rec in left_model.browse(ids)
+ ])
if prefix:
return [(left, 'in', left_model.search(doms).ids)]
return doms
@@ -762,17 +759,17 @@ class expression(object):
def parent_of_domain(left, ids, left_model, parent=None, prefix=''):
""" Return a domain implementing the parent_of operator for [(left,parent_of,ids)],
- either as a range using the parent_left/right tree lookup fields
+ either as a range using the parent_path tree lookup field
(when available), or as an expanded [(left,in,parent_ids)] """
if left_model._parent_store:
- doms = []
- for rec in left_model.browse(ids):
- if doms:
- doms.insert(0, OR_OPERATOR)
- doms += [AND_OPERATOR, ('parent_right', '>', rec.parent_left), ('parent_left', '<=', rec.parent_left)]
+ parent_ids = [
+ int(label)
+ for rec in left_model.browse(ids)
+ for label in rec.parent_path.split('/')[:-1]
+ ]
if prefix:
- return [(left, 'in', left_model.search(doms).ids)]
- return doms
+ return [(left, 'in', parent_ids)]
+ return [('id', 'in', parent_ids)]
else:
parent_name = parent or left_model._parent_name
parent_ids = set()