-
Notifications
You must be signed in to change notification settings - Fork 111
Support isDistinctFrom and isNotDistinctFrom operators #3357
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 5 commits
abf60b7
fc8bbde
bdedab9
360d238
db1f740
a7570ab
7c0b283
6e540c1
3c537c1
1daf249
b93b544
35b081c
70aa7e6
3a8c3dc
b134bbb
0c45afe
6af3ef8
6b82cb2
2eb1075
dd7538f
ded9003
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 |
---|---|---|
|
@@ -234,24 +234,24 @@ public static Object toClassWithRealEquals(@Nullable Object obj) { | |
|
||
@SuppressWarnings("unchecked") | ||
public static int compare(@Nullable Object fieldValue, @Nullable Object comparand) { | ||
if (fieldValue == null) { | ||
if (comparand == null) { | ||
return 0; | ||
} else { | ||
return -1; | ||
} | ||
} else if (comparand == null) { | ||
return 1; | ||
return toComparable(fieldValue).compareTo(toComparable(comparand)); | ||
} | ||
|
||
@SpotBugsSuppressWarnings("NP_BOOLEAN_RETURN_NULL") | ||
private static boolean compareEquals(@Nonnull Object value, @Nonnull Object comparand) { | ||
if (value instanceof Message) { | ||
return MessageHelpers.compareMessageEquals(value, comparand); | ||
} else { | ||
return toComparable(fieldValue).compareTo(toComparable(comparand)); | ||
return toClassWithRealEquals(value).equals(toClassWithRealEquals(comparand)); | ||
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. Can we make 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. |
||
} | ||
} | ||
|
||
@Nullable | ||
@SpotBugsSuppressWarnings("NP_BOOLEAN_RETURN_NULL") | ||
private static Boolean compareEquals(Object value, Object comparand) { | ||
if (value == null || comparand == null) { | ||
return null; | ||
private static boolean compareNotDistinctFrom(Object value, Object comparand) { | ||
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 should have 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. Added. |
||
if (value == null && comparand == null) { | ||
return true; | ||
} else if (value == null || comparand == null) { | ||
return false; | ||
} else { | ||
if (value instanceof Message) { | ||
return MessageHelpers.compareMessageEquals(value, comparand); | ||
|
@@ -285,6 +285,9 @@ private static Boolean compareStartsWith(@Nullable Object value, @Nullable Objec | |
@Nullable | ||
@SpotBugsSuppressWarnings("NP_BOOLEAN_RETURN_NULL") | ||
private static Boolean compareLike(@Nullable Object value, @Nullable Object pattern) { | ||
if (value == null) { | ||
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. Does this want to similarly handle 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. I checked that in sql, 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. I removed the |
||
return null; | ||
} | ||
if (!(value instanceof String)) { | ||
throw new RecordCoreException("Illegal comparand value type: " + value); | ||
} | ||
|
@@ -634,7 +637,9 @@ public enum Type { | |
@API(API.Status.EXPERIMENTAL) | ||
SORT(false), | ||
@API(API.Status.EXPERIMENTAL) | ||
LIKE; | ||
LIKE, | ||
IS_DISTINCT_FROM(true), | ||
NOT_DISTINCT_FROM(false); | ||
|
||
@Nonnull | ||
private static final Supplier<BiMap<Type, PComparisonType>> protoEnumBiMapSupplier = | ||
|
@@ -707,28 +712,44 @@ public static Type invertComparisonType(@Nonnull final Comparisons.Type type) { | |
@Nullable | ||
@SpotBugsSuppressWarnings("NP_BOOLEAN_RETURN_NULL") | ||
public static Boolean evalComparison(@Nonnull Type type, @Nullable Object value, @Nullable Object comparand) { | ||
if (value == null) { | ||
return null; | ||
} | ||
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. as I mentioned in another comment, because of this is called first, we'll never reach the 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. right now, if type = TEXT_CONTAINS_ALL, or anything that is not in the 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. Yes, throwing for unknown type before checking either side does seem better. 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. 👍 after removing the |
||
switch (type) { | ||
case STARTS_WITH: | ||
return compareStartsWith(value, comparand); | ||
case IN: | ||
return compareIn(value, comparand); | ||
case EQUALS: | ||
if (value == null || comparand == null) { | ||
return null; | ||
} | ||
return compareEquals(value, comparand); | ||
case NOT_EQUALS: | ||
if (comparand == null) { | ||
if (value == null || comparand == null) { | ||
return null; | ||
} | ||
return !compareEquals(value, comparand); | ||
case IS_DISTINCT_FROM: | ||
return !compareNotDistinctFrom(value, comparand); | ||
case NOT_DISTINCT_FROM: | ||
return compareNotDistinctFrom(value, comparand); | ||
case LESS_THAN: | ||
if (value == null || comparand == null) { | ||
return null; | ||
} | ||
return compare(value, comparand) < 0; | ||
case LESS_THAN_OR_EQUALS: | ||
if (value == null || comparand == null) { | ||
return null; | ||
} | ||
return compare(value, comparand) <= 0; | ||
case GREATER_THAN: | ||
if (value == null || comparand == null) { | ||
return null; | ||
} | ||
return compare(value, comparand) > 0; | ||
case GREATER_THAN_OR_EQUALS: | ||
if (value == null || comparand == null) { | ||
return null; | ||
} | ||
return compare(value, comparand) >= 0; | ||
case LIKE: | ||
return compareLike(value, comparand); | ||
|
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.
I think the original line 237~244 is wrong? If any of the left or right is null, the comparison result should be unknown? Also in the original code, we call:
if(value == null) return null
before we call thiscompare
method, so the block ofif(fieldValue == null)
was never reached.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 method currently implements full collation for use in contexts where
NULL
is to be considered just another value. For example, that is how index entries sort withNULLS FIRST
. It is still reasonable to use such a function in contexts that implement tri-valued logic by guarding calls, as many callers do today.It is equally reasonable to have this method only implement comparison between non-null values and to expect all callers to deal with nulls, either sorting them first or producing unknown, as is appropriate to their context. And both contexts are appropriate in the larger system, which must deal sometimes with the "query" view that has unknown and other times with the "storage" view that does not. It might be nice to have a clearer separation so that it is unambiguous which view applies, perhaps by using entirely different currency and not just bare
Object
.What this change does is something in between, which doesn't seem right. Specifically, if this does not handle
null
at all, then it ought not to have@Nullable
. The signature should also be changed. I am surprised that the IDE / style checker(s) doesn't flag this for a possible NPE. But otherwise, it's okay provided all callers now check both sides.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.
Got it, I changed the method to compare between non-null values.