/* * ToroDB * Copyright © 2014 8Kdata Technology (www.8kdata.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.torodb.backend.converters.jooq; import com.torodb.kvdocument.values.KvValue; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.jooq.Binding; import org.jooq.BindingGetResultSetContext; import org.jooq.BindingGetSQLInputContext; import org.jooq.BindingGetStatementContext; import org.jooq.BindingRegisterContext; import org.jooq.BindingSQLContext; import org.jooq.BindingSetSQLOutputContext; import org.jooq.BindingSetStatementContext; import org.jooq.Configuration; import org.jooq.Converter; import org.jooq.DataType; import org.jooq.EnumType; import org.jooq.Field; import org.jooq.SQLDialect; import java.sql.SQLException; import java.util.Collection; import java.util.List; public class DataTypeForKv<T extends KvValue<?>> implements DataType<T> { private static final long serialVersionUID = 1L; @SuppressWarnings({"unchecked", "rawtypes"}) public static <DT, JT, T extends KvValue<?>> DataTypeForKv<T> from(DataType<DT> dataType, KvValueConverter<DT, JT, T> converter) { return new DataTypeForKv<>(dataType.asConvertedDataType(new KvChainConverter(dataType .getConverter(), converter)), converter); } @SuppressWarnings({"unchecked", "rawtypes"}) public static <DT, JT, T extends KvValue<?>> DataTypeForKv<T> from(DataType<DT> dataType, KvValueConverter<DT, JT, T> converter, int sqlType) { return new DataTypeForKv<>(dataType.asConvertedDataType(new KvChainConverter(dataType .getConverter(), converter)), converter, sqlType); } @SuppressWarnings({"unchecked", "rawtypes"}) public static <DT, JT, T extends KvValue<?>> DataTypeForKv<T> from(DataType<DT> dataType, KvValueConverter<DT, JT, T> converter, Binding<DT, T> binding) { return new DataTypeForKv<>(dataType.asConvertedDataType(new KvChainBinding(binding, dataType .getConverter(), converter)), converter); } @SuppressWarnings({"unchecked", "rawtypes"}) public static <DT, JT, T extends KvValue<?>> DataTypeForKv<T> from(DataType<DT> dataType, KvValueConverter<DT, JT, T> converter, Binding<DT, T> binding, int sqlType) { return new DataTypeForKv<>(dataType.asConvertedDataType(new KvChainBinding(binding, dataType .getConverter(), converter)), converter, sqlType); } private final DataType<T> dataType; private final int sqlType; private final KvValueConverter<?, ?, T> kvValueConverter; private DataTypeForKv(DataType<T> dataType, KvValueConverter<?, ?, T> kvValueConverter) { super(); this.dataType = dataType; this.sqlType = dataType.getSQLType(); this.kvValueConverter = kvValueConverter; } private DataTypeForKv(DataType<T> dataType, KvValueConverter<?, ?, T> kvValueConverter, int sqlType) { super(); this.dataType = dataType; this.sqlType = sqlType; this.kvValueConverter = kvValueConverter; } public KvValueConverter<?, ?, T> getKvValueConverter() { return kvValueConverter; } @SuppressFBWarnings(value = "NM_CONFUSING", justification = "we cannot " + "change the name of a jOOQ method. And it goes against the code" + "style") @Override public int getSQLType() { return sqlType; } @Override public DataType<T> getSQLDataType() { return dataType.getSQLDataType(); } @Override public DataType<T> getDataType(Configuration configuration) { return dataType.getDataType(configuration); } @Override public Binding<?, T> getBinding() { return dataType.getBinding(); } @Override public Converter<?, T> getConverter() { return dataType.getConverter(); } @Override public Class<T> getType() { return dataType.getType(); } @Override public Class<T[]> getArrayType() { return dataType.getArrayType(); } @Override public DataType<T[]> getArrayDataType() { return dataType.getArrayDataType(); } @Override @SuppressWarnings({"rawtypes", "unchecked"}) public <E extends EnumType> DataType<E> asEnumDataType(Class<E> enumDataType) { DataType<E> dataType = this.dataType.asEnumDataType(enumDataType); return new DataTypeForKv(dataType, kvValueConverter); } @Override @SuppressWarnings({"rawtypes", "unchecked"}) public <U> DataType<U> asConvertedDataType(Converter<? super T, U> converter) { DataType dataType = this.dataType.asConvertedDataType(converter); return new DataTypeForKv(dataType, kvValueConverter); } @Override @SuppressWarnings({"rawtypes", "unchecked"}) public <U> DataType<U> asConvertedDataType(Binding<? super T, U> binding) { DataType dataType = this.dataType.asConvertedDataType(binding); return new DataTypeForKv(dataType, kvValueConverter); } @Override public String getTypeName() { return dataType.getTypeName(); } @Override public String getTypeName(Configuration configuration) { return dataType.getTypeName(configuration); } @Override public String getCastTypeName() { return dataType.getCastTypeName(); } @Override public String getCastTypeName(Configuration configuration) { return dataType.getCastTypeName(configuration); } @Override public SQLDialect getDialect() { return dataType.getDialect(); } @Override public T convert(Object object) { return dataType.convert(object); } @Override public T[] convert(Object... objects) { return dataType.convert(objects); } @Override public List<T> convert(Collection<?> objects) { return dataType.convert(objects); } @Override @SuppressWarnings({"rawtypes", "unchecked"}) public DataType<T> nullable(boolean nullable) { DataType dataType = this.dataType.nullable(nullable); return new DataTypeForKv(dataType, kvValueConverter); } @Override public boolean nullable() { return dataType.nullable(); } @Override @Deprecated public DataType<T> defaulted(boolean defaulted) { return dataType.defaulted(defaulted); } @Override public boolean defaulted() { return dataType.defaulted(); } @Override @SuppressWarnings({"rawtypes", "unchecked"}) public DataType<T> precision(int precision) { DataType dataType = this.dataType.precision(precision); return new DataTypeForKv(dataType, kvValueConverter); } @Override @SuppressWarnings({"rawtypes", "unchecked"}) public DataType<T> precision(int precision, int scale) { DataType dataType = this.dataType.precision(precision, scale); return new DataTypeForKv(dataType, kvValueConverter); } @Override public int precision() { return dataType.precision(); } @Override public boolean hasPrecision() { return dataType.hasPrecision(); } @Override @SuppressWarnings({"rawtypes", "unchecked"}) public DataType<T> scale(int scale) { DataType dataType = this.dataType.scale(scale); return new DataTypeForKv(dataType, kvValueConverter); } @Override public int scale() { return dataType.scale(); } @Override public boolean hasScale() { return dataType.hasScale(); } @Override @SuppressWarnings({"rawtypes", "unchecked"}) public DataType<T> length(int length) { DataType dataType = this.dataType.length(length); return new DataTypeForKv(dataType, kvValueConverter); } @Override public int length() { return dataType.length(); } @Override public boolean hasLength() { return dataType.hasLength(); } @Override public boolean isNumeric() { return dataType.isNumeric(); } @Override public boolean isString() { return dataType.isString(); } @Override public boolean isDateTime() { return dataType.isDateTime(); } @Override public boolean isTemporal() { return dataType.isTemporal(); } @Override public boolean isInterval() { return dataType.isInterval(); } @Override public boolean isBinary() { return dataType.isBinary(); } @Override public boolean isLob() { return dataType.isLob(); } @Override public boolean isArray() { return dataType.isArray(); } @Override @SuppressWarnings({"rawtypes", "unchecked"}) public DataType<T> defaultValue(T defaultValue) { DataType dataType = this.dataType.defaultValue(defaultValue); return new DataTypeForKv(dataType, kvValueConverter); } @Override @SuppressWarnings({"rawtypes", "unchecked"}) public DataType<T> defaultValue(Field<T> defaultValue) { DataType dataType = this.dataType.defaultValue(defaultValue); return new DataTypeForKv(dataType, kvValueConverter); } @Override public Field<T> defaultValue() { return dataType.defaultValue(); } public static class KvChainConverter<NewT, ChainT, WrappedT> implements Converter<NewT, WrappedT> { private static final long serialVersionUID = 1L; private final Converter<NewT, ChainT> leftConverter; private final Converter<ChainT, WrappedT> rightConverter; public KvChainConverter(Converter<NewT, ChainT> leftConverter, Converter<ChainT, WrappedT> rightConverter) { super(); this.leftConverter = leftConverter; this.rightConverter = rightConverter; } @Override public WrappedT from(NewT databaseObject) { return rightConverter.from(leftConverter.from(databaseObject)); } @Override public NewT to(WrappedT userObject) { if (userObject == null) { return null; } return leftConverter.to(rightConverter.to(userObject)); } @Override public Class<NewT> fromType() { return leftConverter.fromType(); } @Override public Class<WrappedT> toType() { return rightConverter.toType(); } } public static class KvChainBinding<NewT, ChainT, WrappedT> implements Binding<NewT, WrappedT> { private static final long serialVersionUID = 1L; private final Binding<NewT, WrappedT> delegate; private final KvChainConverter<NewT, ChainT, WrappedT> chainConverter; public KvChainBinding(Binding<NewT, WrappedT> delegate, Converter<NewT, ChainT> leftConverter, Converter<ChainT, WrappedT> rightConverter) { super(); this.delegate = delegate; this.chainConverter = new KvChainConverter<>(leftConverter, rightConverter); } public Converter<NewT, WrappedT> converter() { return chainConverter; } public void sql(BindingSQLContext<WrappedT> ctx) throws SQLException { delegate.sql(ctx); } public void register(BindingRegisterContext<WrappedT> ctx) throws SQLException { delegate.register(ctx); } public void set(BindingSetStatementContext<WrappedT> ctx) throws SQLException { delegate.set(ctx); } public void set(BindingSetSQLOutputContext<WrappedT> ctx) throws SQLException { delegate.set(ctx); } public void get(BindingGetResultSetContext<WrappedT> ctx) throws SQLException { delegate.get(ctx); } public void get(BindingGetStatementContext<WrappedT> ctx) throws SQLException { delegate.get(ctx); } public void get(BindingGetSQLInputContext<WrappedT> ctx) throws SQLException { delegate.get(ctx); } } }