-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add: 新增easy-orm对clickhouse支持 #1
Open
PengyuDeng
wants to merge
16
commits into
hs-web:main
Choose a base branch
from
PengyuDeng:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
efc3a90
add: 新增对easy-orm对clickhouse支持
PengyuDeng ce44317
fix: 把编译过程转换为程序
PengyuDeng c046f58
fix: 修改clickhouse的介入方式
PengyuDeng 8f8b887
feat: 修改pom文件及gitignore
PengyuDeng f855a1d
fix: 解决clickhouse无法脱离easyorm相关配置文件使用的问题
PengyuDeng 3b79b74
add: 对clickhouse数据类型支持
PengyuDeng 70057e8
fix: 修改date关键字的类型
PengyuDeng 5a8fa4a
fix: 修改执行SQL日志级别
PengyuDeng e39e1d7
fix: 修改检查结果的顺序。
PengyuDeng 6ad7bf0
fix: 修复数据插入不进去的错误
PengyuDeng bffd0fc
add .gitignore
PengyuDeng 0f2c2d9
fix: 优化Service获取class
PengyuDeng 72d3914
fix: 优化封装查询数据后的返回值
PengyuDeng 385ab77
add: 增加clickhouse同步执行器
PengyuDeng 9af65be
fix: 重写仓库
PengyuDeng 2cd2c51
fix: 修复语法
PengyuDeng File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<groupId>org.hswebframework</groupId> | ||
<artifactId>hsweb-incubator-easyorm-clickhouse</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
|
||
<properties> | ||
<maven.compiler.source>8</maven.compiler.source> | ||
<maven.compiler.target>8</maven.compiler.target> | ||
<hsweb.framework.version>4.0.17-SNAPSHOT</hsweb.framework.version> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.hswebframework.web</groupId> | ||
<artifactId>hsweb-commons-crud</artifactId> | ||
<version>${hsweb.framework.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework</groupId> | ||
<artifactId>spring-webflux</artifactId> | ||
<version>5.3.25</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
</project> |
69 changes: 69 additions & 0 deletions
69
src/main/java/org/hswebframework/ezorm/rdb/metadata/dialect/Dialect.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package org.hswebframework.ezorm.rdb.metadata.dialect; | ||
|
||
import org.hswebframework.ezorm.core.meta.Feature; | ||
import org.hswebframework.ezorm.core.utils.StringUtils; | ||
import org.hswebframework.ezorm.rdb.metadata.DataType; | ||
import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata; | ||
import org.hswebframework.ezorm.rdb.metadata.RDBFeatureType; | ||
import org.hswebframework.ezorm.rdb.metadata.dialect.DataTypeBuilder; | ||
import org.hswebframework.ezorm.rdb.supports.clickhouse.ClickhouseDialect; | ||
|
||
import java.sql.SQLType; | ||
import java.util.Optional; | ||
|
||
/** | ||
* @author dengpengyu | ||
* @date 2023/9/18 16:14 | ||
*/ | ||
public interface Dialect extends Feature { | ||
|
||
@Override | ||
default RDBFeatureType getType() { | ||
return RDBFeatureType.dialect; | ||
} | ||
|
||
void addDataTypeBuilder(String typeId, DataTypeBuilder mapper); | ||
|
||
String buildColumnDataType(RDBColumnMetadata columnMetaData); | ||
|
||
String getQuoteStart(); | ||
|
||
String getQuoteEnd(); | ||
|
||
String clearQuote(String string); | ||
|
||
boolean isColumnToUpperCase(); | ||
|
||
Optional<SQLType> convertSqlType(Class<?> type); | ||
|
||
DataType convertDataType(String dataType); | ||
|
||
default String quote(String keyword, boolean changeCase) { | ||
if (keyword.startsWith(getQuoteStart()) && keyword.endsWith(getQuoteEnd())) { | ||
return keyword; | ||
} | ||
return StringUtils.concat( | ||
getQuoteStart(), | ||
isColumnToUpperCase() && changeCase ? keyword.toUpperCase() : keyword, | ||
getQuoteEnd() | ||
); | ||
} | ||
|
||
default String quote(String keyword) { | ||
return quote(keyword, true); | ||
} | ||
|
||
default String buildColumnFullName(String tableName, String columnName) { | ||
if (columnName.contains(".")) { | ||
return columnName; | ||
} | ||
if (StringUtils.isNullOrEmpty(tableName)) { | ||
return StringUtils.concat(getQuoteStart(), isColumnToUpperCase() ? columnName.toUpperCase() : columnName, getQuoteEnd()); | ||
} | ||
return StringUtils.concat(tableName, ".", getQuoteStart(), isColumnToUpperCase() ? columnName.toUpperCase() : columnName, getQuoteEnd()); | ||
} | ||
|
||
ClickhouseDialect CLICKHOUSE = new ClickhouseDialect(); | ||
|
||
} | ||
|
84 changes: 84 additions & 0 deletions
84
src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package org.hswebframework.ezorm.rdb.supports.clickhouse; | ||
|
||
import org.hswebframework.ezorm.core.utils.StringUtils; | ||
import org.hswebframework.ezorm.rdb.metadata.DataType; | ||
import org.hswebframework.ezorm.rdb.metadata.JdbcDataType; | ||
import org.hswebframework.ezorm.rdb.metadata.dialect.DefaultDialect; | ||
|
||
import java.sql.Date; | ||
import java.sql.JDBCType; | ||
|
||
/** | ||
* @className ClickhouseDire | ||
* @Description TODO | ||
* @Author dengpengyu | ||
* @Date 2023/9/4 14:53 | ||
* @Vesion 1.0 | ||
*/ | ||
public class ClickhouseDialect extends DefaultDialect { | ||
|
||
public ClickhouseDialect() { | ||
super(); | ||
addDataTypeBuilder(JDBCType.CHAR, (meta) -> StringUtils.concat("char(", meta.getLength(), ")")); | ||
addDataTypeBuilder(JDBCType.VARCHAR, (meta) -> StringUtils.concat("varchar(", meta.getLength(), ")")); | ||
addDataTypeBuilder(JDBCType.NVARCHAR, (meta) -> StringUtils.concat("nvarchar(", meta.getLength(), ")")); | ||
|
||
addDataTypeBuilder(JDBCType.TIMESTAMP, (meta) -> "datetime(" + Math.min(6, meta.getLength()) + ")"); | ||
addDataTypeBuilder(JDBCType.TIME, (meta) -> "time"); | ||
addDataTypeBuilder(JDBCType.DATE, (meta) -> "date"); | ||
addDataTypeBuilder(JDBCType.CLOB, (meta) -> "text"); | ||
addDataTypeBuilder(JDBCType.LONGVARBINARY, (meta) -> "blob"); | ||
addDataTypeBuilder(JDBCType.LONGVARCHAR, (meta) -> "longtext"); | ||
addDataTypeBuilder(JDBCType.BLOB, (meta) -> "blob"); | ||
addDataTypeBuilder(JDBCType.BIGINT, (meta) -> "bigint"); | ||
addDataTypeBuilder(JDBCType.DOUBLE, (meta) -> "double"); | ||
addDataTypeBuilder(JDBCType.INTEGER, (meta) -> "int"); | ||
addDataTypeBuilder(JDBCType.NUMERIC, (meta) -> StringUtils.concat("decimal(", meta.getPrecision(32), ",", meta.getScale(), ")")); | ||
addDataTypeBuilder(JDBCType.DECIMAL, (meta) -> StringUtils.concat("decimal(", meta.getPrecision(32), ",", meta.getScale(), ")")); | ||
addDataTypeBuilder(JDBCType.TINYINT, (meta) -> "tinyint"); | ||
addDataTypeBuilder(JDBCType.BOOLEAN, (meta) -> "tinyint"); | ||
addDataTypeBuilder(JDBCType.BIGINT, (meta) -> "bigint"); | ||
addDataTypeBuilder(JDBCType.OTHER, (meta) -> "other"); | ||
addDataTypeBuilder(JDBCType.LONGNVARCHAR, (meta) -> "text"); | ||
|
||
addDataTypeBuilder("int", (meta) -> "int"); | ||
addDataTypeBuilder("json", meta -> "json"); | ||
|
||
registerDataType("clob", DataType.builder(JdbcDataType.of(JDBCType.CLOB, String.class), c -> "text")); | ||
registerDataType("longnvarchar", DataType.builder(JdbcDataType.of(JDBCType.LONGNVARCHAR, String.class), c -> "longtext")); | ||
registerDataType("longvarchar", DataType.builder(JdbcDataType.of(JDBCType.LONGVARCHAR, String.class), c -> "longtext")); | ||
|
||
registerDataType("int", JdbcDataType.of(JDBCType.INTEGER, Integer.class)); | ||
registerDataType("text", JdbcDataType.of(JDBCType.CLOB, String.class)); | ||
registerDataType("longtext", JdbcDataType.of(JDBCType.LONGVARCHAR, String.class)); | ||
registerDataType("year", JdbcDataType.of(JDBCType.DATE, Date.class)); | ||
registerDataType("text", JdbcDataType.of(JDBCType.CLOB, Date.class)); | ||
registerDataType("datetime", JdbcDataType.of(JDBCType.TIMESTAMP, Date.class)); | ||
|
||
} | ||
|
||
@Override | ||
public String getQuoteStart() { | ||
return "`"; | ||
} | ||
|
||
@Override | ||
public String getQuoteEnd() { | ||
return "`"; | ||
} | ||
|
||
@Override | ||
public boolean isColumnToUpperCase() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public String getId() { | ||
return "clickhouse"; | ||
} | ||
|
||
@Override | ||
public String getName() { | ||
return "Clickhouse"; | ||
} | ||
} |
140 changes: 140 additions & 0 deletions
140
...n/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package org.hswebframework.ezorm.rdb.supports.clickhouse; | ||
|
||
import com.alibaba.fastjson.JSON; | ||
import com.alibaba.fastjson.JSONArray; | ||
import com.alibaba.fastjson.JSONObject; | ||
import org.hswebframework.ezorm.rdb.executor.BatchSqlRequest; | ||
import org.hswebframework.ezorm.rdb.executor.DefaultColumnWrapperContext; | ||
import org.hswebframework.ezorm.rdb.executor.SqlRequest; | ||
import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSqlExecutor; | ||
import org.hswebframework.ezorm.rdb.executor.wrapper.ResultWrapper; | ||
import org.reactivestreams.Publisher; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.util.CollectionUtils; | ||
import org.springframework.web.reactive.function.client.WebClient; | ||
import reactor.core.publisher.Flux; | ||
import reactor.core.publisher.Mono; | ||
|
||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
/** | ||
* @className ClickhouseRestfulSqlExecutor | ||
* @Description TODO | ||
* @Author dengpengyu | ||
* @Date 2023/9/4 14:40 | ||
* @Vesion 1.0 | ||
*/ | ||
public class ClickhouseRestfulSqlExecutor implements ReactiveSqlExecutor { | ||
private Logger log = LoggerFactory.getLogger(ClickhouseRestfulSqlExecutor.class); | ||
private WebClient client; | ||
|
||
public ClickhouseRestfulSqlExecutor(WebClient client) { | ||
this.client = client; | ||
} | ||
|
||
@Override | ||
public Mono<Integer> update(Publisher<SqlRequest> request) { | ||
return this | ||
.doExecute(request) | ||
.then(Mono.just(1)); | ||
} | ||
|
||
@Override | ||
public Mono<Void> execute(Publisher<SqlRequest> request) { | ||
return this | ||
.doExecute(request) | ||
.then(); | ||
} | ||
|
||
@Override | ||
public <E> Flux<E> select(Publisher<SqlRequest> request, ResultWrapper<E, ?> wrapper) { | ||
|
||
return this | ||
.doExecute(request) | ||
.flatMap(response -> convertQueryResult(response, wrapper)); | ||
} | ||
|
||
private Flux<JSONObject> doExecute(Publisher<SqlRequest> requests) { | ||
return Flux | ||
.from(requests) | ||
.expand(request -> { | ||
if (request instanceof BatchSqlRequest) { | ||
return Flux.fromIterable(((BatchSqlRequest) request).getBatch()); | ||
} | ||
return Flux.empty(); | ||
}) | ||
|
||
.filter(SqlRequest::isNotEmpty) | ||
.concatMap(request -> { | ||
String sql; | ||
if (request.toNativeSql().toUpperCase().startsWith("INSERT") | ||
|| request.toNativeSql().toUpperCase().startsWith("ALTER")) { | ||
sql = request.toNativeSql(); | ||
} else { | ||
sql = request.toNativeSql() + " FORMAT JSON"; | ||
} | ||
log.info("Execute ==> {}", sql); | ||
return client | ||
.post() | ||
.bodyValue(sql) | ||
.exchangeToMono(response -> response | ||
.bodyToMono(String.class) | ||
.map(json -> { | ||
checkExecuteResult(sql, json); | ||
JSONObject result = JSON.parseObject(json); | ||
|
||
return result; | ||
})); | ||
}); | ||
} | ||
|
||
private void checkExecuteResult(String sql, String code) { | ||
if (code.startsWith("Code")) { | ||
throw new RuntimeException(code); | ||
} | ||
} | ||
|
||
protected <E> Flux<E> convertQueryResult(JSONObject result, ResultWrapper<E, ?> wrapper) { | ||
|
||
JSONArray head = result.getJSONArray("meta"); | ||
JSONArray data = result.getJSONArray("data"); | ||
|
||
if (CollectionUtils.isEmpty(head) || CollectionUtils.isEmpty(data)) { | ||
return Flux.empty(); | ||
} | ||
List<String> columns = head.stream() | ||
.map(v -> ((JSONObject) v).get("name").toString()) | ||
.collect(Collectors.toList()); | ||
|
||
return Flux.create(sink -> { | ||
wrapper.beforeWrap(() -> columns); | ||
|
||
for (Object rowo : data) { | ||
E rowInstance = wrapper.newRowInstance(); | ||
JSONObject row = (JSONObject) rowo; | ||
for (int i = 0; i < columns.size(); i++) { | ||
String property = columns.get(i); | ||
Object value = row.get(property); | ||
if ("total".equals(property)) { | ||
value = Long.valueOf(row.get(property).toString()); | ||
} else { | ||
value = row.get(property); | ||
} | ||
DefaultColumnWrapperContext<E> context = new DefaultColumnWrapperContext<>(i, property, value, rowInstance); | ||
wrapper.wrapColumn(context); | ||
rowInstance = context.getRowInstance(); | ||
} | ||
if (!wrapper.completedWrapRow(rowInstance)) { | ||
break; | ||
} | ||
if (rowInstance != null) { | ||
sink.next(rowInstance); | ||
} | ||
} | ||
wrapper.completedWrap(); | ||
sink.complete(); | ||
}); | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseSchemaMetadata.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package org.hswebframework.ezorm.rdb.supports.clickhouse; | ||
|
||
import org.hswebframework.ezorm.rdb.codec.EnumValueCodec; | ||
import org.hswebframework.ezorm.rdb.metadata.RDBSchemaMetadata; | ||
import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata; | ||
import org.hswebframework.ezorm.rdb.operator.CompositeExceptionTranslation; | ||
|
||
import org.hswebframework.ezorm.rdb.supports.clickhouse.sqlBuilder.ClickhouseDeleteSqlBuilder; | ||
import org.hswebframework.ezorm.rdb.supports.clickhouse.sqlBuilder.ClickhouseUpdateSqlBuilder; | ||
import org.hswebframework.ezorm.rdb.supports.mysql.*; | ||
import org.hswebframework.ezorm.rdb.utils.FeatureUtils; | ||
|
||
/** | ||
* @className ClickhouseSchemaMetadata | ||
* @Description TODO | ||
* @Author dengpengyu | ||
* @Date 2023/9/5 9:36 | ||
* @Vesion 1.0 | ||
*/ | ||
public class ClickhouseSchemaMetadata extends RDBSchemaMetadata { | ||
public ClickhouseSchemaMetadata(String name) { | ||
super(name); | ||
addFeature(new MysqlPaginator()); | ||
// TODO 后续增加建表 | ||
//读取表元数据 | ||
addFeature(new ClickhouseTableMetadataParser(this)); | ||
addFeature(new ClickhouseDialect()); | ||
addFeature(new CompositeExceptionTranslation() | ||
.add(FeatureUtils.r2dbcIsAlive(), () -> MysqlR2DBCExceptionTranslation.of(this)) | ||
.add(MysqlJDBCExceptionTranslation.of(this)) | ||
); | ||
} | ||
|
||
@Override | ||
public RDBTableMetadata newTable(String name) { | ||
RDBTableMetadata metadata = super.newTable(name); | ||
metadata.addFeature(ClickhouseUpdateSqlBuilder.of(metadata)); | ||
metadata.addFeature(ClickhouseDeleteSqlBuilder.of(metadata)); | ||
metadata.setOnColumnAdded(column -> { | ||
if (column.getValueCodec() instanceof EnumValueCodec && ((EnumValueCodec) column.getValueCodec()).isToMask()) { | ||
column.addFeature(MysqlEnumInFragmentBuilder.in); | ||
column.addFeature(MysqlEnumInFragmentBuilder.notIn); | ||
} | ||
}); | ||
return metadata; | ||
} | ||
|
||
@Override | ||
public void addTable(RDBTableMetadata metadata) { | ||
metadata.addFeature(new MysqlBatchUpsertOperator(metadata)); | ||
super.addTable(metadata); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
看上去不应该复制(覆盖)这个类
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
好的