feat: 完成r2dbc的支持

This commit is contained in:
wangyu 2024-07-13 00:33:32 +08:00
parent 1b61e13205
commit 8cdfe187d3
23 changed files with 588 additions and 407 deletions

View File

@ -3,17 +3,19 @@ package group.flyfish.fluent.chain;
import group.flyfish.fluent.chain.common.AfterJoinSqlChain; import group.flyfish.fluent.chain.common.AfterJoinSqlChain;
import group.flyfish.fluent.chain.common.HandleSqlChain; import group.flyfish.fluent.chain.common.HandleSqlChain;
import group.flyfish.fluent.chain.common.PreSqlChain; import group.flyfish.fluent.chain.common.PreSqlChain;
import group.flyfish.fluent.chain.execution.BoundEntity; import group.flyfish.fluent.chain.execution.BoundEntitySpec;
import group.flyfish.fluent.chain.execution.BoundProxy; import group.flyfish.fluent.chain.execution.BoundProxy;
import group.flyfish.fluent.chain.execution.ReactiveBoundEntity; import group.flyfish.fluent.chain.execution.ReactiveBoundEntitySpec;
import group.flyfish.fluent.chain.select.AfterOrderSqlChain; import group.flyfish.fluent.chain.select.AfterOrderSqlChain;
import group.flyfish.fluent.chain.select.AfterWhereSqlChain; import group.flyfish.fluent.chain.select.AfterWhereSqlChain;
import group.flyfish.fluent.chain.select.PieceSqlChain; import group.flyfish.fluent.chain.select.PieceSqlChain;
import group.flyfish.fluent.chain.update.AfterSetSqlChain; import group.flyfish.fluent.chain.update.AfterSetSqlChain;
import group.flyfish.fluent.debug.FluentSqlDebugger; import group.flyfish.fluent.debug.FluentSqlDebugger;
import group.flyfish.fluent.entity.BoundSQLEntity;
import group.flyfish.fluent.entity.DataPage; import group.flyfish.fluent.entity.DataPage;
import group.flyfish.fluent.entity.SQLEntity; import group.flyfish.fluent.entity.SQLEntity;
import group.flyfish.fluent.operations.FluentSQLOperations; import group.flyfish.fluent.operations.FluentSQLOperations;
import group.flyfish.fluent.operations.ReactiveFluentSQLOperations;
import group.flyfish.fluent.query.JoinCandidate; import group.flyfish.fluent.query.JoinCandidate;
import group.flyfish.fluent.query.Parameterized; import group.flyfish.fluent.query.Parameterized;
import group.flyfish.fluent.query.Query; import group.flyfish.fluent.query.Query;
@ -48,6 +50,8 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
// 共享的操作 // 共享的操作
private static FluentSQLOperations SHARED_OPERATIONS; private static FluentSQLOperations SHARED_OPERATIONS;
private static ReactiveFluentSQLOperations SHARED_REACTIVE_OPERATIONS;
// 参数map有序 // 参数map有序
private final List<Object> parameters = new ArrayList<>(); private final List<Object> parameters = new ArrayList<>();
@ -55,7 +59,7 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
private Class<?> primaryClass; private Class<?> primaryClass;
// sql实体提供者 // sql实体提供者
private final Supplier<SQLEntity> entity = wrap(this::toEntity); private final Supplier<SQLEntity> entity = wrap(this::entity);
/** /**
* 绑定实现类 * 绑定实现类
@ -66,6 +70,16 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
SHARED_OPERATIONS = operations; SHARED_OPERATIONS = operations;
} }
/**
* 绑定实现类
*
* @param operations r2dbc操作
*/
public static void bind(ReactiveFluentSQLOperations operations) {
SHARED_REACTIVE_OPERATIONS = operations;
}
/** /**
* 查询起手 * 查询起手
* *
@ -172,8 +186,10 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
* @return 处理链 * @return 处理链
*/ */
@Override @Override
public <T> BoundProxy<T> next() { @SuppressWarnings("unchecked")
return new DefaultBoundProxy<>(SQLEntity.of(primaryClass, this::sql, this::parsedParameters)); public <T> BoundProxy<T> fetch() {
// 通过主类构建实体
return new DefaultBoundProxy<>(BoundSQLEntity.of(this.entity, (Class<T>) primaryClass));
} }
/** /**
@ -211,7 +227,7 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
*/ */
@Override @Override
public <T> BoundProxy<T> as(Class<T> type) { public <T> BoundProxy<T> as(Class<T> type) {
return new DefaultBoundProxy<>(SQLEntity.of(type, wrap(this::sql), wrap(this::parsedParameters))); return new DefaultBoundProxy<>(BoundSQLEntity.of(this.entity, type));
} }
/** /**
@ -254,6 +270,15 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
return false; return false;
} }
/**
* 将本实体转换为sql实体
*
* @return 转换结果
*/
private SQLEntity entity() {
return SQLEntity.of(wrap(this::sql), wrap(this::parsedParameters));
}
@Override @Override
public PieceSqlChain limit(int count) { public PieceSqlChain limit(int count) {
return concat("LIMIT").concat(String.valueOf(count)); return concat("LIMIT").concat(String.valueOf(count));
@ -267,16 +292,16 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
@RequiredArgsConstructor @RequiredArgsConstructor
private static class DefaultBoundProxy<T> implements BoundProxy<T> { private static class DefaultBoundProxy<T> implements BoundProxy<T> {
private final SQLEntity<T> entity; private final BoundSQLEntity<T> entity;
@Override @Override
public BoundEntity<T> block() { public BoundEntitySpec<T> block() {
return new DefaultBoundEntity<>(); return new DefaultBoundEntitySpec<>(entity);
} }
@Override @Override
public ReactiveBoundEntity<T> reactive() { public ReactiveBoundEntitySpec<T> reactive() {
return new DefaultReactiveBoundEntity<>(); return new DefaultReactiveBoundEntitySpec<>(entity);
} }
} }
@ -285,49 +310,60 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
* *
* @param <T> * @param <T>
*/ */
private static class DefaultBoundEntity<T> implements BoundEntity<T> { @RequiredArgsConstructor
private static class DefaultBoundEntitySpec<T> implements BoundEntitySpec<T> {
private final BoundSQLEntity<T> entity;
@Override @Override
public T one() { public T one() {
return null; return SHARED_OPERATIONS.selectOne(entity);
} }
@Override @Override
public List<T> all() { public List<T> all() {
return List.of(); return SHARED_OPERATIONS.select(entity);
} }
@Override @Override
public DataPage<T> page() { public DataPage<T> page() {
return null; return SHARED_OPERATIONS.selectPage(entity);
} }
@Override @Override
public int execute() { public int execute() {
return 0; return SHARED_OPERATIONS.execute(entity);
} }
} }
private static class DefaultReactiveBoundEntity<T> implements ReactiveBoundEntity<T> { /**
* 默认的异步绑定实体
*
* @param <T> 泛型
*/
@RequiredArgsConstructor
private static class DefaultReactiveBoundEntitySpec<T> implements ReactiveBoundEntitySpec<T> {
private final BoundSQLEntity<T> entity;
@Override @Override
public Mono<T> one() { public Mono<T> one() {
return null; return SHARED_REACTIVE_OPERATIONS.selectOne(entity);
} }
@Override @Override
public Flux<T> all() { public Flux<T> all() {
return null; return SHARED_REACTIVE_OPERATIONS.select(entity);
} }
@Override @Override
public Mono<DataPage<T>> page() { public Mono<DataPage<T>> page() {
return null; return SHARED_REACTIVE_OPERATIONS.selectPage(entity);
} }
@Override @Override
public Mono<Integer> execute() { public Mono<Integer> execute() {
return null; return SHARED_REACTIVE_OPERATIONS.execute(entity);
} }
} }
} }

View File

@ -1,6 +1,5 @@
package group.flyfish.fluent.chain.common; package group.flyfish.fluent.chain.common;
import group.flyfish.fluent.chain.execution.BoundProxy;
/** /**
* 可执行的sql * 可执行的sql
@ -9,11 +8,5 @@ import group.flyfish.fluent.chain.execution.BoundProxy;
*/ */
public interface ExecutableSql { public interface ExecutableSql {
/**
* 进入下一步以主表作为输出结果
*
* @param <T> 泛型
* @return 绑定操作
*/
<T> BoundProxy<T> next();
} }

View File

@ -11,8 +11,7 @@ import java.util.List;
* *
* @author wangyu * @author wangyu
*/ */
public interface BoundEntity<T> { public interface BoundEntitySpec<T> {
/** /**
* 执行一条sql并且序列化为对象 * 执行一条sql并且序列化为对象

View File

@ -12,13 +12,13 @@ public interface BoundProxy<T> {
* *
* @return 结果 * @return 结果
*/ */
BoundEntity<T> block(); BoundEntitySpec<T> block();
/** /**
* 异步数据库逻辑 * 异步数据库逻辑
* *
* @return 结果 * @return 结果
*/ */
ReactiveBoundEntity<T> reactive(); ReactiveBoundEntitySpec<T> reactive();
} }

View File

@ -11,7 +11,7 @@ import reactor.core.publisher.Mono;
* *
* @author wangyu * @author wangyu
*/ */
public interface ReactiveBoundEntity<T> { public interface ReactiveBoundEntitySpec<T> {
/** /**
* 执行一条sql并且序列化为对象 * 执行一条sql并且序列化为对象

View File

@ -3,13 +3,21 @@ package group.flyfish.fluent.chain.select;
import group.flyfish.fluent.chain.common.ExecutableSql; import group.flyfish.fluent.chain.common.ExecutableSql;
import group.flyfish.fluent.chain.execution.BoundProxy; import group.flyfish.fluent.chain.execution.BoundProxy;
import java.util.List;
public interface FetchSqlChain extends ExecutableSql { public interface FetchSqlChain extends ExecutableSql {
/**
* 使用主表进行下一步操作
*
* @param <T> 泛型
* @return 结果
*/
<T> BoundProxy<T> fetch();
/** /**
* 转换为SQL实体 * 转换为SQL实体
* *
* @param type 具体结果类型
* @param <T> 泛型
* @return 结果 * @return 结果
*/ */
<T> BoundProxy<T> as(Class<T> type); <T> BoundProxy<T> as(Class<T> type);

View File

@ -0,0 +1,37 @@
package group.flyfish.fluent.entity;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.lang.NonNull;
import java.util.function.Supplier;
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class BoundSQLEntity<T> implements Supplier<String> {
@NonNull
private final Supplier<SQLEntity> entity;
// 结果类型
@NonNull
@Getter
private final Class<T> resultType;
public static <T> BoundSQLEntity<T> of(Supplier<SQLEntity> entity, Class<T> resultType) {
return new BoundSQLEntity<>(entity, resultType);
}
@Override
public String get() {
return entity.get().getSql();
}
public String getSql() {
return entity.get().getSql();
}
public Object[] getParameters() {
return entity.get().getParameters();
}
}

View File

@ -1,6 +1,5 @@
package group.flyfish.fluent.entity; package group.flyfish.fluent.entity;
import lombok.Getter;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -8,10 +7,9 @@ import java.util.function.Supplier;
/** /**
* sql运行实体 * sql运行实体
* *
* @param <T> 结果类型泛型
* @author wangyu * @author wangyu
*/ */
public class SQLEntity<T> { public class SQLEntity {
private static final Supplier<Object[]> EMPTY_PARAMETERS = () -> new Object[]{}; private static final Supplier<Object[]> EMPTY_PARAMETERS = () -> new Object[]{};
@ -22,23 +20,17 @@ public class SQLEntity<T> {
// sql参数表提供者 // sql参数表提供者
private final Supplier<Object[]> parameters; private final Supplier<Object[]> parameters;
// 结果类型 private SQLEntity(Supplier<String> sql, Supplier<Object[]> parameters) {
@NonNull
@Getter
private final Class<T> resultType;
private SQLEntity(Class<T> resultType, Supplier<String> sql, Supplier<Object[]> parameters) {
this.resultType = resultType;
this.sql = sql; this.sql = sql;
this.parameters = parameters; this.parameters = parameters;
} }
public static <T> SQLEntity<T> of(Class<T> resultType, Supplier<String> sqlProvider) { public static SQLEntity of(Supplier<String> sqlProvider) {
return of(resultType, sqlProvider, EMPTY_PARAMETERS); return of(sqlProvider, EMPTY_PARAMETERS);
} }
public static <T> SQLEntity<T> of(Class<T> resultType, Supplier<String> sql, Supplier<Object[]> parameters) { public static SQLEntity of(Supplier<String> sql, Supplier<Object[]> parameters) {
return new SQLEntity<T>(resultType, sql, parameters); return new SQLEntity(sql, parameters);
} }
public String getSql() { public String getSql() {

View File

@ -1,7 +1,7 @@
package group.flyfish.fluent.operations; package group.flyfish.fluent.operations;
import group.flyfish.fluent.entity.BoundSQLEntity;
import group.flyfish.fluent.entity.DataPage; import group.flyfish.fluent.entity.DataPage;
import group.flyfish.fluent.entity.SQLEntity;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import java.util.List; import java.util.List;
@ -23,7 +23,7 @@ public interface FluentSQLOperations {
* @return 查询结果 * @return 查询结果
*/ */
@Nullable @Nullable
<T> T selectOne(SQLEntity<T> entity); <T> T selectOne(BoundSQLEntity<T> entity);
/** /**
* 执行一条sql并且查询出所有行 * 执行一条sql并且查询出所有行
@ -32,7 +32,7 @@ public interface FluentSQLOperations {
* @param <T> 目标泛型 * @param <T> 目标泛型
* @return 返回的列表 * @return 返回的列表
*/ */
<T> List<T> select(SQLEntity<T> entity); <T> List<T> select(BoundSQLEntity<T> entity);
/** /**
* 分页查询 * 分页查询
@ -41,7 +41,7 @@ public interface FluentSQLOperations {
* @param <T> 目标泛型 * @param <T> 目标泛型
* @return 返回的分页对象 * @return 返回的分页对象
*/ */
<T> DataPage<T> selectPage(SQLEntity<T> entity); <T> DataPage<T> selectPage(BoundSQLEntity<T> entity);
/** /**
* 直接执行sql根据update count返回更新行数如果是查询永远返回0 * 直接执行sql根据update count返回更新行数如果是查询永远返回0
@ -49,5 +49,5 @@ public interface FluentSQLOperations {
* @param entity sql实体 * @param entity sql实体
* @return 更新行数 * @return 更新行数
*/ */
<T> int execute(SQLEntity<T> entity); <T> int execute(BoundSQLEntity<T> entity);
} }

View File

@ -1,5 +1,6 @@
package group.flyfish.fluent.operations; package group.flyfish.fluent.operations;
import group.flyfish.fluent.entity.BoundSQLEntity;
import group.flyfish.fluent.entity.DataPage; import group.flyfish.fluent.entity.DataPage;
import group.flyfish.fluent.entity.SQLEntity; import group.flyfish.fluent.entity.SQLEntity;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@ -23,7 +24,7 @@ public interface ReactiveFluentSQLOperations {
* @return 查询结果 * @return 查询结果
*/ */
@Nullable @Nullable
<T> Mono<T> selectOne(SQLEntity<T> entity); <T> Mono<T> selectOne(BoundSQLEntity<T> entity);
/** /**
* 执行一条sql并且查询出所有行 * 执行一条sql并且查询出所有行
@ -32,7 +33,7 @@ public interface ReactiveFluentSQLOperations {
* @param <T> 目标泛型 * @param <T> 目标泛型
* @return 返回的列表 * @return 返回的列表
*/ */
<T> Flux<T> select(SQLEntity<T> entity); <T> Flux<T> select(BoundSQLEntity<T> entity);
/** /**
* 分页查询 * 分页查询
@ -41,7 +42,7 @@ public interface ReactiveFluentSQLOperations {
* @param <T> 目标泛型 * @param <T> 目标泛型
* @return 返回的分页对象 * @return 返回的分页对象
*/ */
<T> Mono<DataPage<T>> selectPage(SQLEntity<T> entity); <T> Mono<DataPage<T>> selectPage(BoundSQLEntity<T> entity);
/** /**
* 直接执行sql根据update count返回更新行数如果是查询永远返回0 * 直接执行sql根据update count返回更新行数如果是查询永远返回0
@ -49,5 +50,5 @@ public interface ReactiveFluentSQLOperations {
* @param entity sql实体 * @param entity sql实体
* @return 更新行数 * @return 更新行数
*/ */
<T> Mono<Integer> execute(SQLEntity<T> entity); <T> Mono<Integer> execute(BoundSQLEntity<T> entity);
} }

View File

@ -1,20 +0,0 @@
package group.flyfish.fluent.utils.cache;
import java.util.function.Supplier;
/**
* 绑定的单值对象
*
* @param <T> 泛型
*/
public class BoundObject<T> {
private T object;
public T computeIfAbsent(Supplier<T> supplier) {
if (null == object) {
object = supplier.get();
}
return object;
}
}

View File

@ -4,6 +4,7 @@ import java.util.function.Supplier;
/** /**
* 缓存的supplier * 缓存的supplier
* 组件内部通过该核心逻辑缓存编译的sql
* *
* @author wangyu * @author wangyu
*/ */
@ -20,4 +21,22 @@ public interface CachedWrapper {
BoundObject<T> object = new BoundObject<>(); BoundObject<T> object = new BoundObject<>();
return () -> object.computeIfAbsent(supplier); return () -> object.computeIfAbsent(supplier);
} }
/**
* 绑定的单值对象
*
* @param <T> 泛型
*/
class BoundObject<T> {
private T object;
public T computeIfAbsent(Supplier<T> supplier) {
if (null == object) {
object = supplier.get();
}
return object;
}
}
} }

View File

@ -0,0 +1,112 @@
package group.flyfish.fluent.mapping;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import java.beans.PropertyDescriptor;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
/**
* 映射中的bean
*/
@Setter
@Slf4j
class MappingBean<T> {
private final T instance;
private final MappingDescriptor<T> descriptor;
private final BeanWrapper bw;
private boolean logged;
private Supplier<ConversionService> conversionService = DefaultConversionService::getSharedInstance;
private UnaryOperator<String> propertyTransformer = UnaryOperator.identity();
private BiFunction<String, Object, Object> transformer = (column, value) -> value;
/**
* 创建实例
*
* @return 结果
*/
static <T> MappingBean<T> create(MappingDescriptor<T> descriptor) {
T instance = BeanUtils.instantiateClass(descriptor.getMappedClass());
return new MappingBean<>(instance, descriptor);
}
private MappingBean(T instance, MappingDescriptor<T> descriptor) {
this.instance = instance;
this.descriptor = descriptor;
this.bw = new BeanWrapperImpl(instance);
initBeanWrapper(bw);
}
/**
* 初始化bean wrapper
*
* @param bw bean包装器
*/
protected void initBeanWrapper(BeanWrapper bw) {
ConversionService cs = conversionService.get();
if (cs != null) {
bw.setConversionService(cs);
}
}
/**
* 设置bean的值
*
* @param column 属性名
* @param value
*/
void setValue(String column, ValueProvider value) throws Exception {
String findName = getProperty(column);
if (StringUtils.hasText(findName)) {
PropertyDescriptor pd = descriptor.getMappedFields().get(findName);
if (null == pd) return;
String name = pd.getName();
if (!logged) {
logged = true;
if (log.isDebugEnabled()) {
log.debug("Mapping column '{}' to property '{}' of type '{}'", column, name,
ClassUtils.getQualifiedName(pd.getPropertyType()));
}
}
// 尝试获取值
Object mappedValue = transformer.apply(name, value.get(pd.getPropertyType()));
// 尝试设置
bw.setPropertyValue(name, mappedValue);
}
}
/**
* 获取真正的列名
*
* @param column
* @return 结果
*/
String getProperty(String column) {
return propertyTransformer.apply(column);
}
/**
* 获取设置后的实体
*
* @return 结果
*/
T get() {
return instance;
}
}

View File

@ -0,0 +1,187 @@
package group.flyfish.fluent.mapping;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import group.flyfish.fluent.binding.Alias;
import group.flyfish.fluent.binding.JSONInject;
import group.flyfish.fluent.utils.data.ObjectMappers;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* 特定类型的映射解释器
*
* @param <T> 泛型
*/
@Getter
@Slf4j
class MappingDescriptor<T> {
private final ObjectMapper objectMapper = ObjectMappers.shared();
/**
* The class we are mapping to.
*/
private Class<T> mappedClass;
/**
* Map of the fields we provide mapping for.
*/
private final Map<String, PropertyDescriptor> mappedFields;
/**
* Map of the fields which need json convert
*/
private final Map<String, Class<?>> jsonFields;
static <T> MappingDescriptor<T> of(Class<T> mappedClass) {
return new MappingDescriptor<>(mappedClass);
}
private MappingDescriptor(Class<T> mappedClass) {
Assert.state(mappedClass != null, "Mapped class was not specified");
this.mappedClass = mappedClass;
this.mappedFields = new HashMap<>();
this.jsonFields = new HashMap<>();
initialize();
}
private void initialize() {
Map<String, MergedAnnotations> fieldAnnotations = new HashMap<>();
ReflectionUtils.doWithFields(mappedClass, field -> fieldAnnotations.put(field.getName(), MergedAnnotations.from(field)));
for (PropertyDescriptor pd : BeanUtils.getPropertyDescriptors(mappedClass)) {
if (pd.getWriteMethod() != null) {
MergedAnnotations annotations = fieldAnnotations.get(pd.getName());
String lowerCaseName;
if (annotations.isPresent(Alias.class)) {
String rawName = annotations.get(Alias.class).synthesize().value();
lowerCaseName = lowerCaseName(rawName.replace("_", ""));
} else {
lowerCaseName = lowerCaseName(pd.getName());
}
this.mappedFields.put(lowerCaseName, pd);
String underscoreName = underscoreName(pd.getName());
if (!lowerCaseName.equals(underscoreName)) {
this.mappedFields.put(underscoreName, pd);
}
// 添加json字段
if (annotations.isPresent(JSONInject.class)) {
this.jsonFields.put(pd.getName(), pd.getPropertyType());
}
}
}
}
MappingBean<T> create() {
MappingBean<T> bean = MappingBean.create(this);
bean.setTransformer(this::convertPropertyIfNeed);
bean.setPropertyTransformer(this::lowerCaseName);
return bean;
}
/**
* Remove the specified property from the mapped fields.
*
* @param propertyName the property name (as used by property descriptors)
* @since 5.3.9
*/
private void suppressProperty(String propertyName) {
if (this.mappedFields != null) {
this.mappedFields.remove(lowerCaseName(propertyName));
this.mappedFields.remove(underscoreName(propertyName));
}
}
/**
* Convert the given name to lower case.
* By default, conversions will happen within the US locale.
*
* @param name the original name
* @return the converted name
* @since 4.2
*/
private String lowerCaseName(String name) {
return StringUtils.delete(name, " ").toLowerCase(Locale.US);
}
/**
* Convert a name in camelCase to an underscored name in lower case.
* Any upper case letters are converted to lower case with a preceding underscore.
*
* @param name the original name
* @return the converted name
* @see #lowerCaseName
* @since 4.2
*/
private String underscoreName(String name) {
if (!StringUtils.hasLength(name)) {
return "";
}
StringBuilder result = new StringBuilder();
result.append(Character.toLowerCase(name.charAt(0)));
for (int i = 1; i < name.length(); i++) {
char c = name.charAt(i);
if (Character.isUpperCase(c)) {
result.append('_').append(Character.toLowerCase(c));
} else {
result.append(c);
}
}
return result.toString();
}
/**
* Set the class that each row should be mapped to.
*/
void setMappedClass(Class<T> mappedClass) {
if (this.mappedClass == null) {
this.mappedClass = mappedClass;
initialize();
} else {
if (this.mappedClass != mappedClass) {
throw new InvalidDataAccessApiUsageException("The mapped class can not be reassigned to map to " +
mappedClass + " since it is already providing mapping for " + this.mappedClass);
}
}
}
private Object convertPropertyIfNeed(String name, Object value) {
if (jsonFields.containsKey(name)) {
value = convert(value, jsonFields.get(name));
}
return value;
}
/**
* 转换json对象
*
* @param type 目标类型
* @param value
* @return 结果
*/
private Object convert(Object value, Class<?> type) {
if (value instanceof String) {
try {
return objectMapper.readValue((String) value, type);
} catch (JsonProcessingException e) {
log.error("转换json为对象时出错{}", e.getMessage());
return null;
}
}
return value;
}
}

View File

@ -0,0 +1,62 @@
package group.flyfish.fluent.mapping;
import io.r2dbc.spi.Row;
import io.r2dbc.spi.RowMetadata;
import org.springframework.dao.DataRetrievalFailureException;
import java.util.function.BiFunction;
/**
* 异步支持的sql映射支持json映射
*
* @param <T> 泛型
*/
public class ReactiveSQLMappedRowMapper<T> implements BiFunction<Row, RowMetadata, T> {
/**
* the actual logic for conversation
*/
private final MappingDescriptor<T> descriptor;
/**
* Create a new {@code BeanPropertyRowMapper}, accepting unpopulated
* properties in the target bean.
*
* @param mappedClass the class that each row should be mapped to
*/
private ReactiveSQLMappedRowMapper(Class<T> mappedClass) {
this.descriptor = MappingDescriptor.of(mappedClass);
}
/**
* Static factory method to create a new {@code BeanPropertyRowMapper}.
*
* @param mappedClass the class that each row should be mapped to
*/
public static <T> ReactiveSQLMappedRowMapper<T> newInstance(Class<T> mappedClass) {
return new ReactiveSQLMappedRowMapper<>(mappedClass);
}
/**
* Applies this function to the given arguments.
*
* @param row the first function argument
* @param rowMetadata the second function argument
* @return the function result
*/
@Override
public T apply(Row row, RowMetadata rowMetadata) {
MappingBean<T> bean = descriptor.create();
for (String column : rowMetadata.getColumnNames()) {
try {
bean.setValue(column, type -> row.get(column, type));
} catch (Exception ex) {
throw new DataRetrievalFailureException(
"Unable to map column '" + column + "' to property '" + bean.getProperty(column) + "'", ex);
}
}
return bean.get();
}
}

View File

@ -1,32 +1,14 @@
package group.flyfish.fluent.mapping; package group.flyfish.fluent.mapping;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import group.flyfish.fluent.binding.Alias;
import group.flyfish.fluent.binding.JSONInject;
import group.flyfish.fluent.utils.data.ObjectMappers;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.*;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.dao.DataRetrievalFailureException; import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.JdbcUtils; import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.beans.PropertyDescriptor;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/** /**
* 基于SQL映射的行映射器 * 基于SQL映射的行映射器
@ -37,27 +19,10 @@ import java.util.Map;
@Slf4j @Slf4j
public class SQLMappedRowMapper<T> implements RowMapper<T> { public class SQLMappedRowMapper<T> implements RowMapper<T> {
private final ObjectMapper objectMapper = ObjectMappers.shared();
/** /**
* The class we are mapping to. * the actual logic for conversation
*/ */
@Nullable private final MappingDescriptor<T> descriptor;
private Class<T> mappedClass;
/**
* ConversionService for binding JDBC values to bean properties.
*/
@Nullable
private ConversionService conversionService = DefaultConversionService.getSharedInstance();
/**
* Map of the fields we provide mapping for.
*/
@Nullable
private Map<String, PropertyDescriptor> mappedFields;
/**
* Map of the fields which need json convert
*/
private Map<String, Class<?>> jsonFields;
/** /**
* Create a new {@code BeanPropertyRowMapper}, accepting unpopulated * Create a new {@code BeanPropertyRowMapper}, accepting unpopulated
@ -66,171 +31,18 @@ public class SQLMappedRowMapper<T> implements RowMapper<T> {
* @param mappedClass the class that each row should be mapped to * @param mappedClass the class that each row should be mapped to
*/ */
public SQLMappedRowMapper(Class<T> mappedClass) { public SQLMappedRowMapper(Class<T> mappedClass) {
initialize(mappedClass); this.descriptor = MappingDescriptor.of(mappedClass);
} }
/** /**
* Static factory method to create a new {@code BeanPropertyRowMapper}. * Static factory method to create a new {@code BeanPropertyRowMapper}.
* *
* @param mappedClass the class that each row should be mapped to * @param mappedClass the class that each row should be mapped to
* @see #newInstance(Class, ConversionService)
*/ */
public static <T> SQLMappedRowMapper<T> newInstance(Class<T> mappedClass) { public static <T> SQLMappedRowMapper<T> newInstance(Class<T> mappedClass) {
return new SQLMappedRowMapper<>(mappedClass); return new SQLMappedRowMapper<>(mappedClass);
} }
/**
* Static factory method to create a new {@code BeanPropertyRowMapper}.
*
* @param mappedClass the class that each row should be mapped to
* @param conversionService the {@link ConversionService} for binding
* JDBC values to bean properties, or {@code null} for none
* @see #newInstance(Class)
* @see #setConversionService
* @since 5.2.3
*/
public static <T> SQLMappedRowMapper<T> newInstance(
Class<T> mappedClass, @Nullable ConversionService conversionService) {
SQLMappedRowMapper<T> rowMapper = newInstance(mappedClass);
rowMapper.setConversionService(conversionService);
return rowMapper;
}
/**
* Get the class that we are mapping to.
*/
@Nullable
public final Class<T> getMappedClass() {
return this.mappedClass;
}
/**
* Set the class that each row should be mapped to.
*/
public void setMappedClass(Class<T> mappedClass) {
if (this.mappedClass == null) {
initialize(mappedClass);
} else {
if (this.mappedClass != mappedClass) {
throw new InvalidDataAccessApiUsageException("The mapped class can not be reassigned to map to " +
mappedClass + " since it is already providing mapping for " + this.mappedClass);
}
}
}
/**
* Return a {@link ConversionService} for binding JDBC values to bean properties,
* or {@code null} if none.
*
* @since 4.3
*/
@Nullable
public ConversionService getConversionService() {
return this.conversionService;
}
/**
* Set a {@link ConversionService} for binding JDBC values to bean properties,
* or {@code null} for none.
* <p>Default is a {@link DefaultConversionService}, as of Spring 4.3. This
* provides support for {@code java.time} conversion and other special types.
*
* @see #initBeanWrapper(BeanWrapper)
* @since 4.3
*/
public void setConversionService(@Nullable ConversionService conversionService) {
this.conversionService = conversionService;
}
/**
* Initialize the mapping meta-data for the given class.
*
* @param mappedClass the mapped class
*/
protected void initialize(Class<T> mappedClass) {
this.mappedClass = mappedClass;
this.mappedFields = new HashMap<>();
this.jsonFields = new HashMap<>();
Map<String, MergedAnnotations> fieldAnnotations = new HashMap<>();
ReflectionUtils.doWithFields(mappedClass, field -> fieldAnnotations.put(field.getName(), MergedAnnotations.from(field)));
for (PropertyDescriptor pd : BeanUtils.getPropertyDescriptors(mappedClass)) {
if (pd.getWriteMethod() != null) {
MergedAnnotations annotations = fieldAnnotations.get(pd.getName());
String lowerCaseName;
if (annotations.isPresent(Alias.class)) {
String rawName = annotations.get(Alias.class).synthesize().value();
lowerCaseName = lowerCaseName(rawName.replace("_", ""));
} else {
lowerCaseName = lowerCaseName(pd.getName());
}
this.mappedFields.put(lowerCaseName, pd);
String underscoreName = underscoreName(pd.getName());
if (!lowerCaseName.equals(underscoreName)) {
this.mappedFields.put(underscoreName, pd);
}
// 添加json字段
if (annotations.isPresent(JSONInject.class)) {
this.jsonFields.put(pd.getName(), pd.getPropertyType());
}
}
}
}
/**
* Remove the specified property from the mapped fields.
*
* @param propertyName the property name (as used by property descriptors)
* @since 5.3.9
*/
protected void suppressProperty(String propertyName) {
if (this.mappedFields != null) {
this.mappedFields.remove(lowerCaseName(propertyName));
this.mappedFields.remove(underscoreName(propertyName));
}
}
/**
* Convert the given name to lower case.
* By default, conversions will happen within the US locale.
*
* @param name the original name
* @return the converted name
* @since 4.2
*/
protected String lowerCaseName(String name) {
return name.toLowerCase(Locale.US);
}
/**
* Convert a name in camelCase to an underscored name in lower case.
* Any upper case letters are converted to lower case with a preceding underscore.
*
* @param name the original name
* @return the converted name
* @see #lowerCaseName
* @since 4.2
*/
protected String underscoreName(String name) {
if (!StringUtils.hasLength(name)) {
return "";
}
StringBuilder result = new StringBuilder();
result.append(Character.toLowerCase(name.charAt(0)));
for (int i = 1; i < name.length(); i++) {
char c = name.charAt(i);
if (Character.isUpperCase(c)) {
result.append('_').append(Character.toLowerCase(c));
} else {
result.append(c);
}
}
return result.toString();
}
/** /**
* Extract the values for all columns in the current row. * Extract the values for all columns in the current row.
* <p>Utilizes public setters and result set meta-data. * <p>Utilizes public setters and result set meta-data.
@ -239,124 +51,28 @@ public class SQLMappedRowMapper<T> implements RowMapper<T> {
*/ */
@Override @Override
public T mapRow(ResultSet rs, int rowNumber) throws SQLException { public T mapRow(ResultSet rs, int rowNumber) throws SQLException {
BeanWrapperImpl bw = new BeanWrapperImpl(); MappingBean<T> bean = descriptor.create();
initBeanWrapper(bw);
T mappedObject = constructMappedInstance(rs, bw);
bw.setBeanInstance(mappedObject);
ResultSetMetaData rsmd = rs.getMetaData(); ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount(); int columnCount = rsmd.getColumnCount();
for (int index = 1; index <= columnCount; index++) { for (int i = 1; i <= columnCount; i++) {
String column = JdbcUtils.lookupColumnName(rsmd, index); String column = JdbcUtils.lookupColumnName(rsmd, i);
String field = lowerCaseName(StringUtils.delete(column, " ")); try {
PropertyDescriptor pd = (this.mappedFields != null ? this.mappedFields.get(field) : null); final int index = i;
if (pd != null) { bean.setValue(column, type -> getColumnValue(rs, index, type));
try { } catch (Exception ex) {
Object value = getColumnValue(rs, index, pd); throw new DataRetrievalFailureException(
if (rowNumber == 0 && log.isDebugEnabled()) { "Unable to map column '" + column + "' to property '" + bean.getProperty(column) + "'", ex);
log.debug("Mapping column '" + column + "' to property '" + pd.getName() +
"' of type '" + ClassUtils.getQualifiedName(pd.getPropertyType()) + "'");
}
if (jsonFields.containsKey(pd.getName())) {
value = convert(value, jsonFields.get(pd.getName()));
}
bw.setPropertyValue(pd.getName(), value);
} catch (NotWritablePropertyException ex) {
throw new DataRetrievalFailureException(
"Unable to map column '" + column + "' to property '" + pd.getName() + "'", ex);
}
} }
} }
return mappedObject; return bean.get();
} }
/**
* Construct an instance of the mapped class for the current row.
*
* @param rs the ResultSet to map (pre-initialized for the current row)
* @param tc a TypeConverter with this RowMapper's conversion service
* @return a corresponding instance of the mapped class
* @throws SQLException if an SQLException is encountered
* @since 5.3
*/
protected T constructMappedInstance(ResultSet rs, TypeConverter tc) throws SQLException {
Assert.state(this.mappedClass != null, "Mapped class was not specified");
return BeanUtils.instantiateClass(this.mappedClass);
}
/**
* Initialize the given BeanWrapper to be used for row mapping.
* To be called for each row.
* <p>The default implementation applies the configured {@link ConversionService},
* if any. Can be overridden in subclasses.
*
* @param bw the BeanWrapper to initialize
* @see #getConversionService()
* @see BeanWrapper#setConversionService
*/
protected void initBeanWrapper(BeanWrapper bw) {
ConversionService cs = getConversionService();
if (cs != null) {
bw.setConversionService(cs);
}
}
/**
* Retrieve a JDBC object value for the specified column.
* <p>The default implementation delegates to
* {@link #getColumnValue(ResultSet, int, Class)}.
*
* @param rs is the ResultSet holding the data
* @param index is the column index
* @param pd the bean property that each result object is expected to match
* @return the Object value
* @throws SQLException in case of extraction failure
* @see #getColumnValue(ResultSet, int, Class)
*/
@Nullable
protected Object getColumnValue(ResultSet rs, int index, PropertyDescriptor pd) throws SQLException {
return JdbcUtils.getResultSetValue(rs, index, pd.getPropertyType());
}
/**
* Retrieve a JDBC object value for the specified column.
* <p>The default implementation calls
* {@link JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class)}.
* Subclasses may override this to check specific value types upfront,
* or to post-process values return from {@code getResultSetValue}.
*
* @param rs is the ResultSet holding the data
* @param index is the column index
* @param paramType the target parameter type
* @return the Object value
* @throws SQLException in case of extraction failure
* @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class)
* @since 5.3
*/
@Nullable @Nullable
protected Object getColumnValue(ResultSet rs, int index, Class<?> paramType) throws SQLException { protected Object getColumnValue(ResultSet rs, int index, Class<?> paramType) throws SQLException {
return JdbcUtils.getResultSetValue(rs, index, paramType); return JdbcUtils.getResultSetValue(rs, index, paramType);
} }
/**
* 转换json对象
*
* @param type 目标类型
* @param value
* @return 结果
*/
private Object convert(Object value, Class<?> type) {
if (value instanceof String) {
try {
return objectMapper.readValue((String) value, type);
} catch (JsonProcessingException e) {
log.error("转换json为对象时出错{}", e.getMessage());
return null;
}
}
return value;
}
} }

View File

@ -0,0 +1,17 @@
package group.flyfish.fluent.mapping;
/**
* 值提供者
*
* @author wangyu
*/
interface ValueProvider {
/**
* 通过具体类型获取值
*
* @param type 类型
* @return 结果
*/
Object get(Class<?> type) throws Exception;
}

View File

@ -1,8 +1,8 @@
package group.flyfish.fluent.operations; package group.flyfish.fluent.operations;
import group.flyfish.fluent.chain.SQL; import group.flyfish.fluent.chain.SQL;
import group.flyfish.fluent.entity.BoundSQLEntity;
import group.flyfish.fluent.entity.DataPage; import group.flyfish.fluent.entity.DataPage;
import group.flyfish.fluent.entity.SQLEntity;
import group.flyfish.fluent.mapping.SQLMappedRowMapper; import group.flyfish.fluent.mapping.SQLMappedRowMapper;
import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.JdbcOperations;
@ -40,13 +40,14 @@ public class JdbcTemplateFluentSQLOperations implements FluentSQLOperations {
*/ */
@Override @Override
@SuppressWarnings("all") @SuppressWarnings("all")
public <T> T selectOne(SQLEntity entity, Class<T> clazz) { public <T> T selectOne(BoundSQLEntity<T> entity) {
try { try {
String sql = entity.getSql(); String sql = entity.getSql();
if (ClassUtils.isPrimitiveOrWrapper(clazz)) { Class<T> type = entity.getResultType();
return jdbcOperations.queryForObject(sql, clazz, entity.getParameters()); if (ClassUtils.isPrimitiveOrWrapper(type)) {
return jdbcOperations.queryForObject(sql, type, entity.getParameters());
} }
return jdbcOperations.queryForObject(sql, new SQLMappedRowMapper<>(clazz), entity.getParameters()); return jdbcOperations.queryForObject(sql, SQLMappedRowMapper.newInstance(type), entity.getParameters());
} catch (EmptyResultDataAccessException e) { } catch (EmptyResultDataAccessException e) {
return null; return null;
} }
@ -56,27 +57,26 @@ public class JdbcTemplateFluentSQLOperations implements FluentSQLOperations {
* 执行一条sql并且查询出所有行 * 执行一条sql并且查询出所有行
* *
* @param entity sql实体 * @param entity sql实体
* @param clazz 目标类型
* @return 返回的列表 * @return 返回的列表
*/ */
@Override @Override
public <T> List<T> select(SQLEntity entity, Class<T> clazz) { public <T> List<T> select(BoundSQLEntity<T> entity) {
String sql = entity.getSql(); String sql = entity.getSql();
if (ClassUtils.isPrimitiveOrWrapper(clazz)) { Class<T> type = entity.getResultType();
return jdbcOperations.queryForList(sql, clazz, entity.getParameters()); if (ClassUtils.isPrimitiveOrWrapper(type)) {
return jdbcOperations.queryForList(sql, type, entity.getParameters());
} }
return jdbcOperations.query(sql, new SQLMappedRowMapper<>(clazz), entity.getParameters()); return jdbcOperations.query(sql, SQLMappedRowMapper.newInstance(type), entity.getParameters());
} }
/** /**
* 分页查询 * 分页查询
* *
* @param entity sql实体 * @param entity sql实体
* @param clazz 目标类型
* @return 返回的分页对象 * @return 返回的分页对象
*/ */
@Override @Override
public <T> DataPage<T> selectPage(SQLEntity entity, Class<T> clazz) { public <T> DataPage<T> selectPage(BoundSQLEntity<T> entity) {
return null; return null;
} }
@ -87,7 +87,7 @@ public class JdbcTemplateFluentSQLOperations implements FluentSQLOperations {
* @return 更新行数 * @return 更新行数
*/ */
@Override @Override
public int execute(SQLEntity entity) { public int execute(BoundSQLEntity entity) {
return jdbcOperations.update(entity.getSql(), entity.getParameters()); return jdbcOperations.update(entity.getSql(), entity.getParameters());
} }
} }

View File

@ -1,9 +1,11 @@
package group.flyfish.fluent.operations; package group.flyfish.fluent.operations;
import group.flyfish.fluent.entity.BoundSQLEntity;
import group.flyfish.fluent.entity.DataPage; import group.flyfish.fluent.entity.DataPage;
import group.flyfish.fluent.entity.SQLEntity; import group.flyfish.fluent.mapping.ReactiveSQLMappedRowMapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.r2dbc.core.DatabaseClient; import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.r2dbc.core.RowsFetchSpec;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
@ -18,36 +20,34 @@ public class R2dbcFluentSQLOperations implements ReactiveFluentSQLOperations {
* 如果没有结果将返回null * 如果没有结果将返回null
* *
* @param entity sql实体 * @param entity sql实体
* @param clazz 目标类型
* @return 查询结果 * @return 查询结果
*/ */
@Override @Override
public <T> Mono<T> selectOne(SQLEntity entity, Class<T> clazz) { public <T> Mono<T> selectOne(BoundSQLEntity<T> entity) {
return null; return forSelect(entity).one();
} }
/** /**
* 执行一条sql并且查询出所有行 * 执行一条sql并且查询出所有行
* *
* @param entity sql实体 * @param entity sql实体
* @param clazz 目标类型
* @return 返回的列表 * @return 返回的列表
*/ */
@Override @Override
public <T> Flux<T> select(SQLEntity entity, Class<T> clazz) { public <T> Flux<T> select(BoundSQLEntity<T> entity) {
return null; return forSelect(entity).all();
} }
/** /**
* 分页查询 * 分页查询
* *
* @param entity sql实体 * @param entity sql实体
* @param clazz 目标类型
* @return 返回的分页对象 * @return 返回的分页对象
*/ */
@Override @Override
public <T> Mono<DataPage<T>> selectPage(SQLEntity entity, Class<T> clazz) { public <T> Mono<DataPage<T>> selectPage(BoundSQLEntity<T> entity) {
return null; return Mono.empty();
} }
/** /**
@ -57,7 +57,29 @@ public class R2dbcFluentSQLOperations implements ReactiveFluentSQLOperations {
* @return 更新行数 * @return 更新行数
*/ */
@Override @Override
public Mono<Integer> execute(SQLEntity entity) { public <T> Mono<Integer> execute(BoundSQLEntity<T> entity) {
return null; return resolve(entity).fetch().rowsUpdated();
}
/**
* 解析sql实体
*
* @param entity 实体信息
* @return 结果
*/
private <T> DatabaseClient.GenericExecuteSpec resolve(BoundSQLEntity<T> entity) {
DatabaseClient.GenericExecuteSpec spec = databaseClient.sql(entity);
Object[] parameters = entity.getParameters();
if (null != parameters) {
for (int i = 0; i < parameters.length; i++) {
spec = spec.bind(i, parameters[i]);
}
}
return spec;
}
private <T> RowsFetchSpec<T> forSelect(BoundSQLEntity<T> entity) {
return resolve(entity)
.map(ReactiveSQLMappedRowMapper.newInstance(entity.getResultType()));
} }
} }

View File

@ -2,7 +2,6 @@ package group.flyfish.framework.cases;
import group.flyfish.fluent.chain.select.AfterWhereSqlChain; import group.flyfish.fluent.chain.select.AfterWhereSqlChain;
import group.flyfish.fluent.operations.JdbcTemplateFluentSQLOperations; import group.flyfish.fluent.operations.JdbcTemplateFluentSQLOperations;
import group.flyfish.fluent.utils.cache.CachedWrapper;
import group.flyfish.framework.TestCase; import group.flyfish.framework.TestCase;
import group.flyfish.framework.entity.SaasOrder; import group.flyfish.framework.entity.SaasOrder;
import group.flyfish.framework.entity.SaasPlan; import group.flyfish.framework.entity.SaasPlan;
@ -12,7 +11,6 @@ import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.util.List; import java.util.List;
import java.util.function.Supplier;
import static group.flyfish.fluent.chain.SQL.select; import static group.flyfish.fluent.chain.SQL.select;
import static group.flyfish.fluent.chain.select.SelectComposite.composite; import static group.flyfish.fluent.chain.select.SelectComposite.composite;
@ -61,6 +59,6 @@ public class FluentSqlTestCase extends AbstractTestCase<List<TenantContext>> {
@Override @Override
public List<TenantContext> run() throws Exception { public List<TenantContext> run() throws Exception {
// 一个平平无奇的查询 // 一个平平无奇的查询
return sql.list(TenantContext.class); return sql.as(TenantContext.class).block().all();
} }
} }

View File

@ -1,5 +1,6 @@
package group.flyfish.framework.cases; package group.flyfish.framework.cases;
import group.flyfish.fluent.chain.execution.BoundProxy;
import group.flyfish.framework.TestCase; import group.flyfish.framework.TestCase;
import group.flyfish.framework.entity.SaasTenant; import group.flyfish.framework.entity.SaasTenant;
@ -38,6 +39,7 @@ public class SingleTableTestCase extends AbstractTestCase<List<SaasTenant>> {
@Override @Override
public List<SaasTenant> run() throws Exception { public List<SaasTenant> run() throws Exception {
// 单表查询 // 单表查询
return select().from(SaasTenant.class).list(); BoundProxy<SaasTenant> proxy = select().from(SaasTenant.class).fetch();
return proxy.block().all();
} }
} }

View File

@ -38,8 +38,8 @@
<maven.compiler.source>8</maven.compiler.source> <maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target> <maven.compiler.target>8</maven.compiler.target>
<lombok.version>1.18.24</lombok.version> <lombok.version>1.18.24</lombok.version>
<jackson.version>2.13.3</jackson.version> <jackson.version>2.17.2</jackson.version>
<spring-boot.version>2.7.2</spring-boot.version> <spring-boot.version>2.7.18</spring-boot.version>
<spring.version>5.3.22</spring.version> <spring.version>5.3.22</spring.version>
</properties> </properties>