-
Notifications
You must be signed in to change notification settings - Fork 37
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
Refactor scan with filtering #1715
Conversation
AndConditionSet other = (AndConditionSet) o; | ||
return conditions.equals(other.conditions); | ||
} | ||
private static class OngoingWhere { |
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.
This is introduced for simply and commonly managing the internal condition state for both BuildableScanAllWithWhere
and BuildableScanFromExistingWithXX
. Since it can also be used for GetBuilder,
this class may be moved to somewhere commonplace.
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.
Also, I avoided using just Where
to distinguish the Where
interface, but the name might be a bit weird since it will also be used after closing the where clause. InternalWhere
, WhereClause
, or WhereBuilder
? What do you think?
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.
WhereBuilder
sounds to me that it has build()
method. So, it might be worth adding build()
that returns Collection<Conjunction>
or something.
WhereClause
itself sounds good to me, but I noticed the term Clause
isn't used in this file...
I think WhereCondition
might be an option as the class contains only conditions.
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.
Thanks for the suggestion. I changed my mind a bit. Since the interface Where
is only used twice in this file, using it with the modifier (i.e., OperationBuilder.Where
) is not so bad looking. I'm going with this if no further concerns.
@@ -621,9 +591,9 @@ public static class BuildableScanOrScanAllFromExisting extends BuildableScan | |||
OperationBuilder.Table<BuildableScanOrScanAllFromExisting>, |
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.
Since BuildableScanOrScanAllFromExisting
is also used for changing an existing ScanWithIndex
, it might be better BuildableScanAllFromExisting
. But BuildableScanOrScanAllFromExisting
is older than the cross-partition scan with filtering, so I think breaking it would be a bit aggressive. Please let me know if you have any opinions.
Sorry, I found some null checks were accidentally deleted when refactoring. Fixed in 797b95e. |
*/ | ||
public BuildableAndConditionSet and(ConditionalExpression condition) { | ||
conditions.add(condition); | ||
return new BuildableAndConditionSet(conditions); |
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.
How about copying conditions
or using immutable conditions
to prevent the shared mutable collection from unexpectedly being changed?
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.
Right, that's well-mannered. Is the following expected?
@Immutable
public static class BuildableAndConditionSet {
private final Set<ConditionalExpression> conditions;
BuildableAndConditionSet(Set<ConditionalExpression> conditions) {
this.conditions = ImmutableSet.copyOf(conditions);
}
public BuildableAndConditionSet and(ConditionalExpression condition) {
return new BuildableAndConditionSet(
new ImmutableSet.Builder<ConditionalExpression>()
.addAll(conditions)
.add(condition)
.build());
}
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.
How about copying conditions or using immutable conditions to prevent the shared mutable collection from unexpectedly being changed?
I think my comment was a bit confusing. You could simply return just this
if you choose the mutate builder pattern. You can also take immutable approach. Mutable builder pattern is still common, so either would be fine.
For immutable way, probably you can declare conditions
as ImmutableSet
while it's not an interface. This might be controversial, but I think it's acceptable since Java doesn't have immutable collection interface.
scalardb/core/src/main/java/com/scalar/db/api/Selection.java
Lines 146 to 152 in 16b7a09
@Immutable | |
public static class Conjunction { | |
private final ImmutableSet<ConditionalExpression> conditions; | |
private Conjunction(ImmutableSet<ConditionalExpression> conditions) { | |
this.conditions = conditions; | |
} |
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.
Thanks! Unfortunately, we cannot just return this
here since we need to prevent users from calling or
once they start with and
. So, recreating a set without affecting the current set seems the best solution here.
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.
Ah, you're right. I thought it as a usual builder pattern...
Also, I think I was thinking of defensive copy and immutability when I writing the first comment, but I forgot it when writing the second comment. Sorry for the confusion.
As we talked on another chat, immutable approach is basically better as long as there is no memory memory-pressure concerns.
this.orderings.addAll(buildable.orderings); | ||
this.projections.addAll(buildable.projections); | ||
this.consistency = buildable.consistency; | ||
BuildableScanOrScanAllFromExisting buildableScanFromExisting; |
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.
BuildableScanOrScanAllFromExisting buildableScanFromExisting; | |
private BuildableScanOrScanAllFromExisting buildableScanFromExisting; |
This can be private
?
this.projections.addAll(buildable.projections); | ||
this.consistency = buildable.consistency; | ||
BuildableScanOrScanAllFromExisting buildableScanFromExisting; | ||
protected final OngoingWhere where; |
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.
IntelliJ shows Class 'OngoingWhere' is exposed outside its defined visibility scope
. So, this should be package-private?
protected final OngoingWhere where; | |
final OngoingWhere where; |
AndConditionSet other = (AndConditionSet) o; | ||
return conditions.equals(other.conditions); | ||
} | ||
private static class OngoingWhere { |
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.
WhereBuilder
sounds to me that it has build()
method. So, it might be worth adding build()
that returns Collection<Conjunction>
or something.
WhereClause
itself sounds good to me, but I noticed the term Clause
isn't used in this file...
I think WhereCondition
might be an option as the class contains only conditions.
@komamitsu Thank you for a lot of valuable feedback. I fixed them in a23097e. Also, I've added a little further refactoring in |
protected final List<Scan.Ordering> orderings = new ArrayList<>(); | ||
protected int limit; | ||
@Nullable protected com.scalar.db.api.Consistency consistency; | ||
protected BuildableScanAll buildableScanAll; |
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.
[trivial] BuildableScanAll
is mutable, so you can also make this variable final
and simply use it like this.
@Override
public BuildableScanAllWithWhere projection(String projection) {
buildableScanAll.projection(projection);
return this;
}
The current code can be used as-is if BuildableScanAll
changes into immutable in the future, so I don't have a strong opinion on it , though.
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.
Thanks again. Definitely. Fixed them in 8320ae8 as you mentioned due to no plan for changing them to immutable so far.
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.
LGTM! Thank you!
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.
LGTM! Thank you!
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.
LGTM, thank you!
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.
LGTM! Thank you!
(Very sorry for the late review 🙇 )
Description
This PR refactors
ScanAll
with a where clause so that we can supportGet
,GetWithIndex
Scan
, andScanWithIndex
with a where clause in a consistent way in the upcoming updates. After careful discussion, we decided to introduce a few backward-incompatible changes since cross-partition scan with filtering is a relatively new feature and we expected their users to be none or less.Related issues and/or PRs
Changes made
Conjunction
fromScan
toSelection
ConditionSetBuilder
and{And,Or}ConditionSet
fromScanBuilder
toapi
ScanBuilder
BuildableScanAllFromExistingWithX
toBuildableScanFromExistingWithX
so that it can be commonly used forScan
,ScanWithIndex
andScanAll
BuildableScanFromExistingWithWhere
using a composite buildableOngoingWhere
for the common internal condition managementChecklist
Additional notes (optional)
The following PRs will be upcoming in this order.
ScalAll
in Support dynamic arbitrary filtering on NoSQL databases #1682Scan
andScanWithIndex
Get
andGetWithIndex
Release notes
Refactored scan with filtering.