All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.zero88.jooqx.SQLImpl Maven / Gradle / Ivy

package io.zero88.jooqx;

import java.sql.SQLNonTransientConnectionException;
import java.sql.SQLTransientConnectionException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.jooq.Configuration;
import org.jooq.DSLContext;
import org.jooq.Param;
import org.jooq.Query;
import org.jooq.SQLDialect;
import org.jooq.conf.ParamType;
import org.jooq.exception.SQLStateClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.vertx.core.Vertx;
import io.zero88.jooqx.datatype.DataTypeMapperRegistry;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.With;
import lombok.experimental.Accessors;

final class SQLImpl {

    @Getter
    @Accessors(fluent = true)
    abstract static class SQLEI, RS, C extends SQLResultCollector>
        implements SQLExecutor {

        private final Vertx vertx;
        private final DSLContext dsl;
        @With(AccessLevel.PROTECTED)
        private final S sqlClient;
        private final P preparedQuery;
        private final C resultCollector;
        private final SQLErrorConverter errorConverter;
        private final DataTypeMapperRegistry typeMapperRegistry;

        public SQLEI(Vertx vertx, DSLContext dsl, S sqlClient, P preparedQuery, C resultCollector,
                     SQLErrorConverter errorConverter, DataTypeMapperRegistry typeMapperRegistry) {
            this.vertx = vertx;
            this.dsl = dsl;
            this.sqlClient = sqlClient;
            this.preparedQuery = Optional.ofNullable(preparedQuery).orElseGet(this::defPrepareQuery);
            this.resultCollector = Optional.ofNullable(resultCollector).orElseGet(this::defResultCollector);
            this.errorConverter = Optional.ofNullable(errorConverter).orElseGet(this::defErrorConverter);
            this.typeMapperRegistry = Optional.ofNullable(typeMapperRegistry).orElseGet(this::defMapperRegistry);
        }

        protected final RuntimeException transientConnFailed(String errorMsg, Throwable cause) {
            final String sqlState = SQLStateClass.C08_CONNECTION_EXCEPTION.className();
            return this.errorConverter().handle(new SQLTransientConnectionException(errorMsg, sqlState, cause));
        }

        protected final RuntimeException nonTransientConnFailed(String errorMsg) {
            final String sqlState = SQLStateClass.C08_CONNECTION_EXCEPTION.className();
            return this.errorConverter().handle(new SQLNonTransientConnectionException(errorMsg, sqlState));
        }

        protected abstract P defPrepareQuery();

        protected abstract C defResultCollector();

        @NonNull
        protected SQLErrorConverter defErrorConverter() {
            return SQLErrorConverter.DEFAULT;
        }

        @NonNull
        protected DataTypeMapperRegistry defMapperRegistry() {
            return new DataTypeMapperRegistry();
        }

    }


    abstract static class SQLPQ implements SQLPreparedQuery {

        private static final Pattern NAMED_PARAM_PATTERN = Pattern.compile("(? bindValues(@NonNull Query query, @NonNull BindBatchValues bindBatchValues,
                                        @NonNull DataTypeMapperRegistry mapperRegistry) {
            return this.convert(query.getParams(), bindBatchValues, mapperRegistry);
        }

        protected abstract T doConvert(Map> params, DataTypeMapperRegistry registry,
                                       BiFunction, ?> queryValue);

        private T convert(@NonNull Map> params, @NonNull DataTypeMapperRegistry registry) {
            return doConvert(params, registry, (k, v) -> v.getValue());
        }

        private List convert(@NonNull Map> params, @NonNull BindBatchValues bindBatchValues,
                                @NonNull DataTypeMapperRegistry registry) {
            final List fields = bindBatchValues.getMappingFields();
            final List values = bindBatchValues.getMappingValues();
            return bindBatchValues.getRecords()
                                  .stream()
                                  .map(record -> doConvert(params, registry, (paramNameOrIndex, param) -> {
                                      if (param.getParamName() != null) {
                                          return record.get(param.getParamName());
                                      }
                                      try {
                                          final int index = Integer.parseInt(paramNameOrIndex) - 1;
                                          return Optional.ofNullable(
                                              (Object) record.get(record.field(fields.get(index))))
                                                         .orElseGet(() -> values.get(index));
                                      } catch (NumberFormatException e) {
                                          return record.get(paramNameOrIndex);
                                      }
                                  }))
                                  .collect(Collectors.toList());
        }

    }

}