Compare commits
No commits in common. "ff4637535ac89862fb5e2d99aa26c3ba9665f9d3" and "1b61e132056e16394f3a0913dd857e747d504cb9" have entirely different histories.
ff4637535a
...
1b61e13205
@ -40,7 +40,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<artifactId>fluent-sql-spring-boot-starter</artifactId>
|
<artifactId>fluent-sql-spring-boot-starter</artifactId>
|
||||||
<groupId>group.flyfish.framework</groupId>
|
<groupId>group.flyfish.framework</groupId>
|
||||||
<version>0.1.0</version>
|
<version>0.0.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -50,7 +50,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<artifactId>fluent-sql-spring-jdbc</artifactId>
|
<artifactId>fluent-sql-spring-jdbc</artifactId>
|
||||||
<groupId>group.flyfish.framework</groupId>
|
<groupId>group.flyfish.framework</groupId>
|
||||||
<version>0.1.0</version>
|
<version>0.0.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>fluent-sql</artifactId>
|
<artifactId>fluent-sql</artifactId>
|
||||||
<groupId>group.flyfish.framework</groupId>
|
<groupId>group.flyfish.framework</groupId>
|
||||||
<version>0.1.0</version>
|
<version>0.0.5</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>fluent-sql</artifactId>
|
<artifactId>fluent-sql</artifactId>
|
||||||
<groupId>group.flyfish.framework</groupId>
|
<groupId>group.flyfish.framework</groupId>
|
||||||
<version>0.1.0</version>
|
<version>0.0.5</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ package group.flyfish.fluent.chain;
|
|||||||
import group.flyfish.fluent.chain.common.PreSqlChain;
|
import group.flyfish.fluent.chain.common.PreSqlChain;
|
||||||
import group.flyfish.fluent.chain.select.SelectComposite;
|
import group.flyfish.fluent.chain.select.SelectComposite;
|
||||||
import group.flyfish.fluent.operations.FluentSQLOperations;
|
import group.flyfish.fluent.operations.FluentSQLOperations;
|
||||||
import group.flyfish.fluent.operations.ReactiveFluentSQLOperations;
|
|
||||||
import group.flyfish.fluent.update.Update;
|
import group.flyfish.fluent.update.Update;
|
||||||
import group.flyfish.fluent.utils.sql.SFunction;
|
import group.flyfish.fluent.utils.sql.SFunction;
|
||||||
|
|
||||||
@ -62,13 +61,4 @@ public interface SQL {
|
|||||||
static void bind(FluentSQLOperations operations) {
|
static void bind(FluentSQLOperations operations) {
|
||||||
SQLImpl.bind(operations);
|
SQLImpl.bind(operations);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 绑定数据源上下文,可自由切换实现
|
|
||||||
*
|
|
||||||
* @param operations jdbc操作
|
|
||||||
*/
|
|
||||||
static void bind(ReactiveFluentSQLOperations operations) {
|
|
||||||
SQLImpl.bind(operations);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,17 @@ 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.BoundEntitySpec;
|
import group.flyfish.fluent.chain.execution.BoundEntity;
|
||||||
import group.flyfish.fluent.chain.execution.BoundProxy;
|
import group.flyfish.fluent.chain.execution.BoundProxy;
|
||||||
import group.flyfish.fluent.chain.execution.ReactiveBoundEntitySpec;
|
import group.flyfish.fluent.chain.execution.ReactiveBoundEntity;
|
||||||
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;
|
||||||
@ -50,8 +48,6 @@ 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<>();
|
||||||
|
|
||||||
@ -59,7 +55,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::entity);
|
private final Supplier<SQLEntity> entity = wrap(this::toEntity);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 绑定实现类
|
* 绑定实现类
|
||||||
@ -70,16 +66,6 @@ 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询起手
|
* 查询起手
|
||||||
*
|
*
|
||||||
@ -186,10 +172,8 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
|
|||||||
* @return 处理链
|
* @return 处理链
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
public <T> BoundProxy<T> next() {
|
||||||
public <T> BoundProxy<T> fetch() {
|
return new DefaultBoundProxy<>(SQLEntity.of(primaryClass, this::sql, this::parsedParameters));
|
||||||
// 通过主类构建实体
|
|
||||||
return new DefaultBoundProxy<>(BoundSQLEntity.of(this.entity, (Class<T>) primaryClass));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -227,7 +211,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<>(BoundSQLEntity.of(this.entity, type));
|
return new DefaultBoundProxy<>(SQLEntity.of(type, wrap(this::sql), wrap(this::parsedParameters)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -236,6 +220,7 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
|
|||||||
* @return 构建结果
|
* @return 构建结果
|
||||||
*/
|
*/
|
||||||
private String sql() {
|
private String sql() {
|
||||||
|
Assert.notNull(SHARED_OPERATIONS, "未指定执行数据源!");
|
||||||
String sql = segments.stream().map(SQLSegment::get).collect(Collectors.joining(" "));
|
String sql = segments.stream().map(SQLSegment::get).collect(Collectors.joining(" "));
|
||||||
if (FluentSqlDebugger.enabled()) {
|
if (FluentSqlDebugger.enabled()) {
|
||||||
System.out.println("prepared sql: " + sql);
|
System.out.println("prepared sql: " + sql);
|
||||||
@ -269,15 +254,6 @@ 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));
|
||||||
@ -291,16 +267,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 BoundSQLEntity<T> entity;
|
private final SQLEntity<T> entity;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BoundEntitySpec<T> block() {
|
public BoundEntity<T> block() {
|
||||||
return new DefaultBoundEntitySpec<>(entity);
|
return new DefaultBoundEntity<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ReactiveBoundEntitySpec<T> reactive() {
|
public ReactiveBoundEntity<T> reactive() {
|
||||||
return new DefaultReactiveBoundEntitySpec<>(entity);
|
return new DefaultReactiveBoundEntity<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,68 +285,49 @@ final class SQLImpl extends ConcatSegment<SQLImpl> implements SQLOperations, Pre
|
|||||||
*
|
*
|
||||||
* @param <T>
|
* @param <T>
|
||||||
*/
|
*/
|
||||||
private static class DefaultBoundEntitySpec<T> implements BoundEntitySpec<T> {
|
private static class DefaultBoundEntity<T> implements BoundEntity<T> {
|
||||||
|
|
||||||
private final BoundSQLEntity<T> entity;
|
|
||||||
|
|
||||||
private DefaultBoundEntitySpec(BoundSQLEntity<T> entity) {
|
|
||||||
Assert.notNull(SHARED_OPERATIONS, "未指定执行数据源!");
|
|
||||||
this.entity = entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T one() {
|
public T one() {
|
||||||
return SHARED_OPERATIONS.selectOne(entity);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<T> all() {
|
public List<T> all() {
|
||||||
return SHARED_OPERATIONS.select(entity);
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataPage<T> page() {
|
public DataPage<T> page() {
|
||||||
return SHARED_OPERATIONS.selectPage(entity);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int execute() {
|
public int execute() {
|
||||||
return SHARED_OPERATIONS.execute(entity);
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static class DefaultReactiveBoundEntity<T> implements ReactiveBoundEntity<T> {
|
||||||
* 默认的异步绑定实体
|
|
||||||
*
|
|
||||||
* @param <T> 泛型
|
|
||||||
*/
|
|
||||||
private static class DefaultReactiveBoundEntitySpec<T> implements ReactiveBoundEntitySpec<T> {
|
|
||||||
|
|
||||||
private final BoundSQLEntity<T> entity;
|
|
||||||
|
|
||||||
private DefaultReactiveBoundEntitySpec(BoundSQLEntity<T> entity) {
|
|
||||||
Assert.notNull(SHARED_REACTIVE_OPERATIONS, "未指定执行数据源!");
|
|
||||||
this.entity = entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<T> one() {
|
public Mono<T> one() {
|
||||||
return SHARED_REACTIVE_OPERATIONS.selectOne(entity);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<T> all() {
|
public Flux<T> all() {
|
||||||
return SHARED_REACTIVE_OPERATIONS.select(entity);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<DataPage<T>> page() {
|
public Mono<DataPage<T>> page() {
|
||||||
return SHARED_REACTIVE_OPERATIONS.selectPage(entity);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Integer> execute() {
|
public Mono<Integer> execute() {
|
||||||
return SHARED_REACTIVE_OPERATIONS.execute(entity);
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package group.flyfish.fluent.chain.common;
|
package group.flyfish.fluent.chain.common;
|
||||||
|
|
||||||
|
import group.flyfish.fluent.chain.execution.BoundProxy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 可执行的sql
|
* 可执行的sql
|
||||||
@ -8,5 +9,11 @@ package group.flyfish.fluent.chain.common;
|
|||||||
*/
|
*/
|
||||||
public interface ExecutableSql {
|
public interface ExecutableSql {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进入下一步,以主表作为输出结果
|
||||||
|
*
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @return 绑定操作
|
||||||
|
*/
|
||||||
|
<T> BoundProxy<T> next();
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,8 @@ import java.util.List;
|
|||||||
*
|
*
|
||||||
* @author wangyu
|
* @author wangyu
|
||||||
*/
|
*/
|
||||||
public interface BoundEntitySpec<T> {
|
public interface BoundEntity<T> {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行一条sql,并且序列化为对象
|
* 执行一条sql,并且序列化为对象
|
@ -12,13 +12,13 @@ public interface BoundProxy<T> {
|
|||||||
*
|
*
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
BoundEntitySpec<T> block();
|
BoundEntity<T> block();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步数据库逻辑
|
* 异步数据库逻辑
|
||||||
*
|
*
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
ReactiveBoundEntitySpec<T> reactive();
|
ReactiveBoundEntity<T> reactive();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import reactor.core.publisher.Mono;
|
|||||||
*
|
*
|
||||||
* @author wangyu
|
* @author wangyu
|
||||||
*/
|
*/
|
||||||
public interface ReactiveBoundEntitySpec<T> {
|
public interface ReactiveBoundEntity<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行一条sql,并且序列化为对象
|
* 执行一条sql,并且序列化为对象
|
@ -3,21 +3,13 @@ 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;
|
||||||
|
|
||||||
public interface FetchSqlChain extends ExecutableSql {
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
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);
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,6 @@
|
|||||||
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;
|
||||||
@ -7,9 +8,10 @@ import java.util.function.Supplier;
|
|||||||
/**
|
/**
|
||||||
* sql运行实体
|
* sql运行实体
|
||||||
*
|
*
|
||||||
|
* @param <T> 结果类型泛型
|
||||||
* @author wangyu
|
* @author wangyu
|
||||||
*/
|
*/
|
||||||
public class SQLEntity {
|
public class SQLEntity<T> {
|
||||||
|
|
||||||
private static final Supplier<Object[]> EMPTY_PARAMETERS = () -> new Object[]{};
|
private static final Supplier<Object[]> EMPTY_PARAMETERS = () -> new Object[]{};
|
||||||
|
|
||||||
@ -20,17 +22,23 @@ public class SQLEntity {
|
|||||||
// 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 SQLEntity of(Supplier<String> sqlProvider) {
|
public static <T> SQLEntity<T> of(Class<T> resultType, Supplier<String> sqlProvider) {
|
||||||
return of(sqlProvider, EMPTY_PARAMETERS);
|
return of(resultType, sqlProvider, EMPTY_PARAMETERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SQLEntity of(Supplier<String> sql, Supplier<Object[]> parameters) {
|
public static <T> SQLEntity<T> of(Class<T> resultType, Supplier<String> sql, Supplier<Object[]> parameters) {
|
||||||
return new SQLEntity(sql, parameters);
|
return new SQLEntity<T>(resultType, sql, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSql() {
|
public String getSql() {
|
||||||
|
@ -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(BoundSQLEntity<T> entity);
|
<T> T selectOne(SQLEntity<T> entity);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行一条sql,并且查询出所有行
|
* 执行一条sql,并且查询出所有行
|
||||||
@ -32,7 +32,7 @@ public interface FluentSQLOperations {
|
|||||||
* @param <T> 目标泛型
|
* @param <T> 目标泛型
|
||||||
* @return 返回的列表
|
* @return 返回的列表
|
||||||
*/
|
*/
|
||||||
<T> List<T> select(BoundSQLEntity<T> entity);
|
<T> List<T> select(SQLEntity<T> entity);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页查询
|
* 分页查询
|
||||||
@ -41,7 +41,7 @@ public interface FluentSQLOperations {
|
|||||||
* @param <T> 目标泛型
|
* @param <T> 目标泛型
|
||||||
* @return 返回的分页对象
|
* @return 返回的分页对象
|
||||||
*/
|
*/
|
||||||
<T> DataPage<T> selectPage(BoundSQLEntity<T> entity);
|
<T> DataPage<T> selectPage(SQLEntity<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(BoundSQLEntity<T> entity);
|
<T> int execute(SQLEntity<T> entity);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
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;
|
||||||
@ -24,7 +23,7 @@ public interface ReactiveFluentSQLOperations {
|
|||||||
* @return 查询结果
|
* @return 查询结果
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
<T> Mono<T> selectOne(BoundSQLEntity<T> entity);
|
<T> Mono<T> selectOne(SQLEntity<T> entity);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行一条sql,并且查询出所有行
|
* 执行一条sql,并且查询出所有行
|
||||||
@ -33,7 +32,7 @@ public interface ReactiveFluentSQLOperations {
|
|||||||
* @param <T> 目标泛型
|
* @param <T> 目标泛型
|
||||||
* @return 返回的列表
|
* @return 返回的列表
|
||||||
*/
|
*/
|
||||||
<T> Flux<T> select(BoundSQLEntity<T> entity);
|
<T> Flux<T> select(SQLEntity<T> entity);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页查询
|
* 分页查询
|
||||||
@ -42,7 +41,7 @@ public interface ReactiveFluentSQLOperations {
|
|||||||
* @param <T> 目标泛型
|
* @param <T> 目标泛型
|
||||||
* @return 返回的分页对象
|
* @return 返回的分页对象
|
||||||
*/
|
*/
|
||||||
<T> Mono<DataPage<T>> selectPage(BoundSQLEntity<T> entity);
|
<T> Mono<DataPage<T>> selectPage(SQLEntity<T> entity);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 直接执行sql,根据update count返回更新行数,如果是查询,永远返回0
|
* 直接执行sql,根据update count返回更新行数,如果是查询,永远返回0
|
||||||
@ -50,5 +49,5 @@ public interface ReactiveFluentSQLOperations {
|
|||||||
* @param entity sql实体
|
* @param entity sql实体
|
||||||
* @return 更新行数
|
* @return 更新行数
|
||||||
*/
|
*/
|
||||||
<T> Mono<Integer> execute(BoundSQLEntity<T> entity);
|
<T> Mono<Integer> execute(SQLEntity<T> entity);
|
||||||
}
|
}
|
||||||
|
20
fluent-sql-core/src/main/java/group/flyfish/fluent/utils/cache/BoundObject.java
vendored
Normal file
20
fluent-sql-core/src/main/java/group/flyfish/fluent/utils/cache/BoundObject.java
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,6 @@ import java.util.function.Supplier;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 缓存的supplier
|
* 缓存的supplier
|
||||||
* 组件内部通过该核心逻辑缓存编译的sql
|
|
||||||
*
|
*
|
||||||
* @author wangyu
|
* @author wangyu
|
||||||
*/
|
*/
|
||||||
@ -21,22 +20,4 @@ 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>fluent-sql</artifactId>
|
<artifactId>fluent-sql</artifactId>
|
||||||
<groupId>group.flyfish.framework</groupId>
|
<groupId>group.flyfish.framework</groupId>
|
||||||
<version>0.1.0</version>
|
<version>0.0.5</version>
|
||||||
</parent>
|
</parent>
|
||||||
<description>spring boot 快速集成组件</description>
|
<description>spring boot 快速集成组件</description>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>fluent-sql</artifactId>
|
<artifactId>fluent-sql</artifactId>
|
||||||
<groupId>group.flyfish.framework</groupId>
|
<groupId>group.flyfish.framework</groupId>
|
||||||
<version>0.1.0</version>
|
<version>0.0.5</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@ -46,12 +46,6 @@
|
|||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>io.asyncer</groupId>
|
|
||||||
<artifactId>r2dbc-mysql</artifactId>
|
|
||||||
<version>0.9.7</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-context</artifactId>
|
<artifactId>spring-context</artifactId>
|
||||||
|
@ -1,112 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,187 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +1,32 @@
|
|||||||
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映射的行映射器
|
||||||
@ -19,10 +37,27 @@ import java.sql.SQLException;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class SQLMappedRowMapper<T> implements RowMapper<T> {
|
public class SQLMappedRowMapper<T> implements RowMapper<T> {
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper = ObjectMappers.shared();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the actual logic for conversation
|
* The class we are mapping to.
|
||||||
*/
|
*/
|
||||||
private final MappingDescriptor<T> descriptor;
|
@Nullable
|
||||||
|
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
|
||||||
@ -31,18 +66,171 @@ 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) {
|
||||||
this.descriptor = MappingDescriptor.of(mappedClass);
|
initialize(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.
|
||||||
@ -51,28 +239,124 @@ 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 {
|
||||||
MappingBean<T> bean = descriptor.create();
|
BeanWrapperImpl bw = new BeanWrapperImpl();
|
||||||
|
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 i = 1; i <= columnCount; i++) {
|
for (int index = 1; index <= columnCount; index++) {
|
||||||
String column = JdbcUtils.lookupColumnName(rsmd, i);
|
String column = JdbcUtils.lookupColumnName(rsmd, index);
|
||||||
|
String field = lowerCaseName(StringUtils.delete(column, " "));
|
||||||
|
PropertyDescriptor pd = (this.mappedFields != null ? this.mappedFields.get(field) : null);
|
||||||
|
if (pd != null) {
|
||||||
try {
|
try {
|
||||||
final int index = i;
|
Object value = getColumnValue(rs, index, pd);
|
||||||
bean.setValue(column, type -> getColumnValue(rs, index, type));
|
if (rowNumber == 0 && log.isDebugEnabled()) {
|
||||||
} catch (Exception 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(
|
throw new DataRetrievalFailureException(
|
||||||
"Unable to map column '" + column + "' to property '" + bean.getProperty(column) + "'", ex);
|
"Unable to map column '" + column + "' to property '" + pd.getName() + "'", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bean.get();
|
return mappedObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package group.flyfish.fluent.mapping;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 值提供者
|
|
||||||
*
|
|
||||||
* @author wangyu
|
|
||||||
*/
|
|
||||||
interface ValueProvider {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过具体类型获取值
|
|
||||||
*
|
|
||||||
* @param type 类型
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
Object get(Class<?> type) throws Exception;
|
|
||||||
}
|
|
@ -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,14 +40,13 @@ public class JdbcTemplateFluentSQLOperations implements FluentSQLOperations {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
public <T> T selectOne(BoundSQLEntity<T> entity) {
|
public <T> T selectOne(SQLEntity entity, Class<T> clazz) {
|
||||||
try {
|
try {
|
||||||
String sql = entity.getSql();
|
String sql = entity.getSql();
|
||||||
Class<T> type = entity.getResultType();
|
if (ClassUtils.isPrimitiveOrWrapper(clazz)) {
|
||||||
if (ClassUtils.isPrimitiveOrWrapper(type)) {
|
return jdbcOperations.queryForObject(sql, clazz, entity.getParameters());
|
||||||
return jdbcOperations.queryForObject(sql, type, entity.getParameters());
|
|
||||||
}
|
}
|
||||||
return jdbcOperations.queryForObject(sql, SQLMappedRowMapper.newInstance(type), entity.getParameters());
|
return jdbcOperations.queryForObject(sql, new SQLMappedRowMapper<>(clazz), entity.getParameters());
|
||||||
} catch (EmptyResultDataAccessException e) {
|
} catch (EmptyResultDataAccessException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -57,26 +56,27 @@ public class JdbcTemplateFluentSQLOperations implements FluentSQLOperations {
|
|||||||
* 执行一条sql,并且查询出所有行
|
* 执行一条sql,并且查询出所有行
|
||||||
*
|
*
|
||||||
* @param entity sql实体
|
* @param entity sql实体
|
||||||
|
* @param clazz 目标类型
|
||||||
* @return 返回的列表
|
* @return 返回的列表
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T> List<T> select(BoundSQLEntity<T> entity) {
|
public <T> List<T> select(SQLEntity entity, Class<T> clazz) {
|
||||||
String sql = entity.getSql();
|
String sql = entity.getSql();
|
||||||
Class<T> type = entity.getResultType();
|
if (ClassUtils.isPrimitiveOrWrapper(clazz)) {
|
||||||
if (ClassUtils.isPrimitiveOrWrapper(type)) {
|
return jdbcOperations.queryForList(sql, clazz, entity.getParameters());
|
||||||
return jdbcOperations.queryForList(sql, type, entity.getParameters());
|
|
||||||
}
|
}
|
||||||
return jdbcOperations.query(sql, SQLMappedRowMapper.newInstance(type), entity.getParameters());
|
return jdbcOperations.query(sql, new SQLMappedRowMapper<>(clazz), entity.getParameters());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页查询
|
* 分页查询
|
||||||
*
|
*
|
||||||
* @param entity sql实体
|
* @param entity sql实体
|
||||||
|
* @param clazz 目标类型
|
||||||
* @return 返回的分页对象
|
* @return 返回的分页对象
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T> DataPage<T> selectPage(BoundSQLEntity<T> entity) {
|
public <T> DataPage<T> selectPage(SQLEntity entity, Class<T> clazz) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ public class JdbcTemplateFluentSQLOperations implements FluentSQLOperations {
|
|||||||
* @return 更新行数
|
* @return 更新行数
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int execute(BoundSQLEntity entity) {
|
public int execute(SQLEntity entity) {
|
||||||
return jdbcOperations.update(entity.getSql(), entity.getParameters());
|
return jdbcOperations.update(entity.getSql(), entity.getParameters());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,57 +1,53 @@
|
|||||||
package group.flyfish.fluent.operations;
|
package group.flyfish.fluent.operations;
|
||||||
|
|
||||||
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.mapping.ReactiveSQLMappedRowMapper;
|
import group.flyfish.fluent.entity.SQLEntity;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class R2dbcFluentSQLOperations implements ReactiveFluentSQLOperations {
|
public class R2dbcFluentSQLOperations implements ReactiveFluentSQLOperations {
|
||||||
|
|
||||||
private final DatabaseClient databaseClient;
|
private final DatabaseClient databaseClient;
|
||||||
|
|
||||||
public R2dbcFluentSQLOperations(DatabaseClient databaseClient) {
|
|
||||||
this.databaseClient = databaseClient;
|
|
||||||
SQL.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行一条sql,并且序列化为对象
|
* 执行一条sql,并且序列化为对象
|
||||||
* 注意,如果查询不止一条,该方法仅返回第一条数据
|
* 注意,如果查询不止一条,该方法仅返回第一条数据
|
||||||
* 如果没有结果,将返回null
|
* 如果没有结果,将返回null
|
||||||
*
|
*
|
||||||
* @param entity sql实体
|
* @param entity sql实体
|
||||||
|
* @param clazz 目标类型
|
||||||
* @return 查询结果
|
* @return 查询结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T> Mono<T> selectOne(BoundSQLEntity<T> entity) {
|
public <T> Mono<T> selectOne(SQLEntity entity, Class<T> clazz) {
|
||||||
return forSelect(entity).one();
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行一条sql,并且查询出所有行
|
* 执行一条sql,并且查询出所有行
|
||||||
*
|
*
|
||||||
* @param entity sql实体
|
* @param entity sql实体
|
||||||
|
* @param clazz 目标类型
|
||||||
* @return 返回的列表
|
* @return 返回的列表
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T> Flux<T> select(BoundSQLEntity<T> entity) {
|
public <T> Flux<T> select(SQLEntity entity, Class<T> clazz) {
|
||||||
return forSelect(entity).all();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页查询
|
* 分页查询
|
||||||
*
|
*
|
||||||
* @param entity sql实体
|
* @param entity sql实体
|
||||||
|
* @param clazz 目标类型
|
||||||
* @return 返回的分页对象
|
* @return 返回的分页对象
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T> Mono<DataPage<T>> selectPage(BoundSQLEntity<T> entity) {
|
public <T> Mono<DataPage<T>> selectPage(SQLEntity entity, Class<T> clazz) {
|
||||||
return Mono.empty();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,29 +57,7 @@ public class R2dbcFluentSQLOperations implements ReactiveFluentSQLOperations {
|
|||||||
* @return 更新行数
|
* @return 更新行数
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T> Mono<Integer> execute(BoundSQLEntity<T> entity) {
|
public Mono<Integer> execute(SQLEntity entity) {
|
||||||
return resolve(entity).fetch().rowsUpdated();
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析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()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
package group.flyfish.framework;
|
|
||||||
|
|
||||||
import group.flyfish.fluent.chain.select.FetchSqlChain;
|
|
||||||
import group.flyfish.fluent.operations.R2dbcFluentSQLOperations;
|
|
||||||
import group.flyfish.framework.entity.SaasOrder;
|
|
||||||
import group.flyfish.framework.entity.SaasPlan;
|
|
||||||
import group.flyfish.framework.entity.SaasTenant;
|
|
||||||
import group.flyfish.framework.vo.TenantContext;
|
|
||||||
import io.asyncer.r2dbc.mysql.MySqlConnectionConfiguration;
|
|
||||||
import io.asyncer.r2dbc.mysql.MySqlConnectionFactory;
|
|
||||||
import io.r2dbc.spi.ConnectionFactory;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.springframework.r2dbc.core.DatabaseClient;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
import static group.flyfish.fluent.chain.SQL.select;
|
|
||||||
import static group.flyfish.fluent.chain.select.SelectComposite.composite;
|
|
||||||
import static group.flyfish.fluent.query.Query.where;
|
|
||||||
|
|
||||||
public class FluentR2dbcTest {
|
|
||||||
|
|
||||||
private FetchSqlChain sql;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 静态测试demo
|
|
||||||
* 实际测试请根据自己的数据库字段书写实体
|
|
||||||
*
|
|
||||||
* @throws SQLException sql异常
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testSql() {
|
|
||||||
MySqlConnectionConfiguration configuration = MySqlConnectionConfiguration.builder()
|
|
||||||
.host("localhost")
|
|
||||||
.port(3306)
|
|
||||||
.database("epi_project")
|
|
||||||
.user("root")
|
|
||||||
.password("Unicom#2018")
|
|
||||||
.build();
|
|
||||||
ConnectionFactory connectionFactory = MySqlConnectionFactory.from(configuration);
|
|
||||||
DatabaseClient databaseClient = DatabaseClient.builder().connectionFactory(connectionFactory)
|
|
||||||
.build();
|
|
||||||
new R2dbcFluentSQLOperations(databaseClient);
|
|
||||||
|
|
||||||
// 缓存构建结果
|
|
||||||
this.sql = select(
|
|
||||||
// 查询租户全量字段
|
|
||||||
composite(SaasTenant::getId, SaasTenant::getName, SaasTenant::getIdentifier, SaasTenant::getDatasource,
|
|
||||||
SaasTenant::getStorage, SaasTenant::getStatus, SaasTenant::getEnable),
|
|
||||||
// 查询套餐
|
|
||||||
composite(SaasOrder::getQuotaConfig, SaasOrder::getOrderTime, SaasOrder::getExpireTime,
|
|
||||||
SaasOrder::getOrderType))
|
|
||||||
.from(SaasTenant.class)
|
|
||||||
.leftJoin(SaasOrder.class).on(where(SaasOrder::getTenantId).eq(SaasTenant::getId))
|
|
||||||
.leftJoin(SaasPlan.class).on(where(SaasPlan::getId).eq(SaasOrder::getPlanId))
|
|
||||||
.matching(where(SaasTenant::getEnable).eq(true));
|
|
||||||
|
|
||||||
System.out.println(sql.as(TenantContext.class).reactive().all()
|
|
||||||
.collectList()
|
|
||||||
.block());
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,6 +2,7 @@ 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;
|
||||||
@ -11,6 +12,7 @@ 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;
|
||||||
@ -59,6 +61,6 @@ public class FluentSqlTestCase extends AbstractTestCase<List<TenantContext>> {
|
|||||||
@Override
|
@Override
|
||||||
public List<TenantContext> run() throws Exception {
|
public List<TenantContext> run() throws Exception {
|
||||||
// 一个平平无奇的查询
|
// 一个平平无奇的查询
|
||||||
return sql.as(TenantContext.class).block().all();
|
return sql.list(TenantContext.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
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;
|
||||||
|
|
||||||
@ -39,7 +38,6 @@ public class SingleTableTestCase extends AbstractTestCase<List<SaasTenant>> {
|
|||||||
@Override
|
@Override
|
||||||
public List<SaasTenant> run() throws Exception {
|
public List<SaasTenant> run() throws Exception {
|
||||||
// 单表查询
|
// 单表查询
|
||||||
BoundProxy<SaasTenant> proxy = select().from(SaasTenant.class).fetch();
|
return select().from(SaasTenant.class).list();
|
||||||
return proxy.block().all();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
6
pom.xml
6
pom.xml
@ -7,7 +7,7 @@
|
|||||||
<groupId>group.flyfish.framework</groupId>
|
<groupId>group.flyfish.framework</groupId>
|
||||||
<artifactId>fluent-sql</artifactId>
|
<artifactId>fluent-sql</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<version>0.1.0</version>
|
<version>0.0.5</version>
|
||||||
|
|
||||||
<name>fluent-sql</name>
|
<name>fluent-sql</name>
|
||||||
<description>A very fast sql generation engine using fluent-style api. Help you start your work without mybatis!</description>
|
<description>A very fast sql generation engine using fluent-style api. Help you start your work without mybatis!</description>
|
||||||
@ -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.17.2</jackson.version>
|
<jackson.version>2.13.3</jackson.version>
|
||||||
<spring-boot.version>2.7.18</spring-boot.version>
|
<spring-boot.version>2.7.2</spring-boot.version>
|
||||||
<spring.version>5.3.22</spring.version>
|
<spring.version>5.3.22</spring.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user