io.zero88.jooqx.LegacySQLImpl Maven / Gradle / Ivy
package io.zero88.jooqx;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.jooq.Configuration;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.jooq.Param;
import org.jooq.Query;
import org.jooq.conf.ParamType;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonArray;
import io.vertx.ext.sql.ResultSet;
import io.vertx.ext.sql.SQLClient;
import io.vertx.ext.sql.SQLConnection;
import io.vertx.ext.sql.SQLOperations;
import io.zero88.jooqx.MiscImpl.BatchResultImpl;
import io.zero88.jooqx.SQLImpl.SQLEI;
import io.zero88.jooqx.SQLImpl.SQLPQ;
import io.zero88.jooqx.adapter.RowConverterStrategy;
import io.zero88.jooqx.adapter.SQLResultAdapter;
import io.zero88.jooqx.adapter.SelectStrategy;
import io.zero88.jooqx.datatype.DataTypeMapperRegistry;
import lombok.Getter;
import lombok.NonNull;
import lombok.experimental.Accessors;
final class LegacySQLImpl {
interface LegacyInternal
extends SQLExecutor {
@Override
@NonNull LegacySQLPreparedQuery preparedQuery();
@Override
@NonNull LegacySQLCollector resultCollector();
}
static final class LegacySQLPQ extends SQLPQ implements LegacySQLPreparedQuery {
@Override
protected JsonArray doConvert(Map> params, DataTypeMapperRegistry registry,
BiFunction, ?> queryValue) {
JsonArray array = new JsonArray();
params.entrySet()
.stream()
.filter(entry -> !entry.getValue().isInline())
.forEachOrdered(etr -> array.add(registry.toDatabaseType(etr.getKey(), etr.getValue(), queryValue)));
return array;
}
}
static final class LegacySQLRC implements LegacySQLCollector {
@NonNull
@Override
public List collect(@NonNull ResultSet resultSet, @NonNull RowConverterStrategy strategy) {
final Map, Integer> map = getColumnMap(resultSet, strategy::lookupField);
final List results = resultSet.getResults();
if (strategy.strategy() == SelectStrategy.MANY) {
return results.stream().map(row -> toRecord(strategy, map, row)).collect(Collectors.toList());
}
warnManyResult(results.size() > 1, strategy.strategy());
return results.stream()
.findFirst()
.map(row -> toRecord(strategy, map, row))
.map(Collections::singletonList)
.orElse(new ArrayList<>());
}
private R toRecord(RowConverterStrategy strategy, Map, Integer> map, JsonArray row) {
return map.keySet().stream().collect(strategy.createCollector(f -> row.getValue(map.get(f))));
}
private Map, Integer> getColumnMap(ResultSet rs, Function> lookupField) {
return IntStream.range(0, rs.getNumColumns())
.boxed()
.map(i -> Optional.ofNullable(lookupField.apply(rs.getColumnNames().get(i)))
.map(f -> new SimpleEntry<>(f, i))
.orElse(null))
.filter(Objects::nonNull)
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
}
@Override
public int batchResultSize(List batchResult) {
return batchResult.size();
}
}
@Getter
@Accessors(fluent = true)
abstract static class LegacySQLEI
extends SQLEI
implements LegacyInternal {
LegacySQLEI(Vertx vertx, DSLContext dsl, S sqlClient, LegacySQLPreparedQuery preparedQuery,
LegacySQLCollector resultCollector, SQLErrorConverter errorConverter,
DataTypeMapperRegistry typeMapperRegistry) {
super(vertx, dsl, sqlClient, preparedQuery, resultCollector, errorConverter, typeMapperRegistry);
}
@Override
public final Future execute(@NonNull Query query, @NonNull SQLResultAdapter adapter) {
final Promise promise = Promise.promise();
sqlClient().queryWithParams(preparedQuery().sql(dsl().configuration(), query),
preparedQuery().bindValues(query, typeMapperRegistry()), promise);
return promise.future()
.map(rs -> adapter.collect(rs, resultCollector(), dsl(), typeMapperRegistry()))
.otherwise(errorConverter()::reThrowError);
}
@Override
public final Future batch(@NonNull Query query, @NonNull BindBatchValues bindBatchValues) {
final Promise> promise = Promise.promise();
openConn().map(c -> c.batchWithParams(preparedQuery().sql(dsl().configuration(), query),
preparedQuery().bindValues(query, bindBatchValues,
typeMapperRegistry()), promise));
return promise.future()
.map(r -> new LegacySQLRC().batchResultSize(r))
.map(s -> BatchResultImpl.create(bindBatchValues.size(), s))
.otherwise(errorConverter()::reThrowError);
}
protected abstract Future openConn();
@Override
protected final LegacySQLPreparedQuery defPrepareQuery() {
return new LegacySQLPQ();
}
@Override
protected final LegacySQLCollector defResultCollector() {
return new LegacySQLRC();
}
}
@Getter
@Accessors(fluent = true)
static final class LegacyJooqxImpl extends LegacySQLEI implements LegacyJooqx {
LegacyJooqxImpl(Vertx vertx, DSLContext dsl, SQLClient sqlClient, LegacySQLPreparedQuery preparedQuery,
LegacySQLCollector resultCollector, SQLErrorConverter errorConverter,
DataTypeMapperRegistry typeMapperRegistry) {
super(vertx, dsl, sqlClient, preparedQuery, resultCollector, errorConverter, typeMapperRegistry);
}
@Override
@SuppressWarnings("unchecked")
public @NonNull LegacyJooqxTx transaction() {
return new LegacyJooqTxImpl(this);
}
@Override
protected LegacyJooqxImpl withSqlClient(@NonNull SQLClient sqlClient) {
throw new UnsupportedOperationException("No need");
}
protected Future openConn() {
final Promise promise = Promise.promise();
sqlClient().getConnection(ar -> {
if (ar.failed()) {
promise.fail(transientConnFailed("Unable open SQL connection", ar.cause()));
} else {
promise.complete(ar.result());
}
});
return promise.future();
}
}
@Getter
@Accessors(fluent = true)
static final class LegacyJooqTxImpl extends LegacySQLEI implements LegacyJooqxTx {
private final LegacySQLEI delegate;
LegacyJooqTxImpl(Vertx vertx, DSLContext dsl, SQLConnection sqlClient, LegacySQLPreparedQuery preparedQuery,
LegacySQLCollector resultCollector, SQLErrorConverter errorConverter,
DataTypeMapperRegistry typeMapperRegistry) {
super(vertx, dsl, sqlClient, preparedQuery, resultCollector, errorConverter, typeMapperRegistry);
this.delegate = null;
}
LegacyJooqTxImpl(@NonNull LegacySQLEI delegate) {
super(delegate.vertx(), delegate.dsl(), null, delegate.preparedQuery(), delegate.resultCollector(),
delegate.errorConverter(), delegate.typeMapperRegistry());
this.delegate = delegate;
}
@Override
public Future run(@NonNull Function> block) {
final Promise promise = Promise.promise();
delegate.openConn().map(conn -> conn.setAutoCommit(false, committable -> {
if (committable.failed()) {
failed(conn, promise, transientConnFailed("Unable begin transaction", committable.cause()));
} else {
block.apply(withSqlClient(conn))
.onSuccess(r -> commit(conn, promise, r))
.onFailure(t -> rollback(conn, promise, t));
}
}));
return promise.future();
}
@Override
protected Future openConn() {
return Future.succeededFuture(sqlClient());
}
@Override
protected LegacyJooqTxImpl withSqlClient(@NonNull SQLConnection sqlConn) {
return new LegacyJooqTxImpl(vertx(), dsl(), sqlConn, preparedQuery(), resultCollector(), errorConverter(),
typeMapperRegistry());
}
private void commit(@NonNull SQLConnection conn, @NonNull Promise promise, X output) {
conn.commit(v -> {
if (v.succeeded()) {
promise.complete(output);
conn.close();
} else {
rollback(conn, promise, errorConverter().handle(v.cause()));
}
});
}
private void rollback(@NonNull SQLConnection conn, @NonNull Promise promise, @NonNull Throwable t) {
conn.rollback(rb -> {
if (!rb.succeeded()) {
t.addSuppressed(rb.cause());
}
failed(conn, promise, t);
});
}
private void failed(@NonNull SQLConnection conn, @NonNull Promise promise, @NonNull Throwable t) {
promise.fail(t);
conn.close();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy