Add support for streaming and cursor query execution in SQL templates#1632
Add support for streaming and cursor query execution in SQL templates#1632zZHorizonZz wants to merge 1 commit intoeclipse-vertx:masterfrom
Conversation
tsegismont
left a comment
There was a problem hiding this comment.
At first glance, I'm wondering why do we need a separate SqlTemplateStream.
In the original issue we talked about adding a couple methods to SqlTemplate and I assumed they would return a Cursor or a RowStream.
|
So, mostly, I think the most handy part of SqlTemplate is the mapTo methods. The issue here is that mapTo methods return |
Motivation: - Introduce a feature to handle large result sets efficiently with streaming and cursor-based query execution. Changes: - Added `SqlTemplateStream` and `forCursor` methods to `SqlTemplate`. - Added `SqlTemplateStreamImpl`, `CursorSqlTemplateImpl`, and `MappingRowStream` - Added documentation to `index.adoc` with examples
tsegismont
left a comment
There was a problem hiding this comment.
Thank you for the updates @zZHorizonZz
I took some time to review the proposal and limitations, and I think we're not going in the right direction. Indeed, we have new APIs that look like the original SqlClientTemplate, but not all methods can be supported because it doesn't fit with the usage model of cursor/rowstream.
I think that, instead, we should make it possible for users to parse a template query and map objects to parameters. Then they can use the existing preparedQuery, cursor and rowstream APIs like they usually do.
The parser could look like this (just the basics):
@VertxGen
public interface SqlTemplateParser {
/**
* Create a parser by extracting driver info from a SqlClient.
* The client reference is NOT retained after this call.
*
* @param client the SQL client to extract driver information from
* @param template the SQL template string with named parameters (e.g., "SELECT * FROM users WHERE id = #{id}")
* @return the template parser
*/
static SqlTemplateParser create(SqlClient client, String template) {
SqlClientInternal internal = (SqlClientInternal) client;
return SqlTemplateParserImpl.create(internal.driver(), template);
}
/**
* Get the parsed SQL query with driver-specific placeholders.
*
* @return the SQL query string
*/
String sql();
/**
* Convert parameters to Tuple using the provided TupleMapper.
*
* @param params the parameters object
* @param mapper the tuple mapper
* @param <T> the parameters type
* @return the tuple
*/
@GenIgnore(GenIgnore.PERMITTED_TYPE)
<T> Tuple mapToTuple(T params, TupleMapper<T> mapper);
}
/**
* Convert Map parameters directly to Tuple.
*
* @param params the parameters map
* @return the tuple
*/
default Tuple mapToTuple(Map<String, Object> params) {
return mapToTuple(params, TupleMapper.mapper(Function.identity()));
}
}Then for prepared queries:
class User {
public long id;
public String firstName;
public String lastName;
}
// Define row mapper
RowMapper<User> ROW_USER_MAPPER = row -> {
User user = new User();
user.id = row.getInteger("id");
user.firstName = row.getString("firstName");
user.lastName = row.getString("lastName");
return user;
};
// Parse template
SqlTemplateParser parser = SqlTemplateParser.create(client,
"SELECT * FROM users WHERE id=#{id}");
// Execute with row mapping
Map<String, Object> params = Collections.singletonMap("id", 1);
Tuple tuple = parser.mapToTuple(params);
client.preparedQuery(parser.sql())
.mapping(ROW_USER_MAPPER::map)
.execute(tuple)
.onSuccess(users -> {
users.forEach(user -> {
System.out.println(user.firstName + " " + user.lastName);
});
});And since this is generic, you could leverage the SqlTemplateParser for cursor/rowstreams
|
Thank you for the time @tsegismont This is an interesting approach and actually seems cleaner, but on the other hand I'm not sure how this would work in the case of streaming, because one of the things connection.prepare(sqlTemplate.getSql()).map(ps -> {
RowStream<Row> stream = ps.createStream(fetchSize, tuple);
stream.handler(row -> handler.handle(mapper.map(row)));
//etc
}I.e. there's no easier way to map rows at the moment (or at least I wasn't able to find one, happy to be corrected if I'm missing something). TLDR - I like the idea of making SQL more or less agnostic to the operation, but I think we'd then have a separate issue of making streams easier to use. |
Motivation:
vertx-sql-client-templatesChanges:
forStreamandforCursormethods toSqlTemplate.SqlTemplateStreamImpl,CursorSqlTemplateImpl, andMappingRowStreamindex.adocwith examplesCloses: #1624