Merge lp:~cedric-lebrouster/openobject-server/7.0-bug-1253052-parent-order into lp:openobject-server/7.0

Proposed by Cedric Le Brouster(OpenFire)
Status: Needs review
Proposed branch: lp:~cedric-lebrouster/openobject-server/7.0-bug-1253052-parent-order
Merge into: lp:openobject-server/7.0
Diff against target: 138 lines (+59/-36)
2 files modified
openerp/addons/base/test/base_test.yml (+13/-1)
openerp/osv/orm.py (+46/-35)
To merge this branch: bzr merge lp:~cedric-lebrouster/openobject-server/7.0-bug-1253052-parent-order
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+209670@code.launchpad.net

Description of the change

Fixes parent_left and parent_right recomputation in write/create methods ( bug lp:1253052 )

To post a comment you must log in.
5190. By Cedric Le Brouster(OpenFire)

Add tests for _parent_order

5191. By Cedric Le Brouster(OpenFire)

[FIX] orm: fix miscalculation of _parent_left and _parent_right in create() method for some special case.
(i.e. when new object parent's _parent_left value is 0)

Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

Unmerged revisions

5191. By Cedric Le Brouster(OpenFire)

[FIX] orm: fix miscalculation of _parent_left and _parent_right in create() method for some special case.
(i.e. when new object parent's _parent_left value is 0)

5190. By Cedric Le Brouster(OpenFire)

Add tests for _parent_order

5189. By Cedric Le Brouster(OpenFire)

[FIX] orm: wrong parent_left and parent_right recomputation in write/create methods (see bug 1253052)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openerp/addons/base/test/base_test.yml'
2--- openerp/addons/base/test/base_test.yml 2014-04-16 11:22:39 +0000
3+++ openerp/addons/base/test/base_test.yml 2014-06-13 10:05:21 +0000
4@@ -137,7 +137,19 @@
5 assert len(old_struct) == 4, "After duplication, previous record must have old childs records only"
6 assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed"
7 -
8- 6. Restore pool state after the test
9+ 6. Tests on _parent_order.
10+-
11+ !python {model: res.partner.category }: |
12+ another_root = self.create(cr, uid, {'name':'Root categ'})
13+ struct = self.search(cr, uid, [('id','in',(ref('test_categ_root'),another_root))])
14+ assert struct[0]==another_root, "Root partner categories should be sorted."
15+ struct = self.search(cr, uid, [('id','in',(ref('test_categ_1'),ref('test_categ_2')))])
16+ assert struct[0]==ref('test_categ_1'), "Partner categories should be sorted."
17+ self.write(cr, uid, ref('test_categ_1'), {'name':'Child 3'})
18+ struct = self.search(cr, uid, [('id','in',(ref('test_categ_1'),ref('test_categ_2')))])
19+ assert struct[0]==ref('test_categ_2'), "Partner categories should be re-sorted after name update."
20+-
21+ 7. Restore pool state after the test
22 -
23 !python {model: res.partner.category}: |
24 self.pool._init = True
25
26=== modified file 'openerp/osv/orm.py'
27--- openerp/osv/orm.py 2014-05-19 16:12:41 +0000
28+++ openerp/osv/orm.py 2014-06-13 10:05:21 +0000
29@@ -4176,22 +4176,31 @@
30
31 parents_changed = []
32 parent_order = self._parent_order or self._order
33- if self._parent_store and (self._parent_name in vals):
34+ if self._parent_store:
35 # The parent_left/right computation may take up to
36 # 5 seconds. No need to recompute the values if the
37- # parent is the same.
38+ # parent and order field are the same.
39 # Note: to respect parent_order, nodes must be processed in
40 # order, so ``parents_changed`` must be ordered properly.
41- parent_val = vals[self._parent_name]
42- if parent_val:
43- query = "SELECT id FROM %s WHERE id IN %%s AND (%s != %%s OR %s IS NULL) ORDER BY %s" % \
44- (self._table, self._parent_name, self._parent_name, parent_order)
45- cr.execute(query, (tuple(ids), parent_val))
46- else:
47- query = "SELECT id FROM %s WHERE id IN %%s AND (%s IS NOT NULL) ORDER BY %s" % \
48- (self._table, self._parent_name, parent_order)
49- cr.execute(query, (tuple(ids),))
50- parents_changed = map(operator.itemgetter(0), cr.fetchall())
51+ query = "SELECT id FROM %s WHERE id IN %%s" % (self._table,)
52+ query_params = [tuple(ids)]
53+ query_clause = ""
54+ parent_params = [self._parent_name]
55+ for param in parent_order.split(','):
56+ parent_params.append(param.strip())
57+ for parent_param in parent_params:
58+ if parent_param in vals:
59+ parents_changed = True
60+ parent_val = vals[parent_param]
61+ if parent_val:
62+ query_clause += (query_clause and ' OR ' or '') + "%s != %%s OR %s IS NULL" % (parent_param,parent_param)
63+ query_params.append(parent_val)
64+ else:
65+ query_clause += (query_clause and ' OR ' or '') + "%s IS NOT NULL" % (parent_param,)
66+ if parents_changed:
67+ query += (query_clause and (' AND (' + query_clause + ')') or '') + " ORDER BY %s" % (self._parent_order,)
68+ cr.execute(query, tuple(query_params))
69+ parents_changed = map(operator.itemgetter(0), cr.fetchall())
70
71 upd0 = []
72 upd1 = []
73@@ -4289,18 +4298,16 @@
74 if self.pool._init:
75 self.pool._init_parent[self._name] = True
76 else:
77- order = self._parent_order or self._order
78- parent_val = vals[self._parent_name]
79- if parent_val:
80- clause, params = '%s=%%s' % (self._parent_name,), (parent_val,)
81- else:
82- clause, params = '%s IS NULL' % (self._parent_name,), ()
83-
84 for id in parents_changed:
85- cr.execute('SELECT parent_left, parent_right FROM %s WHERE id=%%s' % (self._table,), (id,))
86- pleft, pright = cr.fetchone()
87+ cr.execute('SELECT parent_left, parent_right, %s FROM %s WHERE id=%%s' % (self._parent_name, self._table,), (id,))
88+ pleft, pright, parent_val = cr.fetchone()
89 distance = pright - pleft + 1
90
91+ if parent_val:
92+ clause, params = '%s=%%s' % (self._parent_name,), (parent_val,)
93+ else:
94+ clause, params = '%s IS NULL' % (self._parent_name,), ()
95+
96 # Positions of current siblings, to locate proper insertion point;
97 # this can _not_ be fetched outside the loop, as it needs to be refreshed
98 # after each update, in case several nodes are sequentially inserted one
99@@ -4520,21 +4527,25 @@
100 self.pool._init_parent[self._name] = True
101 else:
102 parent = vals.get(self._parent_name, False)
103+ where_clause = ' where '+self._parent_name
104 if parent:
105- cr.execute('select parent_right from '+self._table+' where '+self._parent_name+'=%s order by '+(self._parent_order or self._order), (parent,))
106- pleft_old = None
107- result_p = cr.fetchall()
108- for (pleft,) in result_p:
109- if not pleft:
110- break
111- pleft_old = pleft
112- if not pleft_old:
113- cr.execute('select parent_left from '+self._table+' where id=%s', (parent,))
114- pleft_old = cr.fetchone()[0]
115- pleft = pleft_old
116- else:
117- cr.execute('select max(parent_right) from '+self._table)
118- pleft = cr.fetchone()[0] or 0
119+ where_clause += '=%s'
120+ where_params = (parent,)
121+ else:
122+ where_clause += ' is null'
123+ where_params = tuple()
124+ cr.execute('select parent_right from '+self._table + where_clause+' order by '+(self._parent_order or self._order), where_params)
125+ pleft_old = None
126+ result_p = cr.fetchall()
127+ for (pleft,) in result_p:
128+ if not pleft:
129+ break
130+ pleft_old = pleft
131+ if not pleft_old and parent:
132+ cr.execute('select parent_left from '+self._table+' where id=%s', (parent,))
133+ pleft = cr.fetchone()[0]
134+ else:
135+ pleft = pleft_old or -1
136 cr.execute('update '+self._table+' set parent_left=parent_left+2 where parent_left>%s', (pleft,))
137 cr.execute('update '+self._table+' set parent_right=parent_right+2 where parent_right>%s', (pleft,))
138 cr.execute('update '+self._table+' set parent_left=%s,parent_right=%s where id=%s', (pleft+1, pleft+2, id_new))