Extract RevisionNote.Comment and use it instead of PatchLineComment
There are 3 classes that represent an inline comment: - CommentInfo represents an inline comment in the REST API - PatchLineComment represents an inline comment in ReviewDb - RevisionNote.Comment represents an inline comment in NoteDb To support robot comments CommentInfo and RevisionNote.Comment must be extended so that the additional fields that are specific for robot comments can be supported. PatchLineComment should not be touched since robot comments will only be supported with NoteDb, but not with ReviewDb. At the moment PatchLineComment is also used to represent inline comments in all middle layers and in all utility classes that deal with inline comments. This means if NoteDb is used, inline comments come in over REST as CommentInfo, then they are converted into PatchLineComment and for storing them in NoteDb they are converted to RevisionNote.Comment. The intermediate transformation to PatchLineComment is bad for implementing robot comments, since this class should stay unchanged. To fix this RevisionNote.Comment is extracted into an own Comment class and then Comment is used instead of PatchLineComment in the middle layer. This means when NoteDb is used, inline comments are only converted once, from CommentInfo to Comment. Both types will have extensions for robot comments (by subtypes). For storing inline comments in ReviewDb inline comments are converted from CommentInfo to Comment to PatchLineComment. This is better than having the double-conversion for NoteDb, because ReviewDb will be removed in favour of NoteDb. This means when ReviewDb is removed PatchLineComment can then easily be deleted, as it's no longer used all over the codebase, but only in the ReviewDb layer. Change-Id: I53481e8231e04aeca5b924e409e97b0f1d53f516 Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
@@ -0,0 +1,263 @@
|
||||
// Copyright (C) 2016 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.gerrit.reviewdb.client;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class represents inline comments in NoteDb. This means it determines the
|
||||
* JSON format for inline comments in the revision notes that NoteDb uses to
|
||||
* persist inline comments.
|
||||
* <p>
|
||||
* Changing fields in this class changes the storage format of inline comments
|
||||
* in NoteDb and may require a corresponding data migration (adding new optional
|
||||
* fields is generally okay).
|
||||
* <p>
|
||||
* {@link PatchLineComment} also represents inline comments, but in ReviewDb.
|
||||
* There are a few notable differences:
|
||||
* <ul>
|
||||
* <li>PatchLineComment knows the comment status (published or draft). For
|
||||
* comments in NoteDb the status is determined by the branch in which they are
|
||||
* stored (published comments are stored in the change meta ref; draft comments
|
||||
* are store in refs/draft-comments branches in All-Users). Hence Comment
|
||||
* doesn't need to contain the status, but the status is implicitly known by
|
||||
* where the comments are read from.
|
||||
* <li>PatchLineComment knows the change ID. For comments in NoteDb, the change
|
||||
* ID is determined by the branch in which they are stored (the ref name
|
||||
* contains the change ID). Hence Comment doesn't need to contain the change ID,
|
||||
* but the change ID is implicitly known by where the comments are read from.
|
||||
* </ul>
|
||||
* <p>
|
||||
* For all utility classes and middle layer functionality using Comment over
|
||||
* PatchLineComment is preferred, as PatchLineComment will go away together with
|
||||
* ReviewDb. This means Comment should be used everywhere and only for storing
|
||||
* inline comment in ReviewDb a conversion to PatchLineComment is done.
|
||||
* Converting Comments to PatchLineComments and vice verse is done by
|
||||
* CommentsUtil#toPatchLineComments(Change.Id, PatchLineComment.Status, Iterable)
|
||||
* and CommentsUtil#toComments(String, Iterable).
|
||||
*/
|
||||
public class Comment {
|
||||
public static class Key {
|
||||
public String uuid;
|
||||
public String filename;
|
||||
public int patchSetId;
|
||||
|
||||
public Key(Key k) {
|
||||
this(k.uuid, k.filename, k.patchSetId);
|
||||
}
|
||||
|
||||
public Key(String uuid, String filename, int patchSetId) {
|
||||
this.uuid = uuid;
|
||||
this.filename = filename;
|
||||
this.patchSetId = patchSetId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder()
|
||||
.append("Comment.Key{")
|
||||
.append("uuid=").append(uuid).append(',')
|
||||
.append("filename=").append(filename).append(',')
|
||||
.append("patchSetId=").append(patchSetId)
|
||||
.append('}')
|
||||
.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof Key) {
|
||||
Key k = (Key) o;
|
||||
return Objects.equals(uuid, k.uuid)
|
||||
&& Objects.equals(filename, k.filename)
|
||||
&& Objects.equals(patchSetId, k.patchSetId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(uuid, filename, patchSetId);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Identity {
|
||||
int id;
|
||||
|
||||
public Identity(Account.Id id) {
|
||||
this.id = id.get();
|
||||
}
|
||||
|
||||
public Account.Id getId() {
|
||||
return new Account.Id(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof Identity) {
|
||||
return Objects.equals(id, ((Identity) o).id);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder()
|
||||
.append("Comment.Identity{")
|
||||
.append("id=").append(id)
|
||||
.append('}')
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Range {
|
||||
public int startLine;
|
||||
public int startChar;
|
||||
public int endLine;
|
||||
public int endChar;
|
||||
|
||||
public Range(Range r) {
|
||||
this(r.startLine, r.startChar, r.endLine, r.endChar);
|
||||
}
|
||||
|
||||
public Range(com.google.gerrit.extensions.client.Comment.Range r) {
|
||||
this(r.startLine, r.startCharacter, r.endLine, r.endCharacter);
|
||||
}
|
||||
|
||||
public Range(int startLine, int startChar, int endLine, int endChar) {
|
||||
this.startLine = startLine;
|
||||
this.startChar = startChar;
|
||||
this.endLine = endLine;
|
||||
this.endChar = endChar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof Range) {
|
||||
Range r = (Range) o;
|
||||
return Objects.equals(startLine, r.startLine)
|
||||
&& Objects.equals(startChar, r.startChar)
|
||||
&& Objects.equals(endLine, r.endLine)
|
||||
&& Objects.equals(endChar, r.endChar);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(startLine, startChar, endLine, endChar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder()
|
||||
.append("Comment.Range{")
|
||||
.append("startLine=").append(startLine).append(',')
|
||||
.append("startChar=").append(startChar).append(',')
|
||||
.append("endLine=").append(endLine).append(',')
|
||||
.append("endChar=").append(endChar)
|
||||
.append('}')
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public Key key;
|
||||
public int lineNbr;
|
||||
public Identity author;
|
||||
public Timestamp writtenOn;
|
||||
public short side;
|
||||
public String message;
|
||||
public String parentUuid;
|
||||
public Range range;
|
||||
public String tag;
|
||||
public String revId;
|
||||
public String serverId;
|
||||
|
||||
public Comment(Comment c) {
|
||||
this(new Key(c.key), c.author.getId(), new Timestamp(c.writtenOn.getTime()),
|
||||
c.side, c.message, c.serverId);
|
||||
this.lineNbr = c.lineNbr;
|
||||
this.range = c.range != null ? new Range(c.range) : null;
|
||||
this.tag = c.tag;
|
||||
this.revId = c.revId;
|
||||
}
|
||||
|
||||
public Comment(Key key, Account.Id author, Timestamp writtenOn,
|
||||
short side, String message, String serverId) {
|
||||
this.key = key;
|
||||
this.author = new Comment.Identity(author);
|
||||
this.writtenOn = writtenOn;
|
||||
this.side = side;
|
||||
this.message = message;
|
||||
this.serverId = serverId;
|
||||
}
|
||||
|
||||
public void setLineNbrAndRange(Integer lineNbr,
|
||||
com.google.gerrit.extensions.client.Comment.Range range) {
|
||||
this.lineNbr = lineNbr != null
|
||||
? lineNbr
|
||||
: range != null
|
||||
? range.endLine
|
||||
: 0;
|
||||
if (range != null) {
|
||||
this.range = new Comment.Range(range);
|
||||
}
|
||||
}
|
||||
|
||||
public void setRange(CommentRange range) {
|
||||
this.range = range != null ? range.asCommentRange() : null;
|
||||
}
|
||||
|
||||
public void setRevId(RevId revId) {
|
||||
this.revId = revId != null ? revId.get() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof Comment) {
|
||||
return Objects.equals(key, ((Comment) o).key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return key.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder()
|
||||
.append("Comment{")
|
||||
.append("key=").append(key).append(',')
|
||||
.append("lineNbr=").append(lineNbr).append(',')
|
||||
.append("author=").append(author.getId().get()).append(',')
|
||||
.append("writtenOn=").append(writtenOn.toString()).append(',')
|
||||
.append("side=").append(side).append(',')
|
||||
.append("message=").append(Objects.toString(message, "")).append(',')
|
||||
.append("parentUuid=")
|
||||
.append(Objects.toString(parentUuid, "")).append(',')
|
||||
.append("range=").append(Objects.toString(range, "")).append(',')
|
||||
.append("revId=").append(revId != null ? revId : "")
|
||||
.append("tag=").append(Objects.toString(tag, ""))
|
||||
.append('}')
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,10 @@ public class CommentRange {
|
||||
endCharacter = ec;
|
||||
}
|
||||
|
||||
public Comment.Range asCommentRange() {
|
||||
return new Comment.Range(startLine, startCharacter, endLine, endCharacter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof CommentRange) {
|
||||
|
||||
@@ -21,11 +21,24 @@ import com.google.gwtorm.client.StringKey;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Objects;
|
||||
|
||||
/** A comment left by a user on a specific line of a {@link Patch}. */
|
||||
/**
|
||||
* A comment left by a user on a specific line of a {@link Patch}.
|
||||
*
|
||||
* This class represents an inline comment in ReviewDb. It should only be used
|
||||
* for writing/reading inline comments to/from ReviewDb. For all other purposes
|
||||
* inline comments should be represented by {@link Comment}.
|
||||
*
|
||||
* @see Comment
|
||||
*/
|
||||
public final class PatchLineComment {
|
||||
public static class Key extends StringKey<Patch.Key> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static Key from(Change.Id changeId, Comment.Key key) {
|
||||
return new Key(new Patch.Key(new PatchSet.Id(changeId, key.patchSetId),
|
||||
key.filename), key.uuid);
|
||||
}
|
||||
|
||||
@Column(id = 1, name = Column.NONE)
|
||||
protected Patch.Key patchKey;
|
||||
|
||||
@@ -55,6 +68,12 @@ public final class PatchLineComment {
|
||||
public void set(String newValue) {
|
||||
uuid = newValue;
|
||||
}
|
||||
|
||||
public Comment.Key asCommentKey() {
|
||||
return new Comment.Key(get(),
|
||||
getParentKey().getFileName(),
|
||||
getParentKey().getParentKey().get());
|
||||
}
|
||||
}
|
||||
|
||||
public static final char STATUS_DRAFT = 'd';
|
||||
@@ -85,6 +104,28 @@ public final class PatchLineComment {
|
||||
}
|
||||
}
|
||||
|
||||
public static PatchLineComment from(Change.Id changeId,
|
||||
PatchLineComment.Status status, Comment c) {
|
||||
PatchLineComment.Key key = new PatchLineComment.Key(
|
||||
new Patch.Key(new PatchSet.Id(changeId, c.key.patchSetId),
|
||||
c.key.filename),
|
||||
c.key.uuid);
|
||||
|
||||
PatchLineComment plc = new PatchLineComment(key, c.lineNbr,
|
||||
c.author.getId(), c.parentUuid, c.writtenOn);
|
||||
plc.setSide(c.side);
|
||||
plc.setMessage(c.message);
|
||||
if (c.range != null) {
|
||||
Comment.Range r = c.range;
|
||||
plc.setRange(
|
||||
new CommentRange(r.startLine, r.startChar, r.endLine, r.endChar));
|
||||
}
|
||||
plc.setTag(c.tag);
|
||||
plc.setRevId(new RevId(c.revId));
|
||||
plc.setStatus(status);
|
||||
return plc;
|
||||
}
|
||||
|
||||
@Column(id = 1, name = Column.NONE)
|
||||
protected Key key;
|
||||
|
||||
@@ -260,6 +301,17 @@ public final class PatchLineComment {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public Comment asComment(String serverId) {
|
||||
Comment c = new Comment(key.asCommentKey(), author, writtenOn, side,
|
||||
message, serverId);
|
||||
c.setRevId(revId);
|
||||
c.setRange(range);
|
||||
c.lineNbr = lineNbr;
|
||||
c.parentUuid = parentUuid;
|
||||
c.tag = tag;
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof PatchLineComment) {
|
||||
|
||||
Reference in New Issue
Block a user