-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Implement conversion/type expressions #1050
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
Conversation
3c96fe0
to
9a5ec88
Compare
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.
Some of the TODOs cover the same topic; I've left a comment covering each topic covered by all TODOs. With the exception of the TODO, the code marked by it is not a draft, but is usually something I want to highlight or am not entirely satisfied with (but have considered good enough).
driver-core/src/main/com/mongodb/client/model/expressions/Expression.java
Show resolved
Hide resolved
.../src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java
Outdated
Show resolved
Hide resolved
.../src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java
Outdated
Show resolved
Hide resolved
.../src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java
Outdated
Show resolved
Hide resolved
// the direct "isT" (comparable to instanceof) are exposed via switch | ||
// here, we expose isTypeOr. These would be used on an Expression of | ||
// an unknown type, or to provide default values in cases where a null | ||
// has intruded into the alleged type. |
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.
See comments above. I have not exposed any of the isBoolean/isArray/etc (returns BoolEx) expressions, since it seems that the methods below cover what users need them for (isBooleanOr, which is an "opposite" to ifNull, which I think is preferable). Other possible usages would be covered by switch. But perhaps there is some reason to expose these that I am missing.
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 can always expose those methods in the future if we discover that we can't get by without doing so.
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.
Other possible usages would be covered by switch.
How so? It also surprised me not to see these methods.
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.
There seem to be only the following cases where isBoolean
and the rest are are needed:
- When doing pattern-matching (comparable to a group of if-instanceof blocks in Java). Switch is always a better way to model this, when there is more than one type being checked.
something.switchMap(on -> on
.isBoolean(v -> v.asString().concat(of(" - bool")))
.isNumber(v -> v.asString().concat(of(" - number")))
.isString(v -> v.asString().concat(of(" - string")))
.defaults(v -> of("something else"))
...
- When the value is being checked against only one type, we use something like
isBooleanOr(<defaultBolean>)
, which is conceptually shorthand for the following (though the generated MQL is different).
something.switchMap(on -> on
.isBoolean(v -> v)
.defaults(v -> <defaultBoolean>)
...
This case arises in the getField(f, default) methods, to allow users to get fields that they cannot assert contain only one type of value (this also covers null and missing, since those are not, for example, booleans).
- As @stIncMale brought up elsewhere, we might need
array.filter(v -> v.isBoolean()).map(v -> v.isBooleanOr(true))
, but it is better to provide something like our switch's pattern-matching for this, soarray.filterToIntegers
or something more suitably named. This reduces the boilerplate and gets rid of the unused default valuetrue
.
Apart from the above (which are all variations of the same theme of mapping to an alternative based on type), there seems to be no common case where these isType
checks would be used (and the rarer cases can all be modelled using switch(on->isType(...).defaults(...))
if it comes to that).
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.
There seem to be only the following cases
I don't buy this argument. How is this any different than instanceof
in Java? Often it's the only condition in a swittch/if, but sometimes it's combined with other conditions, e.g. if (foo instanceof Bar || foo instance of Baz)
. It would kind of stink if the language syntax prevented that.
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.
The language does not prevent the unusual case you describe:
something.switchMap(on -> on
.isBoolean(v -> of(true))
.isNumber(v -> of(true))
.defaults(v -> of(false)).not()
I say "unusual" because I spot checked our codebase for composite instanceof
, and saw only ~5/100, and even those all seemed improbable in our API. In any case, the alternative, using isBoolean, seems less elegant even for the code fragment you provided:
var isBooleanOrNumber = v -> v.isBoolean().or(v.isNumber())
something.apply(isBooleanOrNumber).not()
The rationale for excluding it is not just YAGNI (which is itself a fair rationale). If we exclude it, users attempting to check types are forced into a "pit of success" for the most common cases, such as :
something.switchMap(on -> on
.isDate(v -> v)
.isString(v -> v.parseDate()))
If we expose the "isType" methods, users would gravitate towards the following:
something
.isDate().cond(v, something
.isStringOr(of("not used")).parseDate())
This is not as readable, requires an unused construct, and it is less maintainable (imagine that you must now check something
for integer milliseconds - consider how immediately obvious the code change is to the switchMap, versus the example using isDate immediately above.
- Still trivially possible to do everything, and in a syntax that is arguably superior
- Forces users into a substantially better syntax for the most common cases
- Maintains "a single way of doing things" within the API
- YAGNI
- We can always add these later but cannot remove them
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.
Discussed, and agreed that these can be added later if needed (and we will have more info to decide this later).
driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java
Show resolved
Hide resolved
9081c8f
to
46bc457
Compare
686d7f7
to
66e6297
Compare
66e6297
to
c9ff819
Compare
.../src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java
Outdated
Show resolved
Hide resolved
.../src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java
Outdated
Show resolved
Hide resolved
.../src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java
Show resolved
Hide resolved
driver-core/src/main/com/mongodb/client/model/expressions/Expression.java
Show resolved
Hide resolved
driver-core/src/main/com/mongodb/client/model/expressions/Expression.java
Show resolved
Hide resolved
...src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java
Outdated
Show resolved
Hide resolved
...src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java
Outdated
Show resolved
Hide resolved
.../src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java
Outdated
Show resolved
Hide resolved
.../src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java
Outdated
Show resolved
Hide resolved
.../src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java
Outdated
Show resolved
Hide resolved
f443b11
to
031d61d
Compare
ab24ae4
to
17686ad
Compare
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.
.
driver-core/src/main/com/mongodb/client/model/expressions/NumberExpression.java
Outdated
Show resolved
Hide resolved
driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java
Outdated
Show resolved
Hide resolved
driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java
Outdated
Show resolved
Hide resolved
driver-core/src/main/com/mongodb/client/model/expressions/Expression.java
Show resolved
Hide resolved
driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java
Show resolved
Hide resolved
driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java
Show resolved
Hide resolved
driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java
Show resolved
Hide resolved
.../src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java
Outdated
Show resolved
Hide resolved
// the direct "isT" (comparable to instanceof) are exposed via switch | ||
// here, we expose isTypeOr. These would be used on an Expression of | ||
// an unknown type, or to provide default values in cases where a null | ||
// has intruded into the alleged type. |
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.
Other possible usages would be covered by switch.
How so? It also surprised me not to see these methods.
.../src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java
Outdated
Show resolved
Hide resolved
driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java
Outdated
Show resolved
Hide resolved
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'm not satisfied with parseNumber yet.
* Implement boolean expressions (#1025) JAVA-4779 * Implement filter, map, reduce (#1031) JAVA-4781 * Implement eq, ne, gt, gte, lt, lte (#1033) JAVA-4784 * Implement string expressions (#1036) JAVA-4801 * Implement arithmetic expressions (#1037) Implement arithmetic expressions (from top 50, and others) JAVA-4803 * Implement array expressions (#1043) JAVA-4805 * Implement date expressions (#1045) JAVA-4804 * Implement conversion/type expressions (#1050) JAVA-4802 * Implement document expressions (#1052) JAVA-4782 * Replace reduce with individual reductions (#1053) JAVA-4814 * Implement map expressions (#1054) JAVA-4817 * Implement switch expression (#1055) JAVA-4813 * Test expressions in context (#1057) JAVA-4820 * Add javadoc for boolean, date, number, integer, and expression (#1059) JAVA-4799 * Update and add documentation (#1059) * Fix, tests JAVA-4799 * Add `@MqlUnchecked` and a few usage examples (#1059) JAVA-4799 * Add has to document, add tests (#1070) JAVA-4799 * Add javadocs for remaining classes (#1070) JAVA-4799 * 5.2 annotations (#1070) JAVA-4799 * 5.0 annotations (#1070) JAVA-4799 * 4.4 annotations (#1070) JAVA-4799 * 4.2 annotations (#1070) JAVA-4799 * 4.0 annotations (#1070) JAVA-4799 * Update and add documentation, add tests, fix minor issues (#1070) Rename extractBsonValue Fix access modifiers Remove excess comments Update docs Fix: behaviour of get Add notNull to API, add notNullApi test Fix docs/annotations, tests Fix docs, annotations, since Fix docs Revert external Add missing MqlUnchecked Fix missing null checks Checkstyle JAVA-4799 * Rename to Mql (automated) (#1073) JAVA-3879 * Rename methods (automated) (#1073) JAVA-3879 * Update naming, terms, and missing checks and annotations (#1073) JAVA-3879 --------- Co-authored-by: Valentin Kovalenko <[email protected]>
JAVA-4802