e1ad15011d2d8d5e54123eee0410a4d57eecbfbd
[zzz-floof.git] / floof / model / comments.py
1 import datetime
2
3 from elixir import *
4 from sqlalchemy import func
5
6 class Discussion(Entity):
7 """Represents a collection of comments attached to some other object."""
8 count = Field(Integer)
9 comments = OneToMany('Comment', order_by='left')
10
11 class Comment(Entity):
12 time = Field(DateTime, default=datetime.datetime.now)
13 text = Field(Unicode(65536))
14
15 # Comments are a tree, and are stored as a nested set, because:
16 # - It's easy to get a subtree with a single query.
17 # - It's easy to get a comment's depth.
18 # - It's easy to sort comments without recursion.
19 # The only real disadvantage is that adding a comment requires a quick
20 # update of all the following comments (in post-order), but that's rare
21 # enough that it shouldn't be a problem.
22 left = Field(Integer, index=True)
23 right = Field(Integer)
24
25 discussion = ManyToOne('Discussion')
26 user = ManyToOne('User')
27
28 def __init__(self, parent=None, **kwargs):
29 """Constructor override to set left/right correctly on a new comment.
30 """
31 super(Comment, self).__init__(**kwargs)
32
33 # Keep the comment count updated
34 self.discussion.count += 1
35
36 if parent:
37 # Parent comment given. Add this comment just before the parent's
38 # right side...
39 self.left = parent.right
40 self.right = parent.right + 1
41
42 # ...then adjust all rightward comments accordingly
43 Comment.query.filter(Comment.discussion == self.discussion) \
44 .filter(Comment.right > parent.right) \
45 .update({ Comment.left: Comment.left + 2,
46 Comment.right: Comment.right + 2 })
47
48 # And, finally, update the parent's right endpoint
49 parent.right += 2
50
51 else:
52 query = session.query(func.max(Comment.right)) \
53 .filter(Comment.discussion == self.discussion)
54 (max_right,) = query.one()
55
56 if not max_right:
57 # No comments yet. Use 1 and 2
58 self.left = 1
59 self.right = 2
60 else:
61 self.left = max_right + 1
62 self.right = max_right + 2