Skip to content

Commit e791adb

Browse files
committed
fixes #14
++move_before and leftsibling_in_level functions
1 parent b581ca2 commit e791adb

File tree

3 files changed

+215
-3
lines changed

3 files changed

+215
-3
lines changed

sqlalchemy_mptt/events.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,35 @@ def mptt_before_update(mapper, connection, instance):
149149
left_sibling_tree_id = None
150150
if hasattr(instance, 'mptt_move_inside'):
151151
mptt_move_inside = instance.mptt_move_inside
152+
if hasattr(instance, 'mptt_move_before'):
153+
(right_sibling_left,
154+
right_sibling_right,
155+
right_sibling_parent,
156+
right_sibling_level,
157+
right_sibling_tree_id) = connection.execute(
158+
select([table.c.lft, table.c.rgt, table.c.parent_id,
159+
table.c.level, table.c.tree_id]).
160+
where(table.c.id == instance.mptt_move_before)
161+
).fetchone()
162+
current_lvl_nodes = connection.execute(
163+
select([table.c.lft, table.c.rgt, table.c.parent_id,
164+
table.c.tree_id]).
165+
where(and_(table.c.level == right_sibling_level,
166+
table.c.tree_id == right_sibling_tree_id,
167+
table.c.lft < right_sibling_left))
168+
).fetchall()
169+
if current_lvl_nodes:
170+
(left_sibling_left,
171+
left_sibling_right,
172+
left_sibling_parent,
173+
left_sibling_tree_id) = current_lvl_nodes[-1]
174+
instance.parent_id = left_sibling_parent
175+
left_sibling = {'lft': left_sibling_left, 'rgt': left_sibling_right,
176+
'is_parent': False}
177+
# if move_before to top level
178+
elif not right_sibling_parent:
179+
left_sibling_tree_id = right_sibling_tree_id - 1
180+
152181
# if placed after a particular node
153182
if hasattr(instance, 'mptt_move_after'):
154183
(left_sibling_left,
@@ -234,7 +263,7 @@ def mptt_before_update(mapper, connection, instance):
234263
parent_tree_id, parent_level, node_level, left_sibling)
235264
else:
236265
# if insert after
237-
if left_sibling_tree_id:
266+
if left_sibling_tree_id or left_sibling_tree_id == 0:
238267
tree_id = left_sibling_tree_id + 1
239268
connection.execute(
240269
table.update(table.c.tree_id > left_sibling_tree_id)

sqlalchemy_mptt/mixins.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,19 @@ def move_before(self, node_id):
8585
session = Session.object_session(self)
8686
node = session.query(self.__table__).filter_by(id=node_id).one()
8787
self.parent_id = node.parent_id
88-
self.mptt_move_after = node_id
88+
self.mptt_move_before = node_id
8989
session.add(self)
9090

91+
def leftsibling_in_level(self):
92+
table = self.__table__
93+
session = Session.object_session(self)
94+
current_lvl_nodes = session.query(table)\
95+
.filter_by(level=self.level).filter_by(tree_id=self.tree_id)\
96+
.filter(table.c.lft < self.left).order_by(table.c.lft).all()
97+
if current_lvl_nodes:
98+
return current_lvl_nodes[-1]
99+
return None
100+
91101
@classmethod
92102
def get_tree(cls, session, json=False, json_fields=None):
93103
def recursive_node_to_dict(node):

sqlalchemy_mptt/tests.py

Lines changed: 174 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1191,7 +1191,7 @@ def test_move_inside_to_the_same_parent_function(self):
11911191
| |
11921192
4 14(9)15 18(11)19
11931193
1194-
level Nested sets example
1194+
level move 6 inside 4
11951195
1 1(1)22
11961196
_______________|___________________
11971197
| | |
@@ -1228,3 +1228,176 @@ def test_move_inside_to_the_same_parent_function(self):
12281228
(20, 14, 15, 4, 19, 2),
12291229
(21, 17, 20, 3, 18, 2),
12301230
(22, 18, 19, 4, 21, 2)], self.result.all())
1231+
1232+
def test_move_before_to_top_level(self):
1233+
""" level Nested sets example
1234+
1 1(1)22
1235+
_______________|___________________
1236+
| | |
1237+
2 2(2)5 6(4)11 12(7)21
1238+
| ^ ^
1239+
3 3(3)4 7(5)8 9(6)10 13(8)16 17(10)20
1240+
| |
1241+
4 14(9)15 18(11)19
1242+
1243+
level move 4 before 1
1244+
1 1(4)6 1(1)16
1245+
^ _______|_______
1246+
2(5)3 4(6)5 | |
1247+
2 2(2)5 6(7)15
1248+
| ^
1249+
3 3(3)4 7(8)10 11(10)14
1250+
| |
1251+
4 8(9)9 12(11)13
1252+
1253+
id lft rgt lvl parent tree
1254+
"""
1255+
node = self.session.query(Tree).filter(Tree.id == 4).one()
1256+
node.move_before("1")
1257+
self.maxDiff = None
1258+
self.assertEqual([(1, 1, 16, 1, None, 2),
1259+
(2, 2, 5, 2, 1, 2),
1260+
(3, 3, 4, 3, 2, 2),
1261+
1262+
(4, 1, 6, 1, None, 1),
1263+
(5, 2, 3, 2, 4, 1),
1264+
(6, 4, 5, 2, 4, 1),
1265+
1266+
(7, 6, 15, 2, 1, 2),
1267+
(8, 7, 10, 3, 7, 2),
1268+
(9, 8, 9, 4, 8, 2),
1269+
(10, 11, 14, 3, 7, 2),
1270+
(11, 12, 13, 4, 10, 2),
1271+
1272+
(12, 1, 22, 1, None, 3),
1273+
(13, 2, 5, 2, 12, 3),
1274+
(14, 3, 4, 3, 13, 3),
1275+
(15, 6, 11, 2, 12, 3),
1276+
(16, 7, 8, 3, 15, 3),
1277+
(17, 9, 10, 3, 15, 3),
1278+
(18, 12, 21, 2, 12, 3),
1279+
(19, 13, 16, 3, 18, 3),
1280+
(20, 14, 15, 4, 19, 3),
1281+
(21, 17, 20, 3, 18, 3),
1282+
(22, 18, 19, 4, 21, 3)], self.result.all())
1283+
1284+
def test_move_before(self):
1285+
""" level Nested sets example
1286+
1 1(1)22
1287+
_______________|___________________
1288+
| | |
1289+
2 2(2)5 6(4)11 12(7)21
1290+
| ^ ^
1291+
3 3(3)4 7(5)8 9(6)10 13(8)16 17(10)20
1292+
| |
1293+
4 14(9)15 18(11)19
1294+
1295+
level move 8 before 4
1296+
1 1(1)22
1297+
_______________|___________________
1298+
| | | |
1299+
2 2(2)5 6(8)9 10(4)15 16(7)21
1300+
| | ^ |
1301+
3 3(3)4 7(9)8 11(5)12 13(6)14 17(10)20
1302+
|
1303+
4 18(11)19
1304+
1305+
id lft rgt lvl parent tree
1306+
"""
1307+
node = self.session.query(Tree).filter(Tree.id == 8).one()
1308+
node.move_before("4")
1309+
self.assertEqual([(1, 1, 22, 1, None, 1),
1310+
(2, 2, 5, 2, 1, 1),
1311+
(3, 3, 4, 3, 2, 1),
1312+
(4, 10, 15, 2, 1, 1),
1313+
(5, 11, 12, 3, 4, 1),
1314+
(6, 13, 14, 3, 4, 1),
1315+
(7, 16, 21, 2, 1, 1),
1316+
(8, 6, 9, 2, 1, 1),
1317+
(9, 7, 8, 3, 8, 1),
1318+
(10, 17, 20, 3, 7, 1),
1319+
(11, 18, 19, 4, 10, 1),
1320+
1321+
(12, 1, 22, 1, None, 2),
1322+
(13, 2, 5, 2, 12, 2),
1323+
(14, 3, 4, 3, 13, 2),
1324+
(15, 6, 11, 2, 12, 2),
1325+
(16, 7, 8, 3, 15, 2),
1326+
(17, 9, 10, 3, 15, 2),
1327+
(18, 12, 21, 2, 12, 2),
1328+
(19, 13, 16, 3, 18, 2),
1329+
(20, 14, 15, 4, 19, 2),
1330+
(21, 17, 20, 3, 18, 2),
1331+
(22, 18, 19, 4, 21, 2)], self.result.all())
1332+
1333+
def test_move_before_to_other_tree(self):
1334+
""" level Move 8 before 15
1335+
1 1(1)18
1336+
_______________|___________________
1337+
| | |
1338+
2 2(2)5 6(4)11 12(7)17
1339+
| ^ |
1340+
3 3(3)4 7(5)8 9(6)10 13(10)16
1341+
|
1342+
4 14(11)15
1343+
1344+
level
1345+
1 1(12)26
1346+
_______________|______________________________
1347+
| | | |
1348+
2 2(13)5 6(8)9 10(15)15 16(18)25
1349+
| | ^ ^
1350+
3 3(14)4 7(9)8 11(16)12 13(17)14 17(19)20 21(21)24
1351+
| |
1352+
4 18(20)19 22(22)23
1353+
1354+
id lft rgt lvl parent tree
1355+
"""
1356+
node = self.session.query(Tree).filter(Tree.id == 8).one()
1357+
node.move_before("15")
1358+
self.assertEqual([(1, 1, 18, 1, None, 1),
1359+
(2, 2, 5, 2, 1, 1),
1360+
(3, 3, 4, 3, 2, 1),
1361+
(4, 6, 11, 2, 1, 1),
1362+
(5, 7, 8, 3, 4, 1),
1363+
(6, 9, 10, 3, 4, 1),
1364+
(7, 12, 17, 2, 1, 1),
1365+
1366+
(8, 6, 9, 2, 12, 2),
1367+
(9, 7, 8, 3, 8, 2),
1368+
1369+
(10, 13, 16, 3, 7, 1),
1370+
(11, 14, 15, 4, 10, 1),
1371+
1372+
(12, 1, 26, 1, None, 2),
1373+
(13, 2, 5, 2, 12, 2),
1374+
(14, 3, 4, 3, 13, 2),
1375+
(15, 10, 15, 2, 12, 2),
1376+
(16, 11, 12, 3, 15, 2),
1377+
(17, 13, 14, 3, 15, 2),
1378+
(18, 16, 25, 2, 12, 2),
1379+
(19, 17, 20, 3, 18, 2),
1380+
(20, 18, 19, 4, 19, 2),
1381+
(21, 21, 24, 3, 18, 2),
1382+
(22, 22, 23, 4, 21, 2)], self.result.all())
1383+
1384+
def test_leftsibling_in_level(self):
1385+
""" level Nested sets example
1386+
1 1(1)22
1387+
_______________|___________________
1388+
| | |
1389+
2 2(2)5 6(4)11 12(7)21
1390+
| ^ ^
1391+
3 3(3)4 7(5)8 9(6)10 13(8)16 17(10)20
1392+
| |
1393+
4 14(9)15 18(11)19
1394+
"""
1395+
node3 = self.session.query(Tree).filter(Tree.id == 3).one()
1396+
node5 = self.session.query(Tree).filter(Tree.id == 5).one()
1397+
node6 = self.session.query(Tree).filter(Tree.id == 6).one()
1398+
node8 = self.session.query(Tree).filter(Tree.id == 8).one()
1399+
node10 = self.session.query(Tree).filter(Tree.id == 10).one()
1400+
self.assertEqual(node10.leftsibling_in_level().id, node8.id)
1401+
self.assertEqual(node8.leftsibling_in_level().id, node6.id)
1402+
self.assertEqual(node6.leftsibling_in_level().id, node5.id)
1403+
self.assertEqual(node3.leftsibling_in_level(), None)

0 commit comments

Comments
 (0)