cob: Move comment reactions to comment

To simplify the code, we move comment reactions to the comment struct
itself.
This commit is contained in:
Alexis Sellier 2023-06-26 23:56:44 +02:00
parent 8b010c27a2
commit e4ab523669
No known key found for this signature in database
3 changed files with 25 additions and 34 deletions

View File

@ -11,7 +11,7 @@ use radicle::cob::patch::Merge;
use radicle::cob::patch::Review;
use radicle::cob::patch::{Patch, PatchId};
use radicle::cob::thread;
use radicle::cob::thread::{CommentId, Thread};
use radicle::cob::thread::CommentId;
use radicle::cob::{ActorId, Author, Reaction, Timestamp};
use radicle::git::RefString;
use radicle::node::AliasStore;
@ -105,7 +105,7 @@ pub(crate) fn issue(id: IssueId, issue: Issue, aliases: &impl AliasStore) -> Val
"assignees": issue.assigned().collect::<Vec<_>>(),
"discussion": issue
.comments()
.map(|(id, comment)| Comment::new(id, comment, issue.thread(), aliases))
.map(|(id, comment)| Comment::new(id, comment, aliases))
.collect::<Vec<_>>(),
"tags": issue.tags().collect::<Vec<_>>(),
})
@ -136,7 +136,7 @@ pub(crate) fn patch(
"oid": rev.head(),
"refs": get_refs(repo, patch.author().id(), &rev.head()).unwrap_or(vec![]),
"discussions": rev.discussion().comments()
.map(|(id, comment)| Comment::new(id, comment, rev.discussion(), aliases))
.map(|(id, comment)| Comment::new(id, comment, aliases))
.collect::<Vec<_>>(),
"timestamp": rev.timestamp(),
"reviews": rev.reviews().map(|(nid, _review)| review(nid, aliases.alias(nid), _review)).collect::<Vec<_>>(),
@ -245,18 +245,13 @@ struct Comment<'a> {
}
impl<'a> Comment<'a> {
fn new(
id: &'a CommentId,
comment: &'a thread::Comment,
thread: &'a Thread,
aliases: &impl AliasStore,
) -> Self {
fn new(id: &'a CommentId, comment: &'a thread::Comment, aliases: &impl AliasStore) -> Self {
let comment_author = Author::new(comment.author());
Self {
id: *id,
author: author(&comment_author, aliases.alias(comment_author.id())),
body: comment.body(),
reactions: thread.reactions(id).collect::<Vec<_>>(),
reactions: comment.reactions().collect::<Vec<_>>(),
timestamp: comment.timestamp(),
reply_to: comment.reply_to(),
}

View File

@ -836,7 +836,7 @@ mod test {
let id = issue.id;
let issue = issues.get(&id).unwrap().unwrap();
let (_, r) = issue.reactions(&comment).next().unwrap();
let (_, r) = issue.comment(&comment).unwrap().reactions().next().unwrap();
assert_eq!(r, &reaction);

View File

@ -61,6 +61,8 @@ pub struct Comment {
author: ActorId,
/// The comment body.
edits: GMap<Lamport, Max<Edit>>,
/// Reactions to this comment.
reactions: LWWSet<(ActorId, Reaction)>,
/// Comment this is a reply to.
/// Should always be set, except for the root comment.
reply_to: Option<CommentId>,
@ -78,6 +80,7 @@ impl Comment {
Self {
author,
reactions: LWWSet::default(),
edits: GMap::singleton(Lamport::initial(), Max::from(edit)),
reply_to,
}
@ -124,6 +127,11 @@ impl Comment {
pub fn edit(&mut self, clock: Lamport, body: String, timestamp: Timestamp) {
self.edits.insert(clock, Edit { body, timestamp }.into())
}
/// Comment reactions.
pub fn reactions(&self) -> impl Iterator<Item = (&ActorId, &Reaction)> {
self.reactions.iter().map(|(a, r)| (a, r))
}
}
impl PartialOrd for Comment {
@ -175,16 +183,13 @@ impl From<Action> for nonempty::NonEmpty<Action> {
pub struct Thread {
/// The comments under the thread.
comments: GMap<CommentId, Redactable<Comment>>,
/// Reactions to changes.
reactions: GMap<CommentId, LWWSet<(ActorId, Reaction), Lamport>>,
/// Comment timeline.
timeline: GSet<(Lamport, EntryId)>,
timeline: GSet<(Lamport, CommentId)>,
}
impl Semilattice for Thread {
fn merge(&mut self, other: Self) {
self.comments.merge(other.comments);
self.reactions.merge(other.reactions);
self.timeline.merge(other.timeline);
}
}
@ -193,7 +198,6 @@ impl Thread {
pub fn new(id: CommentId, comment: Comment) -> Self {
Self {
comments: GMap::singleton(id, Redactable::Present(comment)),
reactions: GMap::default(),
timeline: GSet::default(),
}
}
@ -244,17 +248,6 @@ impl Thread {
})
}
pub fn reactions<'a>(
&'a self,
to: &'a CommentId,
) -> impl Iterator<Item = (&ActorId, &Reaction)> {
self.reactions
.get(to)
.into_iter()
.flat_map(move |rs| rs.iter())
.map(|(a, r)| (a, r))
}
pub fn comments(&self) -> impl DoubleEndedIterator<Item = (&CommentId, &Comment)> + '_ {
self.timeline.iter().filter_map(|(_, id)| {
self.comments
@ -335,14 +328,17 @@ impl cob::store::FromHistory for Thread {
active,
} => {
let key = (op.author, reaction);
let reactions = if active {
LWWSet::singleton(key, op.clock)
if let Some(redactable) = self.comments.get_mut(&to) {
if let Redactable::Present(comment) = redactable {
if active {
comment.reactions.insert(key, op.clock);
} else {
comment.reactions.remove(key, op.clock);
}
}
} else {
let mut set = LWWSet::default();
set.remove(key, op.clock);
set
};
self.reactions.insert(to, reactions);
return Err(Error::Missing(id));
}
}
}
}