-
Notifications
You must be signed in to change notification settings - Fork 18
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
ResultSet API for TarantoolClient #223
Conversation
I would consider several points:
I think we should behave in a most strict way by default, but allow to relax restrictions when asked for this explicitly. We should describe which kinds of precision loss or implicit type changes will be enabled by each of provided options. I think a client configuration options is the proper places for those options. OTOH, I would not want to provide more options then necessary (just to keep things as simple as possible). If there are reasons to omit some of proposed options, then we should consider them. NB: I always afraid of data losses or misinterpretations, especially in context of databases, so I don't sure where an adequate balance between mistake protection and usage convenience exists. In other words, I would appreciate a critical view on my points. |
It seems that when field_count is specified, all tuples are of the same size (null's are encoded explicitly where needed). So we don't need to handle this case specifically. Using of an actual tuple size will give the same behaviour. |
This DSL includes set of request builders that can be used as a public API to construct requests. The main idea here is to provide more natural DSL-like approach to build operations instead of current abstract types like List<?> or List<Object>. Closes: #212
About first two points re numeric precision loss and cross-type conversions: let's implement those conversions for now, because they may be required for JDBC part of the driver. We can forbid them later under an option if there will be demand. |
8fd6068
to
416a303
Compare
This commit introduces a new API to handle TarantoolClient result. The concept is similar to the JDBC ResultSet in terms of a getting the data using rows ans columns. Instead of a guessing-style processing the result via List<?>, TarantoolResultSet offers set of typed methods to retrieve the data or get an error if the result cannot be represented as the designated type. Latter case requires to declare formal rules of a casting between the types. In scope of this commit it is supported 11 standard types and conversions between each other. These types are byte, short, int, long, float, double, boolean, BigInteger, BigDecimal, String, and byte[]. Closes: #211
416a303
to
ce50492
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.
The diff is large and has many comments on it. If it will be considered for modifying and pushing, I'd recommend splitting it into several PRs.
the same result. | ||
|
||
```java | ||
TarantoolResultSet result = client.executeRequest(Requests.selectRequest("space", "pk")); |
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 a good idea, although it's better to provide the exact way of mapping MsgPack entities to resulting structures (List, Map or some custom object) in some kind of mapping layer, where the mapping may be customized. Ofc, the driver will provide some default way of mapping, say, into TarantoolResultSet objects.
TarantoolResultSet result = client.executeRequest(Requests.selectRequest("space", "pk")); | ||
while (result.next()) { | ||
long id = result.getLong(0); | ||
String text = result.getString(1); |
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.
NPE here (or further) is inevitable. The underlying object is essentially a MsgPack array with a non-fixed length. So we should either return an Optional here or provide some kind of interface with checked and unchecked calls, like checked get
with Optional or throwing some kind of ArrayOutOfBounds exception, and unchecked getOrDefault
.
|
||
```java | ||
TarantoolResultSet result = client.executeRequest(Requests.selectRequest("space", "pk")); | ||
while (result.next()) { |
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.
Modern (1.8+) Java code is rarely dealing with bare iterators -- streams, for-each loops and their functional mirrors are the common practice.
```java | ||
TarantoolResultSet result = client.executeRequest(Requests.selectRequest("space", "pk")); | ||
while (result.next()) { | ||
long id = result.getLong(0); |
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.
Do we have unsafe casts here? Or the user will get some kind of an unchecked exception?
|
||
Numeric types internally can represent each other if a type range allows to do it. For example, | ||
byte 100 can be represented as a short, int and other types wider than byte. But 200 integer | ||
cannot be narrowed to a byte because of overflow (byte range is [-128..127]). If a floating |
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.
Will the conversion be performed actually when calling getInt
/getFloat
?
But in this case we will have double conversion with two sources of possible errors: MessagePack entity-to-object and then object-to-value conversions -- not very safe and not very fast. Also the conversion and overflow/underflow shouldn't be implicit without user interference and checked exceptions.
return Stream.of(Operator.values()) | ||
.filter(s -> s.getOpCode().equals(opCode)) | ||
.findFirst() | ||
.orElseThrow(IllegalArgumentException::new); |
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.
Exception message is missing
* Entry point to build requests | ||
* using DSL approach a.k.a Request DSL. | ||
*/ | ||
public class Requests { |
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.
Each request DSL interface offers some kind of request building logic and convenient result processing API instead of function calls with a bunch of parameters. See, for example, how typesafe JPA Criteria API is built or take a look at Querydsl.
IMO, this interface improves select methods a bit but neither is a DSL nor removes the boilerplate completely.
|
||
public SelectRequestSpec index(int indexId) { | ||
this.indexId = indexId; | ||
this.indexName = null; |
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.
That mutability again
this.indexName = Objects.requireNonNull(indexName); | ||
} | ||
|
||
public SelectRequestSpec(String spaceName, int indexId) { |
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 index must have a separate specification
|
||
@Test | ||
void testGetSimpleRows() { | ||
testHelper.executeLua( |
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.
(not in this request) Consider using test-containers for setting up the integration test environment.
I also strongly recommend running a style checker for this code, there are some places with double semicolons and other leftovers. |
Extend an TarantoolClient API to be able to get data using type safe
methods and conversions.
Closes: #211