-
Notifications
You must be signed in to change notification settings - Fork 627
Change Bound's before to inclusive #2981
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,33 +38,36 @@ | |
*/ | ||
public final class Bound { | ||
|
||
/** Whether this bound is just before or just after the provided position */ | ||
private final boolean before; | ||
/** | ||
* Whether this bound includes the provided position (e.g. for {#code startAt()} or {#code | ||
* endAt()}) | ||
*/ | ||
private final boolean inclusive; | ||
|
||
/** The index position of this bound */ | ||
private final List<Value> position; | ||
|
||
public Bound(List<Value> position, boolean before) { | ||
public Bound(List<Value> position, boolean inclusive) { | ||
this.position = position; | ||
this.before = before; | ||
this.inclusive = inclusive; | ||
} | ||
|
||
public List<Value> getPosition() { | ||
return position; | ||
} | ||
|
||
public boolean isBefore() { | ||
return before; | ||
/** | ||
* Whether the bound includes the documents that lie directly on the bound. Returns {@code true} | ||
* for {@code startAt()} and {@code endAt()} and false for {@code startAfter()} and {@code | ||
* endBefore()}. | ||
*/ | ||
public boolean isInclusive() { | ||
return inclusive; | ||
} | ||
|
||
public String canonicalString() { | ||
public String positionString() { | ||
// TODO: Make this collision robust. | ||
StringBuilder builder = new StringBuilder(); | ||
if (before) { | ||
builder.append("b:"); | ||
} else { | ||
builder.append("a:"); | ||
} | ||
boolean first = true; | ||
for (Value indexComponent : position) { | ||
if (!first) { | ||
|
@@ -78,6 +81,17 @@ public String canonicalString() { | |
|
||
/** Returns true if a document sorts before a bound using the provided sort order. */ | ||
public boolean sortsBeforeDocument(List<OrderBy> orderBy, Document document) { | ||
int comparison = compareToDocument(orderBy, document); | ||
return inclusive ? comparison <= 0 : comparison < 0; | ||
} | ||
|
||
/** Returns true if a document sorts after a bound using the provided sort order. */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. readability request: can you include this comment somewhere in the class to save future us from going through this again? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done (added an abbreviated version to |
||
public boolean sortsAfterDocument(List<OrderBy> orderBy, Document document) { | ||
int comparison = compareToDocument(orderBy, document); | ||
return inclusive ? comparison >= 0 : comparison > 0; | ||
} | ||
|
||
private int compareToDocument(List<OrderBy> orderBy, Document document) { | ||
hardAssert(position.size() <= orderBy.size(), "Bound has more components than query's orderBy"); | ||
int comparison = 0; | ||
for (int i = 0; i < position.size(); i++) { | ||
|
@@ -105,8 +119,7 @@ public boolean sortsBeforeDocument(List<OrderBy> orderBy, Document document) { | |
break; | ||
} | ||
} | ||
|
||
return before ? comparison <= 0 : comparison < 0; | ||
return comparison; | ||
} | ||
|
||
@Override | ||
|
@@ -120,21 +133,21 @@ public boolean equals(Object o) { | |
|
||
Bound bound = (Bound) o; | ||
|
||
return before == bound.before && position.equals(bound.position); | ||
return inclusive == bound.inclusive && position.equals(bound.position); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
int result = (before ? 1 : 0); | ||
int result = (inclusive ? 1 : 0); | ||
result = 31 * result + position.hashCode(); | ||
return result; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
StringBuilder builder = new StringBuilder(); | ||
builder.append("Bound(before="); | ||
builder.append(before); | ||
builder.append("Bound(inclusive="); | ||
builder.append(inclusive); | ||
builder.append(", position="); | ||
for (int i = 0; i < position.size(); i++) { | ||
if (i > 0) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -180,7 +180,7 @@ public Bound getLowerBound(FieldIndex fieldIndex) { | |
Value cursorValue = startAt.getPosition().get(i); | ||
if (max(segmentValue, cursorValue) == cursorValue) { | ||
segmentValue = cursorValue; | ||
segmentInclusive = startAt.isBefore(); | ||
segmentInclusive = startAt.isInclusive(); | ||
} | ||
break; | ||
} | ||
|
@@ -256,7 +256,7 @@ public Bound getLowerBound(FieldIndex fieldIndex) { | |
Value cursorValue = endAt.getPosition().get(i); | ||
if (min(segmentValue, cursorValue) == cursorValue) { | ||
segmentValue = cursorValue; | ||
segmentInclusive = !endAt.isBefore(); | ||
segmentInclusive = endAt.isInclusive(); | ||
} | ||
break; | ||
} | ||
|
@@ -276,7 +276,7 @@ public Bound getLowerBound(FieldIndex fieldIndex) { | |
return null; | ||
} | ||
|
||
return new Bound(values, !inclusive); | ||
return new Bound(values, inclusive); | ||
} | ||
|
||
public List<OrderBy> getOrderBy() { | ||
|
@@ -318,12 +318,14 @@ public String getCanonicalId() { | |
|
||
if (startAt != null) { | ||
builder.append("|lb:"); | ||
builder.append(startAt.canonicalString()); | ||
builder.append(startAt.isInclusive() ? "b:" : "a:"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. optional: move this ternary into a method on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The result is flipped depending on whether this is a startAt or endAt cursor, hence I pulled it out. |
||
builder.append(startAt.positionString()); | ||
} | ||
|
||
if (endAt != null) { | ||
builder.append("|ub:"); | ||
builder.append(endAt.canonicalString()); | ||
builder.append(endAt.isInclusive() ? "a:" : "b:"); | ||
builder.append(endAt.positionString()); | ||
} | ||
|
||
memoizedCannonicalId = builder.toString(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -96,6 +96,8 @@ public void addFieldIndex(FieldIndex index) { | |
db.query("SELECT MAX(index_id) FROM index_configuration") | ||
.firstValue(input -> input.isNull(0) ? 0 : input.getInt(0)); | ||
|
||
// TODO(indexing): Properly dedupe indices to avoid duplicate index entries (by comparing | ||
// collection_group+index_proto) | ||
db.execute( | ||
"INSERT OR IGNORE INTO index_configuration (" | ||
+ "index_id, " | ||
|
@@ -176,7 +178,7 @@ public Set<DocumentKey> getDocumentsMatchingTarget(Target target) { | |
if (fieldIndex == null) return null; | ||
|
||
Bound lowerBound = target.getLowerBound(fieldIndex); | ||
String lowerBoundOp = lowerBound.isBefore() ? ">=" : ">"; // `startAt()` versus `startAfter()` | ||
String lowerBoundOp = lowerBound.isInclusive() ? ">=" : ">"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this cleanness makes everything worth it. |
||
|
||
@Nullable Bound upperBound = target.getUpperBound(fieldIndex); | ||
|
||
|
@@ -202,7 +204,7 @@ public Set<DocumentKey> getDocumentsMatchingTarget(Target target) { | |
lowerBoundValues.size() == upperBoundValues.size(), | ||
"Expected upper and lower bound size to match"); | ||
|
||
String upperBoundOp = upperBound.isBefore() ? "<" : "<="; // `endBefore()` versus `endAt()` | ||
String upperBoundOp = upperBound.isInclusive() ? "<=" : "<"; | ||
|
||
// TODO(indexing): To avoid reading the same documents multiple times, we should ideally only | ||
// send one query that combines all clauses. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm. I wonder if we can offload the duplicated logic into decodePosition, or if that just gets us back to the same level of misdirection.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would need to somehow convey whether this is a
start
orend
bound.