From efc3a90026d7e44af75109b6ef66b3c509edb503 Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Mon, 11 Sep 2023 17:33:03 +0800 Subject: [PATCH 01/16] =?UTF-8?q?add:=20=E6=96=B0=E5=A2=9E=E5=AF=B9easy-or?= =?UTF-8?q?m=E5=AF=B9clickhouse=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 112 +++++++++++++ ...lickhouseHttpSqlExecutorConfiguration.java | 40 +++++ hsweb-commons-crud/ClickhouseProperties.java | 22 +++ hsweb-commons-crud/EasyormProperties.java | 122 ++++++++++++++ .../clickhouse/ClickhouseDialect.java | 83 ++++++++++ .../ClickhouseRestfulSqlExecutor.java | 135 ++++++++++++++++ .../clickhouse/ClickhouseSchemaMetadata.java | 53 +++++++ .../ClickhouseTableMetadataParser.java | 75 +++++++++ .../ClickhouseDeleteSqlBuilder.java | 87 ++++++++++ .../ClickhouseUpdateSqlBuilder.java | 150 ++++++++++++++++++ 10 files changed, 879 insertions(+) create mode 100644 README.md create mode 100644 hsweb-commons-crud/ClickhouseHttpSqlExecutorConfiguration.java create mode 100644 hsweb-commons-crud/ClickhouseProperties.java create mode 100644 hsweb-commons-crud/EasyormProperties.java create mode 100644 hsweb-easy-orm/clickhouse/ClickhouseDialect.java create mode 100644 hsweb-easy-orm/clickhouse/ClickhouseRestfulSqlExecutor.java create mode 100644 hsweb-easy-orm/clickhouse/ClickhouseSchemaMetadata.java create mode 100644 hsweb-easy-orm/clickhouse/ClickhouseTableMetadataParser.java create mode 100644 hsweb-easy-orm/clickhouse/sqlBuilder/ClickhouseDeleteSqlBuilder.java create mode 100644 hsweb-easy-orm/clickhouse/sqlBuilder/ClickhouseUpdateSqlBuilder.java diff --git a/README.md b/README.md new file mode 100644 index 0000000..801e082 --- /dev/null +++ b/README.md @@ -0,0 +1,112 @@ +# 说明 + +1. 本仓库需要配合[hsweb-easy-orm](https://github.com/hs-web/hsweb-easy-orm),[hsweb-framework](https://github.com/hs-web/hsweb-framework)使用 +2. 本仓库是针对hsweb-easy-orm 4.X、hsweb-commons-curd 4.X 适配 clickhouse22.X + +# 使用 + +## hsweb-easy-orm编译 + +1. 首先克隆[hsweb-easy-orm](https://github.com/hs-web/hsweb-easy-orm)至本地 + +2. hsweb-easy-orm的pom文件中新增依赖 + + ```xml + + org.springframework + spring-webflux + 5.3.25 + + ``` + +3. 将本项目中hsweb-easy-orm的clickhouse目录复制到hsweb-easy-orm的org.hswebframework.ezorm.rdb.supports下,复制后包路径应是org.hswebframework.ezorm.rdb.supports.clickhouse + +4. hsweb-easy-orm-rdb\src\main\java\org\hswebframework\ezorm\rdb\metadata\dialect\Dialect.java中新增数据库方言如下 + + ```java + Dialect CLICKHOUSE =new ClickhouseDialect(); + ``` + +5. maven编译 + +## hsweb-commons-curd编译 + +1. 首先克隆[hsweb-framework](https://github.com/hs-web/hsweb-framework)至本地 + +2. 将本项目中hsweb-commons-curd文件夹下ClickhouseHttpSqlExecutorConfiguration.java 、ClickhouseProperties.java放置在hsweb-framework/hsweb-commons-curd模块中org.hswebframework.web.crud.configuration路径下。 + +3. 在org.hswebframework.web.crud.configuration.EasyormProperties.java文件中插入相关代码如下,**注意注释部分** + + ```java + + @Getter + @AllArgsConstructor + public enum DialectEnum { + mysql(Dialect.MYSQL, "?") { + @Override + public RDBSchemaMetadata createSchema(String name) { + return new MysqlSchemaMetadata(name); + } + }, + mssql(Dialect.MSSQL, "@arg") { + @Override + public RDBSchemaMetadata createSchema(String name) { + return new SqlServerSchemaMetadata(name); + } + }, + oracle(Dialect.ORACLE, "?") { + @Override + public RDBSchemaMetadata createSchema(String name) { + return new OracleSchemaMetadata(name); + } + }, + postgres(Dialect.POSTGRES, "$") { + @Override + public RDBSchemaMetadata createSchema(String name) { + return new PostgresqlSchemaMetadata(name); + } + }, + h2(Dialect.H2, "$") { + @Override + public RDBSchemaMetadata createSchema(String name) { + return new H2SchemaMetadata(name); + } + } + //start + //这里是对clickhouse的支持 + , + clickhouse(Dialect.CLICKHOUSE,"?"){ + @Override + public RDBSchemaMetadata createSchema(String name) { + return new ClickhouseSchemaMetadata(name); + } + } + //end + ; + + private Dialect dialect; + private String bindSymbol; + + public abstract RDBSchemaMetadata createSchema(String name); + ``` + +4. hsweb-framework/hsweb-commons-curd模块的src/main/resources/META-INF/spring.factories中新增org.hswebframework.web.crud.configuration.ClickhouseHttpSqlExecutorConfiguration,示例如下 + + ``` + # Auto Configure + org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + org.hswebframework.web.crud.configuration.EasyormConfiguration,\ + org.hswebframework.web.crud.configuration.JdbcSqlExecutorConfiguration,\ + org.hswebframework.web.crud.configuration.R2dbcSqlExecutorConfiguration,\ + org.hswebframework.web.crud.configuration.ClickhouseHttpSqlExecutorConfiguration,\ + org.hswebframework.web.crud.web.CommonWebFluxConfiguration,\ + org.hswebframework.web.crud.web.CommonWebMvcConfiguration + ``` + +5. maven编译 + +# 注意 + +1. 先编译hsweb-easy-orm再编译hsweb-commons-curd +2. 编译hsweb-commons-curd时需注意依赖hsweb-easy-orm的版本。 +3. 由于clickhouse各版本系统表差异过大,本仓库暂只支持clickhouse22.X版本 \ No newline at end of file diff --git a/hsweb-commons-crud/ClickhouseHttpSqlExecutorConfiguration.java b/hsweb-commons-crud/ClickhouseHttpSqlExecutorConfiguration.java new file mode 100644 index 0000000..afb7364 --- /dev/null +++ b/hsweb-commons-crud/ClickhouseHttpSqlExecutorConfiguration.java @@ -0,0 +1,40 @@ +package org.hswebframework.web.crud.configuration; + +import org.hswebframework.ezorm.rdb.executor.SyncSqlExecutor; +import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSqlExecutor; +import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSyncSqlExecutor; +import org.hswebframework.ezorm.rdb.supports.clickhouse.ClickhouseRestfulSqlExecutor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClient; + + +/** + * @author dengpengyu + */ +@Configuration +@EnableConfigurationProperties(ClickhouseProperties.class) +//@ConditionalOnMissingBean(ConnectionFactory.class) +public class ClickhouseHttpSqlExecutorConfiguration { + @Bean + @ConditionalOnMissingBean + public ReactiveSqlExecutor reactiveSqlExecutor(ClickhouseProperties properties) { + + WebClient clickhouseWebClient = WebClient + .builder() + .baseUrl(properties.getUrl()) + .defaultHeader("X-ClickHouse-User", properties.getUsername()) + .defaultHeader("X-ClickHouse-Key", properties.getPassword()) + .build(); + + return new ClickhouseRestfulSqlExecutor(clickhouseWebClient); + } + + @Bean + @ConditionalOnMissingBean + public SyncSqlExecutor syncSqlExecutor(ReactiveSqlExecutor reactiveSqlExecutor) { + return ReactiveSyncSqlExecutor.of(reactiveSqlExecutor); + } +} \ No newline at end of file diff --git a/hsweb-commons-crud/ClickhouseProperties.java b/hsweb-commons-crud/ClickhouseProperties.java new file mode 100644 index 0000000..f99a48b --- /dev/null +++ b/hsweb-commons-crud/ClickhouseProperties.java @@ -0,0 +1,22 @@ +package org.hswebframework.web.crud.configuration; + + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @author dengpengyu + * @date 2023/9/6 14:08 + */ +@Data +@ConfigurationProperties(prefix = "spring.clickhouse") +@Component +public class ClickhouseProperties { + + private String url; + + private String username; + + private String password; +} diff --git a/hsweb-commons-crud/EasyormProperties.java b/hsweb-commons-crud/EasyormProperties.java new file mode 100644 index 0000000..0cac45a --- /dev/null +++ b/hsweb-commons-crud/EasyormProperties.java @@ -0,0 +1,122 @@ +package org.hswebframework.web.crud.configuration; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.SneakyThrows; +import org.hswebframework.ezorm.rdb.metadata.RDBDatabaseMetadata; +import org.hswebframework.ezorm.rdb.metadata.RDBSchemaMetadata; +import org.hswebframework.ezorm.rdb.metadata.dialect.Dialect; +import org.hswebframework.ezorm.rdb.supports.clickhouse.ClickhouseSchemaMetadata; +import org.hswebframework.ezorm.rdb.supports.h2.H2SchemaMetadata; +import org.hswebframework.ezorm.rdb.supports.mssql.SqlServerSchemaMetadata; +import org.hswebframework.ezorm.rdb.supports.mysql.MysqlSchemaMetadata; +import org.hswebframework.ezorm.rdb.supports.oracle.OracleSchemaMetadata; +import org.hswebframework.ezorm.rdb.supports.postgres.PostgresqlSchemaMetadata; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +@ConfigurationProperties(prefix = "easyorm") +@Data +public class EasyormProperties { + + private String defaultSchema="PUBLIC"; + + private String[] schemas = {}; + + private boolean autoDdl = true; + + private boolean allowAlter = false; + + private boolean allowTypeAlter = true; + + private DialectEnum dialect = DialectEnum.h2; + + private Class dialectType; + + private Class schemaType; + + public RDBDatabaseMetadata createDatabaseMetadata() { + RDBDatabaseMetadata metadata = new RDBDatabaseMetadata(createDialect()); + + Set schemaSet = new HashSet<>(Arrays.asList(schemas)); + if (defaultSchema != null) { + schemaSet.add(defaultSchema); + } + schemaSet.stream() + .map(this::createSchema) + .forEach(metadata::addSchema); + + metadata.getSchema(defaultSchema) + .ifPresent(metadata::setCurrentSchema); + + return metadata; + } + + @SneakyThrows + public RDBSchemaMetadata createSchema(String name) { + if (schemaType == null) { + return dialect.createSchema(name); + } + return schemaType.getConstructor(String.class).newInstance(name); + } + + @SneakyThrows + public Dialect createDialect() { + if (dialectType == null) { + return dialect.getDialect(); + } + + return dialectType.newInstance(); + } + + @Getter + @AllArgsConstructor + public enum DialectEnum { + mysql(Dialect.MYSQL, "?") { + @Override + public RDBSchemaMetadata createSchema(String name) { + return new MysqlSchemaMetadata(name); + } + }, + mssql(Dialect.MSSQL, "@arg") { + @Override + public RDBSchemaMetadata createSchema(String name) { + return new SqlServerSchemaMetadata(name); + } + }, + oracle(Dialect.ORACLE, "?") { + @Override + public RDBSchemaMetadata createSchema(String name) { + return new OracleSchemaMetadata(name); + } + }, + postgres(Dialect.POSTGRES, "$") { + @Override + public RDBSchemaMetadata createSchema(String name) { + return new PostgresqlSchemaMetadata(name); + } + }, + h2(Dialect.H2, "$") { + @Override + public RDBSchemaMetadata createSchema(String name) { + return new H2SchemaMetadata(name); + } + }, + clickhouse(Dialect.CLICKHOUSE,"?"){ + @Override + public RDBSchemaMetadata createSchema(String name) { + return new ClickhouseSchemaMetadata(name); + } + } + ; + + private Dialect dialect; + private String bindSymbol; + + public abstract RDBSchemaMetadata createSchema(String name); + } +} diff --git a/hsweb-easy-orm/clickhouse/ClickhouseDialect.java b/hsweb-easy-orm/clickhouse/ClickhouseDialect.java new file mode 100644 index 0000000..e150312 --- /dev/null +++ b/hsweb-easy-orm/clickhouse/ClickhouseDialect.java @@ -0,0 +1,83 @@ +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"; + } +} diff --git a/hsweb-easy-orm/clickhouse/ClickhouseRestfulSqlExecutor.java b/hsweb-easy-orm/clickhouse/ClickhouseRestfulSqlExecutor.java new file mode 100644 index 0000000..37e9747 --- /dev/null +++ b/hsweb-easy-orm/clickhouse/ClickhouseRestfulSqlExecutor.java @@ -0,0 +1,135 @@ +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 update(Publisher request) { + return this + .doExecute(request) + .then(Mono.just(1)); + } + + @Override + public Mono execute(Publisher request) { + return this + .doExecute(request) + .then(); + } + + @Override + public Flux select(Publisher request, ResultWrapper wrapper) { + + return this + .doExecute(request) + .flatMap(response -> convertQueryResult(response, wrapper)); + } + + private Flux doExecute(Publisher 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 Flux convertQueryResult(JSONObject result, ResultWrapper wrapper) { + + JSONArray head = result.getJSONArray("meta"); + JSONArray data = result.getJSONArray("data"); + + if (CollectionUtils.isEmpty(head) || CollectionUtils.isEmpty(data)) { + return Flux.empty(); + } + List 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); + DefaultColumnWrapperContext 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(); + }); + } +} diff --git a/hsweb-easy-orm/clickhouse/ClickhouseSchemaMetadata.java b/hsweb-easy-orm/clickhouse/ClickhouseSchemaMetadata.java new file mode 100644 index 0000000..4819bcf --- /dev/null +++ b/hsweb-easy-orm/clickhouse/ClickhouseSchemaMetadata.java @@ -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.operator.builder.fragments.update.DefaultUpdateSqlBuilder; +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); + } +} diff --git a/hsweb-easy-orm/clickhouse/ClickhouseTableMetadataParser.java b/hsweb-easy-orm/clickhouse/ClickhouseTableMetadataParser.java new file mode 100644 index 0000000..a5f956a --- /dev/null +++ b/hsweb-easy-orm/clickhouse/ClickhouseTableMetadataParser.java @@ -0,0 +1,75 @@ +package org.hswebframework.ezorm.rdb.supports.clickhouse; + +import org.hswebframework.ezorm.rdb.metadata.RDBSchemaMetadata; +import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata; +import org.hswebframework.ezorm.rdb.supports.commons.RDBTableMetadataParser; +import reactor.core.publisher.Flux; + +import java.util.List; + +/** + * @className Clickhouse + * @Description TODO + * @Author dengpengyu + * @Date 2023/9/4 14:56 + * @Vesion 1.0 + */ +public class ClickhouseTableMetadataParser extends RDBTableMetadataParser { + private static final String TABLE_META_SQL = String.join(" ", + "select", + "column_name as `name`,", + "data_type as `data_type`,", + "character_maximum_length as `data_length`,", + "numeric_precision as `data_precision`,", + "numeric_scale as `data_scale`,", + "column_comment as `comment`,", + "table_name as `table_name`,", + "case when is_nullable=0 then 0 else 1 end ", + "from information_schema.columns where table_schema=#{schema} and table_name like #{table}"); + + private static final String TABLE_COMMENT_SQL = String.join(" ", + "select ", + "`comment`", + ",name as `table_name`", + "from system.tables where database=#{schema} and name like #{table}"); + + + private static final String ALL_TABLE_SQL = "select table_name as `name` from system.tables where database=#{schema}"; + + private static final String TABLE_EXISTS_SQL = "select count() as `total` from system.tables where database=#{schema} and name=#{table}"; + + public ClickhouseTableMetadataParser(RDBSchemaMetadata schema) { + super(schema); + } + + @Override + protected String getTableMetaSql(String name) { + return TABLE_META_SQL; + } + + @Override + protected String getTableCommentSql(String name) { + return TABLE_COMMENT_SQL; + } + + @Override + protected String getAllTableSql() { + return ALL_TABLE_SQL; + } + + @Override + public String getTableExistsSql() { + return TABLE_EXISTS_SQL; + } + + @Override + public List parseAll() { + return super.fastParseAll(); + } + + @Override + public Flux parseAllReactive() { + return super.fastParseAllReactive(); + } + +} diff --git a/hsweb-easy-orm/clickhouse/sqlBuilder/ClickhouseDeleteSqlBuilder.java b/hsweb-easy-orm/clickhouse/sqlBuilder/ClickhouseDeleteSqlBuilder.java new file mode 100644 index 0000000..f3899a0 --- /dev/null +++ b/hsweb-easy-orm/clickhouse/sqlBuilder/ClickhouseDeleteSqlBuilder.java @@ -0,0 +1,87 @@ +package org.hswebframework.ezorm.rdb.supports.clickhouse.sqlBuilder; + +import lombok.AllArgsConstructor; + +import org.apache.commons.collections.CollectionUtils; +import org.hswebframework.ezorm.core.param.Term; +import org.hswebframework.ezorm.rdb.executor.SqlRequest; +import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata; +import org.hswebframework.ezorm.rdb.metadata.key.ForeignKeyMetadata; +import org.hswebframework.ezorm.rdb.operator.builder.fragments.*; +import org.hswebframework.ezorm.rdb.operator.builder.fragments.delete.DeleteSqlBuilder; +import org.hswebframework.ezorm.rdb.operator.builder.fragments.term.ForeignKeyTermFragmentBuilder; + +import org.hswebframework.ezorm.rdb.operator.dml.delete.DeleteOperatorParameter; + + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + + +/** + * @className ClickhouseDeleteSqlBuilder + * @Description TODO + * @Author dengpengyu + * @Date 2023/9/6 10:06 + * @Vesion 1.0 + */ +@AllArgsConstructor(staticName = "of") +@SuppressWarnings("all") +public class ClickhouseDeleteSqlBuilder extends AbstractTermsFragmentBuilder implements DeleteSqlBuilder { + + private RDBTableMetadata table; + + @Override + public SqlRequest build(DeleteOperatorParameter parameter) { + if (CollectionUtils.isEmpty(parameter.getWhere())) { + throw new UnsupportedOperationException("Unsupported No Conditions delete"); + } + + PrepareSqlFragments fragments = PrepareSqlFragments.of(); + fragments.addSql("ALTER TABLE", table.getFullName(), "DELETE WHERE"); + + SqlFragments where = createTermFragments(parameter, parameter.getWhere()); + if (where.isEmpty()) { + throw new UnsupportedOperationException("Unsupported No Conditions delete"); + } + fragments.addFragments(where); + + return fragments.toRequest(); + } + + @Override + protected SqlFragments createTermFragments(DeleteOperatorParameter parameter, Term term) { + String columnName = term.getColumn(); + if (columnName == null) { + return EmptySqlFragments.INSTANCE; + } + + if (columnName.contains(".")) { + String[] arr = columnName.split("[.]"); + if (table.equalsNameOrAlias(arr[0])) { + columnName = arr[1]; + } else { + return table.getForeignKey(arr[0]) + .flatMap(key -> table.findFeature(ForeignKeyTermFragmentBuilder.ID) + .map(builder -> builder.createFragments(table.getName(), key, createForeignKeyTerm(key, term)))) + .orElse(EmptySqlFragments.INSTANCE); + } + } + + return table + .getColumn(columnName) + .flatMap(column -> column + .findFeature(TermFragmentBuilder.createFeatureId(term.getTermType())) + .map(termFragment -> termFragment.createFragments(column.getQuoteName(), column, term))) + .orElse(EmptySqlFragments.INSTANCE); + } + + protected List createForeignKeyTerm(ForeignKeyMetadata keyMetadata, Term term) { + Term copy = term.clone(); + //只要是嵌套到外键表的条件则认为是关联表的条件 + term.setTerms(new LinkedList<>()); + + return Collections.singletonList(copy); + } +} diff --git a/hsweb-easy-orm/clickhouse/sqlBuilder/ClickhouseUpdateSqlBuilder.java b/hsweb-easy-orm/clickhouse/sqlBuilder/ClickhouseUpdateSqlBuilder.java new file mode 100644 index 0000000..b2f2b18 --- /dev/null +++ b/hsweb-easy-orm/clickhouse/sqlBuilder/ClickhouseUpdateSqlBuilder.java @@ -0,0 +1,150 @@ +package org.hswebframework.ezorm.rdb.supports.clickhouse.sqlBuilder; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.apache.commons.collections.CollectionUtils; +import org.hswebframework.ezorm.core.param.Term; +import org.hswebframework.ezorm.rdb.executor.EmptySqlRequest; +import org.hswebframework.ezorm.rdb.executor.SqlRequest; +import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata; +import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata; +import org.hswebframework.ezorm.rdb.metadata.key.ForeignKeyMetadata; +import org.hswebframework.ezorm.rdb.operator.builder.fragments.*; +import org.hswebframework.ezorm.rdb.operator.builder.fragments.term.ForeignKeyTermFragmentBuilder; +import org.hswebframework.ezorm.rdb.operator.builder.fragments.update.UpdateSqlBuilder; +import org.hswebframework.ezorm.rdb.operator.dml.update.UpdateColumn; +import org.hswebframework.ezorm.rdb.operator.dml.update.UpdateOperatorParameter; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import static java.util.Optional.ofNullable; +import static org.hswebframework.ezorm.rdb.operator.builder.fragments.function.FunctionFragmentBuilder.createFeatureId; +/** + * @author dengpengyu + */ +/** + * @className ClickhouseUpdateSqlBuilder + * @Description TODO + * @Author dengpengyu + * @Date 2023/9/6 9:56 + * @Vesion 1.0 + */ +@AllArgsConstructor(staticName = "of") +@SuppressWarnings("all") +public class ClickhouseUpdateSqlBuilder extends AbstractTermsFragmentBuilder implements UpdateSqlBuilder { + @Getter + private RDBTableMetadata table; + + @Override + public SqlRequest build(UpdateOperatorParameter parameter) { + + if (CollectionUtils.isEmpty(parameter.getColumns())) { + return EmptySqlRequest.INSTANCE; + } + if (CollectionUtils.isEmpty(parameter.getWhere())) { + throw new UnsupportedOperationException("unsupported no conditions update"); + } + + PrepareSqlFragments fragments = PrepareSqlFragments.of(); + + fragments.addSql("ALTER TABLE", table.getFullName(), "UPDATE"); + + int index = 0; + for (UpdateColumn column : parameter.getColumns()) { + SqlFragments columnFragments = table.getColumn(column.getColumn()) + .filter(RDBColumnMetadata::isUpdatable) + .map(columnMetadata -> { + Object value = column.getValue(); + if (value == null) { + return EmptySqlFragments.INSTANCE; + } + + PrepareSqlFragments sqlFragments = PrepareSqlFragments.of(); + sqlFragments.addSql(columnMetadata.getQuoteName(), "="); + + if (column instanceof NativeSql) { + return PrepareSqlFragments.of() + .addSql(((NativeSql) column).getSql()) + .addParameter(((NativeSql) column).getParameters()); + } + if (value instanceof NativeSql) { + return PrepareSqlFragments.of() + .addSql(columnMetadata.getQuoteName(), "=") + .addSql(((NativeSql) column.getValue()).getSql()) + .addParameter(((NativeSql) column.getValue()).getParameters()); + } + + sqlFragments.addFragments(ofNullable(column.getFunction()) + .flatMap(function -> columnMetadata.findFeature(createFeatureId(function))) + .map(builder -> builder.create(columnMetadata.getName(), columnMetadata, column)) + .orElseGet(() -> PrepareSqlFragments.of() + .addSql("?") + .addParameter(columnMetadata.encode(value)))); + + return sqlFragments; + + }).orElse(EmptySqlFragments.INSTANCE); + + + if (columnFragments.isNotEmpty()) { + if (index++ != 0) { + fragments.addSql(","); + } + fragments.addFragments(columnFragments); + + } + } + if (index == 0) { + throw new UnsupportedOperationException("No columns are updated"); + } + fragments.addSql("where"); + + SqlFragments where = createTermFragments(parameter, parameter.getWhere()); + + if (where.isEmpty()) { + throw new UnsupportedOperationException("Unsupported No Conditions update"); + } + + fragments.addFragments(where); + + return fragments.toRequest(); + } + + @Override + protected SqlFragments createTermFragments(UpdateOperatorParameter parameter, Term term) { + String columnName = term.getColumn(); + if (columnName == null) { + return EmptySqlFragments.INSTANCE; + } + + if (columnName.contains(".")) { + String[] arr = columnName.split("[.]"); + if (table.equalsNameOrAlias(arr[0])) { + columnName = arr[1]; + } else { + return table.getForeignKey(arr[0]) + .flatMap(key -> key.getSource() + .findFeature(ForeignKeyTermFragmentBuilder.ID) + .map(builder -> builder.createFragments(table.getName(), key, createForeignKeyTerm(key, term)))) + .orElse(EmptySqlFragments.INSTANCE); + } + } + + return table + .getColumn(columnName) + .flatMap(column -> column + .findFeature(TermFragmentBuilder.createFeatureId(term.getTermType())) + .map(termFragment -> termFragment.createFragments(column.getQuoteName(), column, term))) + .orElse(EmptySqlFragments.INSTANCE); + } + + protected List createForeignKeyTerm(ForeignKeyMetadata keyMetadata, Term term) { + Term copy = term.clone(); + //只要是嵌套到外键表的条件则认为是关联表的条件 + term.setTerms(new LinkedList<>()); + + return Collections.singletonList(copy); + } +} From ce44317efaba5dc3d366eacb8272988e0207330c Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Mon, 18 Sep 2023 16:55:20 +0800 Subject: [PATCH 02/16] =?UTF-8?q?fix:=20=E6=8A=8A=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E8=BF=87=E7=A8=8B=E8=BD=AC=E6=8D=A2=E4=B8=BA=E7=A8=8B=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 112 ------------------ pom.xml | 30 +++++ .../ezorm/rdb/metadata/dialect/Dialect.java | 69 +++++++++++ .../clickhouse/ClickhouseDialect.java | 1 + .../ClickhouseRestfulSqlExecutor.java | 5 + .../clickhouse/ClickhouseSchemaMetadata.java | 2 +- .../ClickhouseTableMetadataParser.java | 0 .../ClickhouseDeleteSqlBuilder.java | 3 - .../ClickhouseUpdateSqlBuilder.java | 1 + ...lickhouseHttpSqlExecutorConfiguration.java | 1 + .../configuration}/ClickhouseProperties.java | 6 +- .../configuration}/EasyormProperties.java | 45 +------ src/main/resources/META-INF/spring.factories | 3 + 13 files changed, 119 insertions(+), 159 deletions(-) delete mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/org/hswebframework/ezorm/rdb/metadata/dialect/Dialect.java rename {hsweb-easy-orm => src/main/java/org/hswebframework/ezorm/rdb/supports}/clickhouse/ClickhouseDialect.java (99%) rename {hsweb-easy-orm => src/main/java/org/hswebframework/ezorm/rdb/supports}/clickhouse/ClickhouseRestfulSqlExecutor.java (95%) rename {hsweb-easy-orm => src/main/java/org/hswebframework/ezorm/rdb/supports}/clickhouse/ClickhouseSchemaMetadata.java (95%) rename {hsweb-easy-orm => src/main/java/org/hswebframework/ezorm/rdb/supports}/clickhouse/ClickhouseTableMetadataParser.java (100%) rename {hsweb-easy-orm => src/main/java/org/hswebframework/ezorm/rdb/supports}/clickhouse/sqlBuilder/ClickhouseDeleteSqlBuilder.java (99%) rename {hsweb-easy-orm => src/main/java/org/hswebframework/ezorm/rdb/supports}/clickhouse/sqlBuilder/ClickhouseUpdateSqlBuilder.java (99%) rename {hsweb-commons-crud => src/main/java/org/hswebframework/web/crud/configuration}/ClickhouseHttpSqlExecutorConfiguration.java (99%) rename {hsweb-commons-crud => src/main/java/org/hswebframework/web/crud/configuration}/ClickhouseProperties.java (86%) rename {hsweb-commons-crud => src/main/java/org/hswebframework/web/crud/configuration}/EasyormProperties.java (59%) create mode 100644 src/main/resources/META-INF/spring.factories diff --git a/README.md b/README.md deleted file mode 100644 index 801e082..0000000 --- a/README.md +++ /dev/null @@ -1,112 +0,0 @@ -# 说明 - -1. 本仓库需要配合[hsweb-easy-orm](https://github.com/hs-web/hsweb-easy-orm),[hsweb-framework](https://github.com/hs-web/hsweb-framework)使用 -2. 本仓库是针对hsweb-easy-orm 4.X、hsweb-commons-curd 4.X 适配 clickhouse22.X - -# 使用 - -## hsweb-easy-orm编译 - -1. 首先克隆[hsweb-easy-orm](https://github.com/hs-web/hsweb-easy-orm)至本地 - -2. hsweb-easy-orm的pom文件中新增依赖 - - ```xml - - org.springframework - spring-webflux - 5.3.25 - - ``` - -3. 将本项目中hsweb-easy-orm的clickhouse目录复制到hsweb-easy-orm的org.hswebframework.ezorm.rdb.supports下,复制后包路径应是org.hswebframework.ezorm.rdb.supports.clickhouse - -4. hsweb-easy-orm-rdb\src\main\java\org\hswebframework\ezorm\rdb\metadata\dialect\Dialect.java中新增数据库方言如下 - - ```java - Dialect CLICKHOUSE =new ClickhouseDialect(); - ``` - -5. maven编译 - -## hsweb-commons-curd编译 - -1. 首先克隆[hsweb-framework](https://github.com/hs-web/hsweb-framework)至本地 - -2. 将本项目中hsweb-commons-curd文件夹下ClickhouseHttpSqlExecutorConfiguration.java 、ClickhouseProperties.java放置在hsweb-framework/hsweb-commons-curd模块中org.hswebframework.web.crud.configuration路径下。 - -3. 在org.hswebframework.web.crud.configuration.EasyormProperties.java文件中插入相关代码如下,**注意注释部分** - - ```java - - @Getter - @AllArgsConstructor - public enum DialectEnum { - mysql(Dialect.MYSQL, "?") { - @Override - public RDBSchemaMetadata createSchema(String name) { - return new MysqlSchemaMetadata(name); - } - }, - mssql(Dialect.MSSQL, "@arg") { - @Override - public RDBSchemaMetadata createSchema(String name) { - return new SqlServerSchemaMetadata(name); - } - }, - oracle(Dialect.ORACLE, "?") { - @Override - public RDBSchemaMetadata createSchema(String name) { - return new OracleSchemaMetadata(name); - } - }, - postgres(Dialect.POSTGRES, "$") { - @Override - public RDBSchemaMetadata createSchema(String name) { - return new PostgresqlSchemaMetadata(name); - } - }, - h2(Dialect.H2, "$") { - @Override - public RDBSchemaMetadata createSchema(String name) { - return new H2SchemaMetadata(name); - } - } - //start - //这里是对clickhouse的支持 - , - clickhouse(Dialect.CLICKHOUSE,"?"){ - @Override - public RDBSchemaMetadata createSchema(String name) { - return new ClickhouseSchemaMetadata(name); - } - } - //end - ; - - private Dialect dialect; - private String bindSymbol; - - public abstract RDBSchemaMetadata createSchema(String name); - ``` - -4. hsweb-framework/hsweb-commons-curd模块的src/main/resources/META-INF/spring.factories中新增org.hswebframework.web.crud.configuration.ClickhouseHttpSqlExecutorConfiguration,示例如下 - - ``` - # Auto Configure - org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - org.hswebframework.web.crud.configuration.EasyormConfiguration,\ - org.hswebframework.web.crud.configuration.JdbcSqlExecutorConfiguration,\ - org.hswebframework.web.crud.configuration.R2dbcSqlExecutorConfiguration,\ - org.hswebframework.web.crud.configuration.ClickhouseHttpSqlExecutorConfiguration,\ - org.hswebframework.web.crud.web.CommonWebFluxConfiguration,\ - org.hswebframework.web.crud.web.CommonWebMvcConfiguration - ``` - -5. maven编译 - -# 注意 - -1. 先编译hsweb-easy-orm再编译hsweb-commons-curd -2. 编译hsweb-commons-curd时需注意依赖hsweb-easy-orm的版本。 -3. 由于clickhouse各版本系统表差异过大,本仓库暂只支持clickhouse22.X版本 \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..5e7d949 --- /dev/null +++ b/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + org.hswebframework + hsweb-incubator-easyorm-clickhouse + 1.0-SNAPSHOT + + + 8 + 8 + 4.0.17-SNAPSHOT + + + + + org.hswebframework.web + hsweb-commons-crud + ${hsweb.framework.version} + + + org.springframework + spring-webflux + 5.3.25 + + + + \ No newline at end of file diff --git a/src/main/java/org/hswebframework/ezorm/rdb/metadata/dialect/Dialect.java b/src/main/java/org/hswebframework/ezorm/rdb/metadata/dialect/Dialect.java new file mode 100644 index 0000000..e078e35 --- /dev/null +++ b/src/main/java/org/hswebframework/ezorm/rdb/metadata/dialect/Dialect.java @@ -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 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(); + +} + diff --git a/hsweb-easy-orm/clickhouse/ClickhouseDialect.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java similarity index 99% rename from hsweb-easy-orm/clickhouse/ClickhouseDialect.java rename to src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java index e150312..e1e5ee5 100644 --- a/hsweb-easy-orm/clickhouse/ClickhouseDialect.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java @@ -7,6 +7,7 @@ import java.sql.Date; import java.sql.JDBCType; + /** * @className ClickhouseDire * @Description TODO diff --git a/hsweb-easy-orm/clickhouse/ClickhouseRestfulSqlExecutor.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java similarity index 95% rename from hsweb-easy-orm/clickhouse/ClickhouseRestfulSqlExecutor.java rename to src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java index 37e9747..9a67cb8 100644 --- a/hsweb-easy-orm/clickhouse/ClickhouseRestfulSqlExecutor.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java @@ -117,6 +117,11 @@ protected Flux convertQueryResult(JSONObject result, ResultWrapper 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 context = new DefaultColumnWrapperContext<>(i, property, value, rowInstance); wrapper.wrapColumn(context); rowInstance = context.getRowInstance(); diff --git a/hsweb-easy-orm/clickhouse/ClickhouseSchemaMetadata.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseSchemaMetadata.java similarity index 95% rename from hsweb-easy-orm/clickhouse/ClickhouseSchemaMetadata.java rename to src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseSchemaMetadata.java index 4819bcf..6572a41 100644 --- a/hsweb-easy-orm/clickhouse/ClickhouseSchemaMetadata.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseSchemaMetadata.java @@ -4,7 +4,7 @@ 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.operator.builder.fragments.update.DefaultUpdateSqlBuilder; + 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.*; diff --git a/hsweb-easy-orm/clickhouse/ClickhouseTableMetadataParser.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseTableMetadataParser.java similarity index 100% rename from hsweb-easy-orm/clickhouse/ClickhouseTableMetadataParser.java rename to src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseTableMetadataParser.java diff --git a/hsweb-easy-orm/clickhouse/sqlBuilder/ClickhouseDeleteSqlBuilder.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/sqlBuilder/ClickhouseDeleteSqlBuilder.java similarity index 99% rename from hsweb-easy-orm/clickhouse/sqlBuilder/ClickhouseDeleteSqlBuilder.java rename to src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/sqlBuilder/ClickhouseDeleteSqlBuilder.java index f3899a0..46c2c67 100644 --- a/hsweb-easy-orm/clickhouse/sqlBuilder/ClickhouseDeleteSqlBuilder.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/sqlBuilder/ClickhouseDeleteSqlBuilder.java @@ -1,7 +1,6 @@ package org.hswebframework.ezorm.rdb.supports.clickhouse.sqlBuilder; import lombok.AllArgsConstructor; - import org.apache.commons.collections.CollectionUtils; import org.hswebframework.ezorm.core.param.Term; import org.hswebframework.ezorm.rdb.executor.SqlRequest; @@ -10,10 +9,8 @@ import org.hswebframework.ezorm.rdb.operator.builder.fragments.*; import org.hswebframework.ezorm.rdb.operator.builder.fragments.delete.DeleteSqlBuilder; import org.hswebframework.ezorm.rdb.operator.builder.fragments.term.ForeignKeyTermFragmentBuilder; - import org.hswebframework.ezorm.rdb.operator.dml.delete.DeleteOperatorParameter; - import java.util.Collections; import java.util.LinkedList; import java.util.List; diff --git a/hsweb-easy-orm/clickhouse/sqlBuilder/ClickhouseUpdateSqlBuilder.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/sqlBuilder/ClickhouseUpdateSqlBuilder.java similarity index 99% rename from hsweb-easy-orm/clickhouse/sqlBuilder/ClickhouseUpdateSqlBuilder.java rename to src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/sqlBuilder/ClickhouseUpdateSqlBuilder.java index b2f2b18..9b82886 100644 --- a/hsweb-easy-orm/clickhouse/sqlBuilder/ClickhouseUpdateSqlBuilder.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/sqlBuilder/ClickhouseUpdateSqlBuilder.java @@ -24,6 +24,7 @@ /** * @author dengpengyu */ + /** * @className ClickhouseUpdateSqlBuilder * @Description TODO diff --git a/hsweb-commons-crud/ClickhouseHttpSqlExecutorConfiguration.java b/src/main/java/org/hswebframework/web/crud/configuration/ClickhouseHttpSqlExecutorConfiguration.java similarity index 99% rename from hsweb-commons-crud/ClickhouseHttpSqlExecutorConfiguration.java rename to src/main/java/org/hswebframework/web/crud/configuration/ClickhouseHttpSqlExecutorConfiguration.java index afb7364..ac99cee 100644 --- a/hsweb-commons-crud/ClickhouseHttpSqlExecutorConfiguration.java +++ b/src/main/java/org/hswebframework/web/crud/configuration/ClickhouseHttpSqlExecutorConfiguration.java @@ -3,6 +3,7 @@ import org.hswebframework.ezorm.rdb.executor.SyncSqlExecutor; import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSqlExecutor; import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSyncSqlExecutor; + import org.hswebframework.ezorm.rdb.supports.clickhouse.ClickhouseRestfulSqlExecutor; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; diff --git a/hsweb-commons-crud/ClickhouseProperties.java b/src/main/java/org/hswebframework/web/crud/configuration/ClickhouseProperties.java similarity index 86% rename from hsweb-commons-crud/ClickhouseProperties.java rename to src/main/java/org/hswebframework/web/crud/configuration/ClickhouseProperties.java index f99a48b..478202e 100644 --- a/hsweb-commons-crud/ClickhouseProperties.java +++ b/src/main/java/org/hswebframework/web/crud/configuration/ClickhouseProperties.java @@ -1,18 +1,18 @@ package org.hswebframework.web.crud.configuration; - import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** * @author dengpengyu - * @date 2023/9/6 14:08 + * @date 2023/9/13 15:29 */ @Data @ConfigurationProperties(prefix = "spring.clickhouse") @Component -public class ClickhouseProperties { +public class +ClickhouseProperties { private String url; diff --git a/hsweb-commons-crud/EasyormProperties.java b/src/main/java/org/hswebframework/web/crud/configuration/EasyormProperties.java similarity index 59% rename from hsweb-commons-crud/EasyormProperties.java rename to src/main/java/org/hswebframework/web/crud/configuration/EasyormProperties.java index 0cac45a..9f6b2a1 100644 --- a/hsweb-commons-crud/EasyormProperties.java +++ b/src/main/java/org/hswebframework/web/crud/configuration/EasyormProperties.java @@ -7,12 +7,8 @@ import org.hswebframework.ezorm.rdb.metadata.RDBDatabaseMetadata; import org.hswebframework.ezorm.rdb.metadata.RDBSchemaMetadata; import org.hswebframework.ezorm.rdb.metadata.dialect.Dialect; +import org.hswebframework.ezorm.rdb.supports.clickhouse.ClickhouseDialect; import org.hswebframework.ezorm.rdb.supports.clickhouse.ClickhouseSchemaMetadata; -import org.hswebframework.ezorm.rdb.supports.h2.H2SchemaMetadata; -import org.hswebframework.ezorm.rdb.supports.mssql.SqlServerSchemaMetadata; -import org.hswebframework.ezorm.rdb.supports.mysql.MysqlSchemaMetadata; -import org.hswebframework.ezorm.rdb.supports.oracle.OracleSchemaMetadata; -import org.hswebframework.ezorm.rdb.supports.postgres.PostgresqlSchemaMetadata; import org.springframework.boot.context.properties.ConfigurationProperties; import java.util.Arrays; @@ -23,7 +19,7 @@ @Data public class EasyormProperties { - private String defaultSchema="PUBLIC"; + private String defaultSchema = "PUBLIC"; private String[] schemas = {}; @@ -33,7 +29,7 @@ public class EasyormProperties { private boolean allowTypeAlter = true; - private DialectEnum dialect = DialectEnum.h2; + private DialectEnum dialect = DialectEnum.clickhouse; private Class dialectType; @@ -76,43 +72,12 @@ public Dialect createDialect() { @Getter @AllArgsConstructor public enum DialectEnum { - mysql(Dialect.MYSQL, "?") { - @Override - public RDBSchemaMetadata createSchema(String name) { - return new MysqlSchemaMetadata(name); - } - }, - mssql(Dialect.MSSQL, "@arg") { - @Override - public RDBSchemaMetadata createSchema(String name) { - return new SqlServerSchemaMetadata(name); - } - }, - oracle(Dialect.ORACLE, "?") { - @Override - public RDBSchemaMetadata createSchema(String name) { - return new OracleSchemaMetadata(name); - } - }, - postgres(Dialect.POSTGRES, "$") { - @Override - public RDBSchemaMetadata createSchema(String name) { - return new PostgresqlSchemaMetadata(name); - } - }, - h2(Dialect.H2, "$") { - @Override - public RDBSchemaMetadata createSchema(String name) { - return new H2SchemaMetadata(name); - } - }, - clickhouse(Dialect.CLICKHOUSE,"?"){ + clickhouse(Dialect.CLICKHOUSE, "?") { @Override public RDBSchemaMetadata createSchema(String name) { return new ClickhouseSchemaMetadata(name); } - } - ; + }; private Dialect dialect; private String bindSymbol; diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..9460a7e --- /dev/null +++ b/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Auto Configure +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.hswebframework.web.crud.configuration.ClickhouseHttpSqlExecutorConfiguration \ No newline at end of file From c046f58550cd5be02354cac88cb717b3d9cf65b7 Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Mon, 25 Sep 2023 17:47:50 +0800 Subject: [PATCH 03/16] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9clickhouse?= =?UTF-8?q?=E7=9A=84=E4=BB=8B=E5=85=A5=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ezorm/rdb/metadata/dialect/Dialect.java | 69 -------------- .../clickhouse/ClickhouseDialect.java | 14 ++- .../supports/clickhouse/ClickhouseHelper.java | 47 ++++++++++ .../ClickhouseRestfulSqlExecutor.java | 5 + .../ezorm/rdb/supports/clickhouse/Helper.java | 92 +++++++++++++++++++ .../ClickhouseReactiveCrudService.java | 26 ++++++ ...lickhouseHttpSqlExecutorConfiguration.java | 41 --------- .../configuration/ClickhouseProperties.java | 2 + .../crud/configuration/EasyormProperties.java | 87 ------------------ src/main/resources/META-INF/spring.factories | 3 +- 10 files changed, 182 insertions(+), 204 deletions(-) delete mode 100644 src/main/java/org/hswebframework/ezorm/rdb/metadata/dialect/Dialect.java create mode 100644 src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseHelper.java create mode 100644 src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/Helper.java create mode 100644 src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java delete mode 100644 src/main/java/org/hswebframework/web/crud/configuration/ClickhouseHttpSqlExecutorConfiguration.java delete mode 100644 src/main/java/org/hswebframework/web/crud/configuration/EasyormProperties.java diff --git a/src/main/java/org/hswebframework/ezorm/rdb/metadata/dialect/Dialect.java b/src/main/java/org/hswebframework/ezorm/rdb/metadata/dialect/Dialect.java deleted file mode 100644 index e078e35..0000000 --- a/src/main/java/org/hswebframework/ezorm/rdb/metadata/dialect/Dialect.java +++ /dev/null @@ -1,69 +0,0 @@ -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 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(); - -} - diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java index e1e5ee5..c73003a 100644 --- a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java @@ -7,6 +7,7 @@ import java.sql.Date; import java.sql.JDBCType; +import java.time.LocalDate; /** * @className ClickhouseDire @@ -18,11 +19,14 @@ 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.TINYINT, (meta) -> "Int8"); + addDataTypeBuilder(JDBCType.BOOLEAN, (meta) -> "Int8"); + + + addDataTypeBuilder(JDBCType.VARCHAR, (meta) -> "string"); + 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"); @@ -43,7 +47,7 @@ public ClickhouseDialect() { addDataTypeBuilder("int", (meta) -> "int"); addDataTypeBuilder("json", meta -> "json"); - + registerDataType("date", JdbcDataType.of(JDBCType.VARCHAR, String.class)); 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")); diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseHelper.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseHelper.java new file mode 100644 index 0000000..e7c3085 --- /dev/null +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseHelper.java @@ -0,0 +1,47 @@ +package org.hswebframework.ezorm.rdb.supports.clickhouse; + + +import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSqlExecutor; + +import org.hswebframework.ezorm.rdb.metadata.RDBSchemaMetadata; +import org.hswebframework.ezorm.rdb.metadata.dialect.Dialect; +import org.hswebframework.web.crud.configuration.ClickhouseProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClient; + + +/** + * @author dengpengyu + * @date 2023/9/21 14:28 + */ +@Configuration +@EnableConfigurationProperties(ClickhouseProperties.class) +public class ClickhouseHelper implements Helper { + + @Autowired + ClickhouseProperties properties; + + @Override + public RDBSchemaMetadata getRDBSchemaMetadata() { + return new ClickhouseSchemaMetadata(properties.getDatabase()); + } + + @Override + public Dialect getDialect() { + return new ClickhouseDialect(); + } + + @Override + public ReactiveSqlExecutor getReactiveSqlExecutor() { + WebClient clickhouseWebClient = WebClient + .builder() + .baseUrl(properties.getUrl()) + .defaultHeader("X-ClickHouse-User", properties.getUsername()) + .defaultHeader("X-ClickHouse-Key", properties.getPassword()) + .build(); + + return new ClickhouseRestfulSqlExecutor(clickhouseWebClient); + } +} diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java index 9a67cb8..b426483 100644 --- a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java @@ -122,6 +122,11 @@ protected Flux convertQueryResult(JSONObject result, ResultWrapper } else { value = row.get(property); } + try{ + value = Double.valueOf(row.get(property).toString()); + }catch (Exception e){ + value = row.get(property); + } DefaultColumnWrapperContext context = new DefaultColumnWrapperContext<>(i, property, value, rowInstance); wrapper.wrapColumn(context); rowInstance = context.getRowInstance(); diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/Helper.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/Helper.java new file mode 100644 index 0000000..9f843b1 --- /dev/null +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/Helper.java @@ -0,0 +1,92 @@ +package org.hswebframework.ezorm.rdb.supports.clickhouse; + +import lombok.SneakyThrows; +import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSqlExecutor; +import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSyncSqlExecutor; +import org.hswebframework.ezorm.rdb.mapping.EntityColumnMapping; +import org.hswebframework.ezorm.rdb.mapping.MappingFeatureType; +import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; +import org.hswebframework.ezorm.rdb.mapping.defaults.DefaultReactiveRepository; +import org.hswebframework.ezorm.rdb.mapping.jpa.JpaEntityTableMetadataParser; +import org.hswebframework.ezorm.rdb.mapping.wrapper.EntityResultWrapper; +import org.hswebframework.ezorm.rdb.metadata.RDBDatabaseMetadata; +import org.hswebframework.ezorm.rdb.metadata.RDBSchemaMetadata; +import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata; +import org.hswebframework.ezorm.rdb.metadata.dialect.Dialect; +import org.hswebframework.ezorm.rdb.operator.DatabaseOperator; +import org.hswebframework.ezorm.rdb.operator.DefaultDatabaseOperator; + +import java.util.function.Supplier; + +/** + * @author dengpengyu + * @date 2023/9/21 14:20 + */ +public interface Helper { + + RDBSchemaMetadata getRDBSchemaMetadata(); + + Dialect getDialect(); + + ReactiveSqlExecutor getReactiveSqlExecutor(); + + default RDBDatabaseMetadata getRDBDatabaseMetadata() { + RDBDatabaseMetadata metadata = new RDBDatabaseMetadata(getDialect()); + + RDBSchemaMetadata schema = getRDBSchemaMetadata(); + + ReactiveSqlExecutor sqlExecutor = getReactiveSqlExecutor(); + +// schema.addFeature((EventListener) (type, context) -> System.out.println(type)); + + metadata.setCurrentSchema(schema); + metadata.addSchema(schema); + metadata.addFeature(sqlExecutor); + metadata.addFeature(ReactiveSyncSqlExecutor.of(sqlExecutor)); + + return metadata; + } + + @SneakyThrows + default ReactiveRepository createRepository(Class clazz) { + RDBDatabaseMetadata metadata = getRDBDatabaseMetadata(); + DatabaseOperator operator = DefaultDatabaseOperator.of(metadata); + + JpaEntityTableMetadataParser parser = new JpaEntityTableMetadataParser(); + parser.setDatabaseMetadata(metadata); + /* parser.parseTableMetadata(clazz) + .ifPresent(address -> { + operator.ddl() + .createOrAlter(address) + .commit() + .reactive() + .block(); + });*/ + + RDBTableMetadata table = parser + .parseTableMetadata(clazz) + .orElseThrow(NullPointerException::new); + +// operator.ddl() +// .createOrAlter(table) +// .commit() +// .reactive() +// .block(); + + Supplier supplier = new Supplier() { + @SneakyThrows + @Override + public Object get() { + return clazz.newInstance(); + } + }; + EntityResultWrapper wrapper = new EntityResultWrapper(supplier); + wrapper.setMapping(table + .getFeature(MappingFeatureType.columnPropertyMapping.createFeatureId(clazz)) + .orElseThrow(NullPointerException::new)); + + + return new DefaultReactiveRepository<>(operator, table, clazz, wrapper); + } + +} diff --git a/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java b/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java new file mode 100644 index 0000000..50a5dda --- /dev/null +++ b/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java @@ -0,0 +1,26 @@ +package org.hswebframework.service; + + +import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; +import org.hswebframework.ezorm.rdb.supports.clickhouse.ClickhouseHelper; +import org.hswebframework.web.crud.service.ReactiveCrudService; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author dengpengyu + * @date 2023/9/20 11:38 + */ +public abstract class ClickhouseReactiveCrudService implements ReactiveCrudService { + + private ReactiveRepository repository; + + @Autowired + private ClickhouseHelper clickhouseHelper; + + @Override + public ReactiveRepository getRepository() { + return clickhouseHelper.createRepository(getEntityClass()); + } + + public abstract Class getEntityClass(); +} diff --git a/src/main/java/org/hswebframework/web/crud/configuration/ClickhouseHttpSqlExecutorConfiguration.java b/src/main/java/org/hswebframework/web/crud/configuration/ClickhouseHttpSqlExecutorConfiguration.java deleted file mode 100644 index ac99cee..0000000 --- a/src/main/java/org/hswebframework/web/crud/configuration/ClickhouseHttpSqlExecutorConfiguration.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.hswebframework.web.crud.configuration; - -import org.hswebframework.ezorm.rdb.executor.SyncSqlExecutor; -import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSqlExecutor; -import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSyncSqlExecutor; - -import org.hswebframework.ezorm.rdb.supports.clickhouse.ClickhouseRestfulSqlExecutor; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.reactive.function.client.WebClient; - - -/** - * @author dengpengyu - */ -@Configuration -@EnableConfigurationProperties(ClickhouseProperties.class) -//@ConditionalOnMissingBean(ConnectionFactory.class) -public class ClickhouseHttpSqlExecutorConfiguration { - @Bean - @ConditionalOnMissingBean - public ReactiveSqlExecutor reactiveSqlExecutor(ClickhouseProperties properties) { - - WebClient clickhouseWebClient = WebClient - .builder() - .baseUrl(properties.getUrl()) - .defaultHeader("X-ClickHouse-User", properties.getUsername()) - .defaultHeader("X-ClickHouse-Key", properties.getPassword()) - .build(); - - return new ClickhouseRestfulSqlExecutor(clickhouseWebClient); - } - - @Bean - @ConditionalOnMissingBean - public SyncSqlExecutor syncSqlExecutor(ReactiveSqlExecutor reactiveSqlExecutor) { - return ReactiveSyncSqlExecutor.of(reactiveSqlExecutor); - } -} \ No newline at end of file diff --git a/src/main/java/org/hswebframework/web/crud/configuration/ClickhouseProperties.java b/src/main/java/org/hswebframework/web/crud/configuration/ClickhouseProperties.java index 478202e..fc77de2 100644 --- a/src/main/java/org/hswebframework/web/crud/configuration/ClickhouseProperties.java +++ b/src/main/java/org/hswebframework/web/crud/configuration/ClickhouseProperties.java @@ -16,6 +16,8 @@ private String url; + private String database; + private String username; private String password; diff --git a/src/main/java/org/hswebframework/web/crud/configuration/EasyormProperties.java b/src/main/java/org/hswebframework/web/crud/configuration/EasyormProperties.java deleted file mode 100644 index 9f6b2a1..0000000 --- a/src/main/java/org/hswebframework/web/crud/configuration/EasyormProperties.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.hswebframework.web.crud.configuration; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.Getter; -import lombok.SneakyThrows; -import org.hswebframework.ezorm.rdb.metadata.RDBDatabaseMetadata; -import org.hswebframework.ezorm.rdb.metadata.RDBSchemaMetadata; -import org.hswebframework.ezorm.rdb.metadata.dialect.Dialect; -import org.hswebframework.ezorm.rdb.supports.clickhouse.ClickhouseDialect; -import org.hswebframework.ezorm.rdb.supports.clickhouse.ClickhouseSchemaMetadata; -import org.springframework.boot.context.properties.ConfigurationProperties; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -@ConfigurationProperties(prefix = "easyorm") -@Data -public class EasyormProperties { - - private String defaultSchema = "PUBLIC"; - - private String[] schemas = {}; - - private boolean autoDdl = true; - - private boolean allowAlter = false; - - private boolean allowTypeAlter = true; - - private DialectEnum dialect = DialectEnum.clickhouse; - - private Class dialectType; - - private Class schemaType; - - public RDBDatabaseMetadata createDatabaseMetadata() { - RDBDatabaseMetadata metadata = new RDBDatabaseMetadata(createDialect()); - - Set schemaSet = new HashSet<>(Arrays.asList(schemas)); - if (defaultSchema != null) { - schemaSet.add(defaultSchema); - } - schemaSet.stream() - .map(this::createSchema) - .forEach(metadata::addSchema); - - metadata.getSchema(defaultSchema) - .ifPresent(metadata::setCurrentSchema); - - return metadata; - } - - @SneakyThrows - public RDBSchemaMetadata createSchema(String name) { - if (schemaType == null) { - return dialect.createSchema(name); - } - return schemaType.getConstructor(String.class).newInstance(name); - } - - @SneakyThrows - public Dialect createDialect() { - if (dialectType == null) { - return dialect.getDialect(); - } - - return dialectType.newInstance(); - } - - @Getter - @AllArgsConstructor - public enum DialectEnum { - clickhouse(Dialect.CLICKHOUSE, "?") { - @Override - public RDBSchemaMetadata createSchema(String name) { - return new ClickhouseSchemaMetadata(name); - } - }; - - private Dialect dialect; - private String bindSymbol; - - public abstract RDBSchemaMetadata createSchema(String name); - } -} diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories index 9460a7e..ce6376f 100644 --- a/src/main/resources/META-INF/spring.factories +++ b/src/main/resources/META-INF/spring.factories @@ -1,3 +1,2 @@ # Auto Configure -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.hswebframework.web.crud.configuration.ClickhouseHttpSqlExecutorConfiguration \ No newline at end of file +org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.hswebframework.ezorm.rdb.supports.clickhouse.ClickhouseHelper \ No newline at end of file From 8f8b887fb36d612eb1a68b26515a0a75ea58dfaf Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Mon, 25 Sep 2023 22:01:48 +0800 Subject: [PATCH 04/16] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9pom=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=8F=8Agitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + hsweb-incubator-easyorm-clickhouse.iml | 86 ++++++++++++++++++++++++++ pom.xml | 26 +++++++- 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 hsweb-incubator-easyorm-clickhouse.iml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc8a670 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/* \ No newline at end of file diff --git a/hsweb-incubator-easyorm-clickhouse.iml b/hsweb-incubator-easyorm-clickhouse.iml new file mode 100644 index 0000000..835b7dd --- /dev/null +++ b/hsweb-incubator-easyorm-clickhouse.iml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 5e7d949..5d8d83b 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ 8 8 - 4.0.17-SNAPSHOT + 4.0.16 @@ -26,5 +26,29 @@ 5.3.25 + + + aliyun-nexus + aliyun + https://maven.aliyun.com/nexus/content/groups/public/ + + false + + + + + hsweb-nexus + Nexus Release Repository + https://nexus.jetlinks.cn/content/groups/public/ + + false + + + true + always + + + + \ No newline at end of file From f855a1d8c8736f9b091126e848cc4cb0c8544ddb Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:35:10 +0800 Subject: [PATCH 05/16] =?UTF-8?q?fix:=20=E8=A7=A3=E5=86=B3clickhouse?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E8=84=B1=E7=A6=BBeasyorm=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6=E4=BD=BF=E7=94=A8=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- ...onBeanDefinitionRegistryPostProcessor.java | 46 +++++++++++++++++++ src/main/resources/META-INF/spring.factories | 4 +- 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/hswebframework/web/crud/configuration/EasyormConfigurationBeanDefinitionRegistryPostProcessor.java diff --git a/pom.xml b/pom.xml index 5d8d83b..f0ff083 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.hswebframework hsweb-incubator-easyorm-clickhouse - 1.0-SNAPSHOT + 1.1-SNAPSHOT 8 diff --git a/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfigurationBeanDefinitionRegistryPostProcessor.java b/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfigurationBeanDefinitionRegistryPostProcessor.java new file mode 100644 index 0000000..c68cfe4 --- /dev/null +++ b/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfigurationBeanDefinitionRegistryPostProcessor.java @@ -0,0 +1,46 @@ +package org.hswebframework.web.crud.configuration; + +import org.hswebframework.ezorm.rdb.mapping.defaults.DefaultReactiveRepository; +import org.hswebframework.utils.StringUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import java.util.Arrays; + +/** + * @className EasyormConfigurationBeanDefinitionRegistryPostProcessor + * @Description TODO + * @Author zhong + * @Date 2023/10/8 14:07 + * @Vesion 1.0 + */ +@Component +public class EasyormConfigurationBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware { + private ApplicationContext applicationContext; + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { + Environment environment =applicationContext.getEnvironment(); + if (StringUtils.isNullOrEmpty(environment.getProperty("easyorm.dialect"))){ + String[] beanNames = ((DefaultListableBeanFactory) registry).getBeanNamesForType(DefaultReactiveRepository.class); + Arrays.stream(beanNames).forEach(item-> registry.removeBeanDefinition(item)); + registry.removeBeanDefinition("org.hswebframework.web.crud.configuration.AutoDDLProcessor_1"); + } + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext=applicationContext; + } +} diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories index ce6376f..556ddf6 100644 --- a/src/main/resources/META-INF/spring.factories +++ b/src/main/resources/META-INF/spring.factories @@ -1,2 +1,4 @@ # Auto Configure -org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.hswebframework.ezorm.rdb.supports.clickhouse.ClickhouseHelper \ No newline at end of file +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + org.hswebframework.ezorm.rdb.supports.clickhouse.ClickhouseHelper,\ + org.hswebframework.web.crud.configuration.EasyormConfigurationBeanDefinitionRegistryPostProcessor \ No newline at end of file From 3b79b74aad13db423caabcb41f6bd8ac1edb4db0 Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Fri, 13 Oct 2023 09:13:05 +0800 Subject: [PATCH 06/16] =?UTF-8?q?add:=20=E5=AF=B9clickhouse=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=B1=BB=E5=9E=8B=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 24 ++++++++- .../clickhouse/ClickhouseDataType.java | 29 +++++++++++ .../clickhouse/ClickhouseDialect.java | 49 ++++--------------- 3 files changed, 61 insertions(+), 41 deletions(-) create mode 100644 src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDataType.java diff --git a/pom.xml b/pom.xml index f0ff083..fd6ed2c 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,29 @@ always - + + + sct-releases + Nexus Release Repository + http://192.168.9.91:81/repository/maven-releases/ + + + sct-snapshots + Nexus Snapshot Repository + http://192.168.9.91:81/repository/maven-snapshots/ + + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + + \ No newline at end of file diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDataType.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDataType.java new file mode 100644 index 0000000..1d57cea --- /dev/null +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDataType.java @@ -0,0 +1,29 @@ +package org.hswebframework.ezorm.rdb.supports.clickhouse; + +/** + * @author dengpengyu + * @date 2023/10/12 15:16 + */ +public interface ClickhouseDataType { + + String INT8 = "Int8"; + + String INT16 = "Int16"; + + String INT32 = "Int32"; + + String INT64 = "Int64"; + + String INT128 = "Int128"; + + String INT256 = "Int256"; + + String STRING = "string"; + + String UUID = "UUID"; + + String Data = "Data"; + + String DATETIME64 = "DateTime64"; + +} diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java index c73003a..462b6fb 100644 --- a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java @@ -8,6 +8,7 @@ import java.sql.Date; import java.sql.JDBCType; import java.time.LocalDate; +import java.util.UUID; /** * @className ClickhouseDire @@ -19,46 +20,14 @@ public class ClickhouseDialect extends DefaultDialect { public ClickhouseDialect() { - - - addDataTypeBuilder(JDBCType.TINYINT, (meta) -> "Int8"); - addDataTypeBuilder(JDBCType.BOOLEAN, (meta) -> "Int8"); - - - addDataTypeBuilder(JDBCType.VARCHAR, (meta) -> "string"); - 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("date", JdbcDataType.of(JDBCType.VARCHAR, String.class)); - 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)); - + addDataTypeBuilder(JDBCType.TINYINT, (meta) -> ClickhouseDataType.INT8); + addDataTypeBuilder(JDBCType.BOOLEAN, (meta) -> ClickhouseDataType.INT8); + addDataTypeBuilder(JDBCType.SMALLINT, (meta) -> ClickhouseDataType.INT16); + addDataTypeBuilder(JDBCType.INTEGER, (meta) -> ClickhouseDataType.INT32); + addDataTypeBuilder(JDBCType.BIGINT, (meta) -> ClickhouseDataType.INT64); + addDataTypeBuilder(JDBCType.VARCHAR, (meta) -> ClickhouseDataType.STRING); + registerDataType("uuid", JdbcDataType.of(JDBCType.VARCHAR, String.class)); + registerDataType("timestamp", JdbcDataType.of(JDBCType.BIGINT, Long.class)); } @Override From 70057e8ca9b4624fce707e551f360d106c117778 Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Fri, 13 Oct 2023 15:37:33 +0800 Subject: [PATCH 07/16] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9date=E5=85=B3?= =?UTF-8?q?=E9=94=AE=E5=AD=97=E7=9A=84=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 16 +++++++++++++++- .../supports/clickhouse/ClickhouseDialect.java | 2 ++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fd6ed2c..392abcb 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.hswebframework hsweb-incubator-easyorm-clickhouse - 1.1-SNAPSHOT + 1.0-RELEASES 8 @@ -71,6 +71,20 @@ maven-deploy-plugin 2.8.2 + + + org.apache.maven.plugins + maven-source-plugin + 2.1.2 + + + package + + jar + + + + \ No newline at end of file diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java index 462b6fb..6055893 100644 --- a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java @@ -4,6 +4,7 @@ import org.hswebframework.ezorm.rdb.metadata.DataType; import org.hswebframework.ezorm.rdb.metadata.JdbcDataType; import org.hswebframework.ezorm.rdb.metadata.dialect.DefaultDialect; +import org.joda.time.DateTime; import java.sql.Date; import java.sql.JDBCType; @@ -28,6 +29,7 @@ public ClickhouseDialect() { addDataTypeBuilder(JDBCType.VARCHAR, (meta) -> ClickhouseDataType.STRING); registerDataType("uuid", JdbcDataType.of(JDBCType.VARCHAR, String.class)); registerDataType("timestamp", JdbcDataType.of(JDBCType.BIGINT, Long.class)); + registerDataType("date", JdbcDataType.of(JDBCType.VARCHAR, String.class)); } @Override From 5a8fa4adedbb235e7f4cba4c34e7fb64fb3bcea9 Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Mon, 16 Oct 2023 15:19:15 +0800 Subject: [PATCH 08/16] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E6=89=A7?= =?UTF-8?q?=E8=A1=8CSQL=E6=97=A5=E5=BF=97=E7=BA=A7=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java index b426483..fc2705e 100644 --- a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java @@ -75,7 +75,7 @@ private Flux doExecute(Publisher requests) { } else { sql = request.toNativeSql() + " FORMAT JSON"; } - log.info("Execute ==> {}", sql); + log.trace("Execute ==> {}", sql); return client .post() .bodyValue(sql) From e39e1d7a0438227b7a802b64a2e74c4d06aa3732 Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Fri, 17 Nov 2023 14:59:43 +0800 Subject: [PATCH 09/16] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E7=BB=93=E6=9E=9C=E7=9A=84=E9=A1=BA=E5=BA=8F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 392abcb..a7709fd 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.hswebframework hsweb-incubator-easyorm-clickhouse - 1.0-RELEASES + 1.0-SNAPSHOT 8 diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java index fc2705e..2090b42 100644 --- a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java @@ -82,8 +82,8 @@ private Flux doExecute(Publisher requests) { .exchangeToMono(response -> response .bodyToMono(String.class) .map(json -> { - checkExecuteResult(sql, json); JSONObject result = JSON.parseObject(json); + checkExecuteResult(sql, json); return result; })); From 6ad7bf0d643ffed43d86e3273ce0b3b8e5f0573a Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Sat, 18 Nov 2023 10:14:19 +0800 Subject: [PATCH 10/16] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=8F=92=E5=85=A5=E4=B8=8D=E8=BF=9B=E5=8E=BB=E7=9A=84?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ClickhouseReactiveCrudService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java b/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java index 50a5dda..6d00afb 100644 --- a/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java +++ b/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java @@ -19,8 +19,11 @@ public abstract class ClickhouseReactiveCrudService implements ReactiveCru @Override public ReactiveRepository getRepository() { - return clickhouseHelper.createRepository(getEntityClass()); + if (repository == null) { + repository = clickhouseHelper.createRepository(getEntityClass()); + } + return repository; } - public abstract Class getEntityClass(); + public abstract Class getEntityClass(); } From bffd0fc49f111d29f5df765204edaaf127233adc Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Fri, 12 Jan 2024 20:04:13 +0800 Subject: [PATCH 11/16] add .gitignore --- .gitignore | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index bc8a670..c0fb2d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,27 @@ -.idea/* \ No newline at end of file +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +*.idea +*.iml +target +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* From 0f2c2d9b90e9377ae02bafcfaa592e956fa1007f Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Sat, 13 Jan 2024 09:54:54 +0800 Subject: [PATCH 12/16] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96Service=E8=8E=B7?= =?UTF-8?q?=E5=8F=96class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ClickhouseReactiveCrudService.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java b/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java index 6d00afb..f701ed8 100644 --- a/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java +++ b/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java @@ -12,18 +12,24 @@ */ public abstract class ClickhouseReactiveCrudService implements ReactiveCrudService { + private final Class clazz; + private ReactiveRepository repository; @Autowired private ClickhouseHelper clickhouseHelper; + public ClickhouseReactiveCrudService(Class clazz) { + this.clazz = clazz; + } + @Override public ReactiveRepository getRepository() { if (repository == null) { - repository = clickhouseHelper.createRepository(getEntityClass()); + repository = clickhouseHelper.createRepository(clazz); } return repository; } - public abstract Class getEntityClass(); +// public abstract Class getEntityClass(); } From 72d39140dac84f67aa0c4a5cdc3a77a9886acde4 Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:36:08 +0800 Subject: [PATCH 13/16] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E5=B0=81?= =?UTF-8?q?=E8=A3=85=E6=9F=A5=E8=AF=A2=E6=95=B0=E6=8D=AE=E5=90=8E=E7=9A=84?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hsweb-incubator-easyorm-clickhouse.iml | 38 +++++----- pom.xml | 2 +- .../clickhouse/ClickhouseDataType.java | 69 +++++++++++++------ .../clickhouse/ClickhouseDialect.java | 18 ++--- .../ClickhouseRestfulSqlExecutor.java | 53 ++++++++------ .../ClickhouseReactiveCrudService.java | 12 ++-- ...onBeanDefinitionRegistryPostProcessor.java | 2 +- 7 files changed, 111 insertions(+), 83 deletions(-) diff --git a/hsweb-incubator-easyorm-clickhouse.iml b/hsweb-incubator-easyorm-clickhouse.iml index 835b7dd..4cb7b15 100644 --- a/hsweb-incubator-easyorm-clickhouse.iml +++ b/hsweb-incubator-easyorm-clickhouse.iml @@ -15,12 +15,12 @@ - - + + - + - + @@ -30,17 +30,17 @@ - - - + + + - - - + + + @@ -50,18 +50,18 @@ - + - - - - - + + + + + @@ -70,13 +70,13 @@ - - + + - + diff --git a/pom.xml b/pom.xml index a7709fd..0ab5a5f 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ 8 8 - 4.0.16 + 4.0.17-SNAPSHOT diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDataType.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDataType.java index 1d57cea..ad3c289 100644 --- a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDataType.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDataType.java @@ -1,29 +1,54 @@ package org.hswebframework.ezorm.rdb.supports.clickhouse; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.dict.EnumDict; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Array; + /** * @author dengpengyu * @date 2023/10/12 15:16 */ -public interface ClickhouseDataType { - - String INT8 = "Int8"; - - String INT16 = "Int16"; - - String INT32 = "Int32"; - - String INT64 = "Int64"; - - String INT128 = "Int128"; - - String INT256 = "Int256"; - - String STRING = "string"; - - String UUID = "UUID"; - - String Data = "Data"; - - String DATETIME64 = "DateTime64"; - +@AllArgsConstructor +@Getter +public enum ClickhouseDataType implements EnumDict> { + + INT8(Byte.class), + INT16(Short.class), + INT32(Integer.class), + INT64(Long.class), + INT128(BigInteger.class), + INT256(BigInteger.class), + UINT8(Short.class), + UINT16(Integer.class), + UINT32(Long.class), + UINT64(BigInteger.class), + NULLABLE_UINT64(BigInteger.class), + FLOAT32(Float.class), + FLOAT64(Double.class), + STRING(String.class), + UUID(String.class), + BOOLEAN(Boolean.class), + DATE(java.sql.Date.class), + DATETIME(java.sql.Timestamp.class), + DATETIME64(java.time.LocalDateTime.class), + ARRAY(Array.class), // This would be a placeholder, actual implementation depends on the array type + ENUM(String.class), // Enums in Clickhouse are typically represented as strings in Java + DECIMAL(BigDecimal.class), + IP(String.class); // IP address types can be represented as strings + + private final Class javaType; + + @Override + public Class getValue() { + return javaType; + } + + @Override + public String getText() { + return name(); + } } diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java index 6055893..ccb020f 100644 --- a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDialect.java @@ -1,15 +1,9 @@ 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 org.joda.time.DateTime; -import java.sql.Date; import java.sql.JDBCType; -import java.time.LocalDate; -import java.util.UUID; /** * @className ClickhouseDire @@ -21,12 +15,12 @@ public class ClickhouseDialect extends DefaultDialect { public ClickhouseDialect() { - addDataTypeBuilder(JDBCType.TINYINT, (meta) -> ClickhouseDataType.INT8); - addDataTypeBuilder(JDBCType.BOOLEAN, (meta) -> ClickhouseDataType.INT8); - addDataTypeBuilder(JDBCType.SMALLINT, (meta) -> ClickhouseDataType.INT16); - addDataTypeBuilder(JDBCType.INTEGER, (meta) -> ClickhouseDataType.INT32); - addDataTypeBuilder(JDBCType.BIGINT, (meta) -> ClickhouseDataType.INT64); - addDataTypeBuilder(JDBCType.VARCHAR, (meta) -> ClickhouseDataType.STRING); + addDataTypeBuilder(JDBCType.TINYINT, (meta) -> ClickhouseDataType.INT8.getText()); + addDataTypeBuilder(JDBCType.BOOLEAN, (meta) -> ClickhouseDataType.INT8.getText()); + addDataTypeBuilder(JDBCType.SMALLINT, (meta) -> ClickhouseDataType.INT16.getText()); + addDataTypeBuilder(JDBCType.INTEGER, (meta) -> ClickhouseDataType.INT32.getText()); + addDataTypeBuilder(JDBCType.BIGINT, (meta) -> ClickhouseDataType.INT64.getText()); + addDataTypeBuilder(JDBCType.VARCHAR, (meta) -> ClickhouseDataType.STRING.getText()); registerDataType("uuid", JdbcDataType.of(JDBCType.VARCHAR, String.class)); registerDataType("timestamp", JdbcDataType.of(JDBCType.BIGINT, Long.class)); registerDataType("date", JdbcDataType.of(JDBCType.VARCHAR, String.class)); diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java index 2090b42..7f65a71 100644 --- a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java @@ -3,6 +3,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import lombok.SneakyThrows; import org.hswebframework.ezorm.rdb.executor.BatchSqlRequest; import org.hswebframework.ezorm.rdb.executor.DefaultColumnWrapperContext; import org.hswebframework.ezorm.rdb.executor.SqlRequest; @@ -16,7 +17,8 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import java.util.List; +import java.lang.reflect.Constructor; +import java.util.*; import java.util.stream.Collectors; /** @@ -98,36 +100,43 @@ private void checkExecuteResult(String sql, String code) { protected Flux convertQueryResult(JSONObject result, ResultWrapper wrapper) { - JSONArray head = result.getJSONArray("meta"); - JSONArray data = result.getJSONArray("data"); + Map columnMeta = new HashMap(); - if (CollectionUtils.isEmpty(head) || CollectionUtils.isEmpty(data)) { + JSONArray resultMeta = result.getJSONArray("meta"); + JSONArray resultEntityList = result.getJSONArray("data"); + + if (CollectionUtils.isEmpty(resultMeta) || CollectionUtils.isEmpty(resultEntityList)) { return Flux.empty(); } - List columns = head.stream() - .map(v -> ((JSONObject) v).get("name").toString()) - .collect(Collectors.toList()); + //把当前列和列类型一一对应 + for (Object o : resultMeta) { + JSONObject e = (JSONObject) o; + columnMeta.put(e.getString("name"), ClickhouseDataType.valueOf(e.getString("type").toUpperCase().replace("NULLABLE(", "").replace(")", ""))); + } + //所有的列名 + ArrayList columns = new ArrayList<>(columnMeta.keySet()); return Flux.create(sink -> { wrapper.beforeWrap(() -> columns); - for (Object rowo : data) { + for (Object oneObjectEntity : resultEntityList) { 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); - } - try{ - value = Double.valueOf(row.get(property).toString()); - }catch (Exception e){ - value = row.get(property); + JSONObject oneJsonObjectEntity = (JSONObject) oneObjectEntity; + for (String columnName : columns) { +// String columnName = columns.get(i); + Object value = oneJsonObjectEntity.get(columnName); + ClickhouseDataType dataType = columnMeta.get(columnName); + try { + Class typeClass = dataType.getJavaType(); + Constructor constructor = typeClass.getConstructor(String.class); + + if (Objects.nonNull(value)) { + value = constructor.newInstance(value.toString()); + } + } catch (Exception e) { + e.printStackTrace(); } - DefaultColumnWrapperContext context = new DefaultColumnWrapperContext<>(i, property, value, rowInstance); + DefaultColumnWrapperContext context = new DefaultColumnWrapperContext<>(columns.indexOf(columnName), columnName, value, rowInstance); wrapper.wrapColumn(context); rowInstance = context.getRowInstance(); } diff --git a/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java b/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java index f701ed8..d1a7454 100644 --- a/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java +++ b/src/main/java/org/hswebframework/service/ClickhouseReactiveCrudService.java @@ -12,24 +12,24 @@ */ public abstract class ClickhouseReactiveCrudService implements ReactiveCrudService { - private final Class clazz; +// private Class clazz; private ReactiveRepository repository; @Autowired private ClickhouseHelper clickhouseHelper; - public ClickhouseReactiveCrudService(Class clazz) { - this.clazz = clazz; - } +// public ClickhouseReactiveCrudService(Class clazz) { +// this.clazz = clazz; +// } @Override public ReactiveRepository getRepository() { if (repository == null) { - repository = clickhouseHelper.createRepository(clazz); + repository = clickhouseHelper.createRepository(getEntityClass()); } return repository; } -// public abstract Class getEntityClass(); + public abstract Class getEntityClass(); } diff --git a/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfigurationBeanDefinitionRegistryPostProcessor.java b/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfigurationBeanDefinitionRegistryPostProcessor.java index c68cfe4..ae89ef5 100644 --- a/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfigurationBeanDefinitionRegistryPostProcessor.java +++ b/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfigurationBeanDefinitionRegistryPostProcessor.java @@ -31,7 +31,7 @@ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) t if (StringUtils.isNullOrEmpty(environment.getProperty("easyorm.dialect"))){ String[] beanNames = ((DefaultListableBeanFactory) registry).getBeanNamesForType(DefaultReactiveRepository.class); Arrays.stream(beanNames).forEach(item-> registry.removeBeanDefinition(item)); - registry.removeBeanDefinition("org.hswebframework.web.crud.configuration.AutoDDLProcessor_1"); +// registry.removeBeanDefinition("org.hswebframework.web.crud.configuration.AutoDDLProcessor_1"); } } From 385ab776907b830fd3549bedbf52bc8b0c4d5f89 Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Wed, 17 Jan 2024 10:37:37 +0800 Subject: [PATCH 14/16] =?UTF-8?q?add:=20=E5=A2=9E=E5=8A=A0clickhouse?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E6=89=A7=E8=A1=8C=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../supports/clickhouse/ClickhouseHelper.java | 7 +- ...ava => ClickhouseReactiveSqlExecutor.java} | 9 +- .../clickhouse/ClickhouseSyncSqlExecutor.java | 177 ++++++++++++++++++ .../ezorm/rdb/supports/clickhouse/Helper.java | 7 +- 4 files changed, 190 insertions(+), 10 deletions(-) rename src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/{ClickhouseRestfulSqlExecutor.java => ClickhouseReactiveSqlExecutor.java} (94%) create mode 100644 src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseSyncSqlExecutor.java diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseHelper.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseHelper.java index e7c3085..2ad3df2 100644 --- a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseHelper.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseHelper.java @@ -42,6 +42,11 @@ public ReactiveSqlExecutor getReactiveSqlExecutor() { .defaultHeader("X-ClickHouse-Key", properties.getPassword()) .build(); - return new ClickhouseRestfulSqlExecutor(clickhouseWebClient); + return new ClickhouseReactiveSqlExecutor(clickhouseWebClient); + } + + @Override + public ClickhouseProperties getClickhouseProperties() { + return properties; } } diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseReactiveSqlExecutor.java similarity index 94% rename from src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java rename to src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseReactiveSqlExecutor.java index 7f65a71..f572cde 100644 --- a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseRestfulSqlExecutor.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseReactiveSqlExecutor.java @@ -3,7 +3,6 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import lombok.SneakyThrows; import org.hswebframework.ezorm.rdb.executor.BatchSqlRequest; import org.hswebframework.ezorm.rdb.executor.DefaultColumnWrapperContext; import org.hswebframework.ezorm.rdb.executor.SqlRequest; @@ -19,7 +18,6 @@ import java.lang.reflect.Constructor; import java.util.*; -import java.util.stream.Collectors; /** * @className ClickhouseRestfulSqlExecutor @@ -28,11 +26,11 @@ * @Date 2023/9/4 14:40 * @Vesion 1.0 */ -public class ClickhouseRestfulSqlExecutor implements ReactiveSqlExecutor { - private Logger log = LoggerFactory.getLogger(ClickhouseRestfulSqlExecutor.class); +public class ClickhouseReactiveSqlExecutor implements ReactiveSqlExecutor { + private Logger log = LoggerFactory.getLogger(ClickhouseReactiveSqlExecutor.class); private WebClient client; - public ClickhouseRestfulSqlExecutor(WebClient client) { + public ClickhouseReactiveSqlExecutor(WebClient client) { this.client = client; } @@ -123,7 +121,6 @@ protected Flux convertQueryResult(JSONObject result, ResultWrapper E rowInstance = wrapper.newRowInstance(); JSONObject oneJsonObjectEntity = (JSONObject) oneObjectEntity; for (String columnName : columns) { -// String columnName = columns.get(i); Object value = oneJsonObjectEntity.get(columnName); ClickhouseDataType dataType = columnMeta.get(columnName); try { diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseSyncSqlExecutor.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseSyncSqlExecutor.java new file mode 100644 index 0000000..880e64e --- /dev/null +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseSyncSqlExecutor.java @@ -0,0 +1,177 @@ +package org.hswebframework.ezorm.rdb.supports.clickhouse; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import lombok.AllArgsConstructor; +import lombok.SneakyThrows; +import org.hswebframework.ezorm.core.meta.Feature; +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.SyncSqlExecutor; +import org.hswebframework.ezorm.rdb.executor.wrapper.ResultWrapper; +import org.hswebframework.web.crud.configuration.ClickhouseProperties; +import org.reactivestreams.Publisher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.lang.reflect.Constructor; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * @className ClickhouseReactiveSqlExecutor + * @Description TODO + * @Author zhong + * @Date 2024/1/16 14:55 + * @Vesion 1.0 + */ +@AllArgsConstructor(staticName = "of") +public class ClickhouseSyncSqlExecutor implements SyncSqlExecutor { + private Logger log = LoggerFactory.getLogger(ClickhouseSyncSqlExecutor.class); + + private RestTemplate restTemplate; + + private String url; + + private HttpHeaders headers; + + public ClickhouseSyncSqlExecutor(ClickhouseProperties clickhouseProperties) { + restTemplate =new RestTemplate(); + this.url=clickhouseProperties.getUrl(); + headers = new HttpHeaders(); + headers.add("X-ClickHouse-User", clickhouseProperties.getUsername()); + headers.add("X-ClickHouse-Key", clickhouseProperties.getPassword()); + } + + public static Feature of(ClickhouseProperties clickhouseProperties) { + return new ClickhouseSyncSqlExecutor(clickhouseProperties); + } + + + + @Override + @SneakyThrows + public int update(SqlRequest request) { + return this + .doExecute(Mono.just(request)) + .then(Mono.just(1)).toFuture().get(30, TimeUnit.SECONDS); + + } + + @Override + @SneakyThrows + public void execute(SqlRequest request) { + + this + .doExecute(Mono.just(request)) + .then() + .toFuture().get(30,TimeUnit.SECONDS); + + } + + @Override + @SneakyThrows + public R select(SqlRequest request, ResultWrapper wrapper) { + this + .doExecute(Mono.just(request)) + .flatMap(response -> convertQueryResult(response, wrapper)) + .collectList().toFuture().get(30,TimeUnit.SECONDS); + + return wrapper.getResult(); + + } + + + private Flux doExecute(Publisher 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); + HttpEntity requestEntity = new HttpEntity<>(sql, headers); + ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); + JSONObject result = JSON.parseObject(responseEntity.getBody()); + + return Mono.just(result); + }) + ; + } + + protected Flux convertQueryResult(JSONObject result, ResultWrapper wrapper) { + + Map columnMeta = new HashMap(); + + JSONArray resultMeta = result.getJSONArray("meta"); + JSONArray resultEntityList = result.getJSONArray("data"); + + if (CollectionUtils.isEmpty(resultMeta) || CollectionUtils.isEmpty(resultEntityList)) { + return Flux.empty(); + } + //把当前列和列类型一一对应 + for (Object o : resultMeta) { + JSONObject e = (JSONObject) o; + columnMeta.put(e.getString("name"), ClickhouseDataType.valueOf(e.getString("type").toUpperCase().replace("NULLABLE(", "").replace(")", ""))); + } + //所有的列名 + ArrayList columns = new ArrayList<>(columnMeta.keySet()); + + return Flux.create(sink -> { + wrapper.beforeWrap(() -> columns); + + for (Object oneObjectEntity : resultEntityList) { + E rowInstance = wrapper.newRowInstance(); + JSONObject oneJsonObjectEntity = (JSONObject) oneObjectEntity; + for (String columnName : columns) { + Object value = oneJsonObjectEntity.get(columnName); + ClickhouseDataType dataType = columnMeta.get(columnName); + try { + Class typeClass = dataType.getJavaType(); + Constructor constructor = typeClass.getConstructor(String.class); + + if (Objects.nonNull(value)) { + value = constructor.newInstance(value.toString()); + } + } catch (Exception e) { + e.printStackTrace(); + } + DefaultColumnWrapperContext context = new DefaultColumnWrapperContext<>(columns.indexOf(columnName), columnName, value, rowInstance); + wrapper.wrapColumn(context); + rowInstance = context.getRowInstance(); + } + if (!wrapper.completedWrapRow(rowInstance)) { + break; + } + if (rowInstance != null) { + sink.next(rowInstance); + } + } + wrapper.completedWrap(); + sink.complete(); + }); + }} + diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/Helper.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/Helper.java index 9f843b1..20fb658 100644 --- a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/Helper.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/Helper.java @@ -15,6 +15,7 @@ import org.hswebframework.ezorm.rdb.metadata.dialect.Dialect; import org.hswebframework.ezorm.rdb.operator.DatabaseOperator; import org.hswebframework.ezorm.rdb.operator.DefaultDatabaseOperator; +import org.hswebframework.web.crud.configuration.ClickhouseProperties; import java.util.function.Supplier; @@ -30,6 +31,8 @@ public interface Helper { ReactiveSqlExecutor getReactiveSqlExecutor(); + ClickhouseProperties getClickhouseProperties(); + default RDBDatabaseMetadata getRDBDatabaseMetadata() { RDBDatabaseMetadata metadata = new RDBDatabaseMetadata(getDialect()); @@ -37,12 +40,10 @@ default RDBDatabaseMetadata getRDBDatabaseMetadata() { ReactiveSqlExecutor sqlExecutor = getReactiveSqlExecutor(); -// schema.addFeature((EventListener) (type, context) -> System.out.println(type)); - metadata.setCurrentSchema(schema); metadata.addSchema(schema); metadata.addFeature(sqlExecutor); - metadata.addFeature(ReactiveSyncSqlExecutor.of(sqlExecutor)); + metadata.addFeature(ClickhouseSyncSqlExecutor.of(getClickhouseProperties())); return metadata; } From 9af65be1638be51171767621c899a74e09b26b6a Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Fri, 19 Jan 2024 11:12:54 +0800 Subject: [PATCH 15/16] =?UTF-8?q?fix:=20=E9=87=8D=E5=86=99=E4=BB=93?= =?UTF-8?q?=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ClickhouseDefaultRepository.java | 262 ++++++++++++++++++ .../ClickhouseReactiveDefaultRepository.java | 163 +++++++++++ .../ezorm/rdb/supports/clickhouse/Helper.java | 4 +- 3 files changed, 426 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDefaultRepository.java create mode 100644 src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseReactiveDefaultRepository.java diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDefaultRepository.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDefaultRepository.java new file mode 100644 index 0000000..93e75a3 --- /dev/null +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseDefaultRepository.java @@ -0,0 +1,262 @@ +package org.hswebframework.ezorm.rdb.supports.clickhouse; + +import lombok.Getter; +import lombok.Setter; +import org.hswebframework.ezorm.core.GlobalConfig; +import org.hswebframework.ezorm.core.ObjectPropertyOperator; +import org.hswebframework.ezorm.rdb.events.ContextKeyValue; +import org.hswebframework.ezorm.rdb.events.ContextKeys; +import org.hswebframework.ezorm.rdb.executor.wrapper.ResultWrapper; +import org.hswebframework.ezorm.rdb.mapping.EntityColumnMapping; +import org.hswebframework.ezorm.rdb.mapping.LazyEntityColumnMapping; +import org.hswebframework.ezorm.rdb.mapping.MappingFeatureType; +import org.hswebframework.ezorm.rdb.mapping.events.EventResultOperator; +import org.hswebframework.ezorm.rdb.mapping.events.MappingContextKeys; +import org.hswebframework.ezorm.rdb.mapping.events.MappingEventTypes; +import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata; +import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata; +import org.hswebframework.ezorm.rdb.operator.DatabaseOperator; +import org.hswebframework.ezorm.rdb.operator.builder.fragments.NativeSql; +import org.hswebframework.ezorm.rdb.operator.dml.insert.InsertOperator; +import org.hswebframework.ezorm.rdb.operator.dml.insert.InsertResultOperator; +import org.hswebframework.ezorm.rdb.operator.dml.upsert.SaveResultOperator; +import org.hswebframework.ezorm.rdb.operator.dml.upsert.UpsertOperator; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import static org.hswebframework.ezorm.rdb.events.ContextKeys.tableMetadata; +import static org.hswebframework.ezorm.rdb.mapping.events.MappingContextKeys.*; +import static org.hswebframework.ezorm.rdb.mapping.events.MappingContextKeys.insert; + +/** + * @className ClickhouseDefaultRepository + * @Description TODO + * @Author zhong + * @Date 2024/1/19 9:32 + * @Vesion 1.0 + */ +public abstract class ClickhouseDefaultRepository { + protected DatabaseOperator operator; + + protected ResultWrapper wrapper; + + private volatile String idColumn; + + @Getter + protected EntityColumnMapping mapping; + + @Setter + protected volatile String[] properties; + + protected Supplier tableSupplier; + + protected final List> defaultContextKeyValue = new ArrayList<>(); + + public ClickhouseDefaultRepository(DatabaseOperator operator, Supplier supplier, ResultWrapper wrapper) { + this.operator = operator; + this.wrapper = wrapper; + this.tableSupplier = supplier; + defaultContextKeyValue.add(repository.value(this)); + defaultContextKeyValue.add(ContextKeys.database.value(operator)); + + } + + protected RDBTableMetadata getTable() { + return tableSupplier.get(); + } + + protected ContextKeyValue[] getDefaultContextKeyValue(ContextKeyValue... kv) { + if (kv.length == 0) { + return defaultContextKeyValue.toArray(new ContextKeyValue[0]); + } + List> keyValues = new ArrayList<>(defaultContextKeyValue); + keyValues.addAll(Arrays.asList(kv)); + return keyValues.toArray(new ContextKeyValue[0]); + } + + public String[] getProperties() { + if (properties == null) { + properties = mapping + .getColumnPropertyMapping() + .entrySet() + .stream() + .filter(kv -> getTable().getColumn(kv.getKey()).isPresent()) + .map(Map.Entry::getValue) + .toArray(String[]::new); + } + return properties; + } + + protected String getIdColumn() { + if (idColumn == null) { + this.idColumn = getTable() + .getColumns() + .stream() + .filter(RDBColumnMetadata::isPrimaryKey) + .findFirst() + .map(RDBColumnMetadata::getName) + .orElseThrow(() -> new UnsupportedOperationException("id column not exists")); + } + return idColumn; + } + + protected void initMapping(Class entityType) { + + this.mapping = LazyEntityColumnMapping.of(() -> getTable() + .findFeature(MappingFeatureType.columnPropertyMapping.createFeatureId(entityType)) + .orElseThrow(() -> new UnsupportedOperationException("unsupported columnPropertyMapping feature"))); + defaultContextKeyValue.add(MappingContextKeys.columnMapping(mapping)); + } + + protected Collection tryMergeDuplicate(Collection data) { + if (data.isEmpty()) { + return data; + } + Map merging = new HashMap<>(data.size()); + List merged = new ArrayList<>(data.size()); + for (E datum : data) { + Object id = getProperty(datum, getIdColumn()); + if (id == null) { + merged.add(datum); + } else { + merging.compute(id, (_id, old) -> { + if (old != null) { + return merge(old, datum); + } + return datum; + }); + } + } + merged.addAll(merging.values()); + return merged; + } + + protected E merge(E older, E newer) { + ObjectPropertyOperator opt = GlobalConfig.getPropertyOperator(); + for (String property : getProperties()) { + Object newerVal = opt.getProperty(newer, property).orElse(null); + if (newerVal != null) { + continue; + } + opt.getProperty(older, property) + .ifPresent(olderValue -> opt.setProperty(newer, property, olderValue)); + + } + return newer; + } + + private Object getProperty(E data, String property) { + return GlobalConfig + .getPropertyOperator() + .getProperty(data, property) + .orElse(null); + } + + protected SaveResultOperator doSave(Collection data) { + Collection _data = tryMergeDuplicate(data); + RDBTableMetadata table = getTable(); + UpsertOperator upsert = operator.dml().upsert(table); + + return EventResultOperator.create( + () -> { + upsert.columns(getProperties()); + List ignore = new ArrayList<>(); + for (E e : _data) { + upsert.values(Stream.of(getProperties()) + .map(property -> getInsertColumnValue(e, property, (prop, val) -> ignore.add(prop))) + .toArray()); + } + upsert.ignoreUpdate(ignore.toArray(new String[0])); + return upsert.execute(); + }, + SaveResultOperator.class, + table, + MappingEventTypes.save_before, + MappingEventTypes.save_after, + getDefaultContextKeyValue(instance(_data), + type("batch"), + tableMetadata(table), + upsert(upsert)) + ); + } + + protected InsertResultOperator doInsert(E data) { + RDBTableMetadata table = getTable(); + InsertOperator insert = operator.dml().insert(table); + + return EventResultOperator.create( + () -> { + for (Map.Entry entry : mapping.getColumnPropertyMapping().entrySet()) { + String column = entry.getKey(); + String property = entry.getValue(); + insert.value(column, getInsertColumnValue(data, property)); + } + return insert.execute(); + }, + InsertResultOperator.class, + table, + MappingEventTypes.insert_before, + MappingEventTypes.insert_after, + getDefaultContextKeyValue( + instance(data), + type("single"), + tableMetadata(table), + insert(insert)) + ); + + } + + private Object getInsertColumnValue(E data, String property, BiConsumer whenDefaultValue) { + Object value = GlobalConfig.getPropertyOperator().getProperty(data, property).orElse(null); + if (value == null) { + value = mapping.getColumnByProperty(property) + .flatMap(RDBColumnMetadata::generateDefaultValue) + .orElse(null); + if (value != null) { + whenDefaultValue.accept(property, value); + //回填 + if (!(value instanceof NativeSql)) { + GlobalConfig.getPropertyOperator().setProperty(data, property, value); + } + } + } + return value; + } + + private Object getInsertColumnValue(E data, String property) { + + return getInsertColumnValue(data, property, (prop, val) -> { + }); + } + + protected InsertResultOperator doInsert(Collection batch) { + Collection _data = tryMergeDuplicate(batch); + RDBTableMetadata table = getTable(); + InsertOperator insert = operator.dml().insert(table); + + return EventResultOperator.create( + () -> { + insert.columns(getProperties()); + + for (E e : _data) { + insert.values(Stream.of(getProperties()) + .map(property -> getInsertColumnValue(e, property)) + .toArray()); + } + return insert.execute(); + }, + InsertResultOperator.class, + table, + MappingEventTypes.insert_before, + MappingEventTypes.insert_after, + getDefaultContextKeyValue( + instance(_data), + type("batch"), + tableMetadata(table), + insert(insert)) + ); + } +} diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseReactiveDefaultRepository.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseReactiveDefaultRepository.java new file mode 100644 index 0000000..cbcbc71 --- /dev/null +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseReactiveDefaultRepository.java @@ -0,0 +1,163 @@ +package org.hswebframework.ezorm.rdb.supports.clickhouse; + +import org.apache.commons.collections4.CollectionUtils; +import org.hswebframework.ezorm.rdb.executor.wrapper.ResultWrapper; +import org.hswebframework.ezorm.rdb.mapping.ReactiveDelete; +import org.hswebframework.ezorm.rdb.mapping.ReactiveQuery; +import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; +import org.hswebframework.ezorm.rdb.mapping.ReactiveUpdate; +import org.hswebframework.ezorm.rdb.mapping.defaults.*; +import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata; +import org.hswebframework.ezorm.rdb.operator.DatabaseOperator; +import org.hswebframework.ezorm.rdb.operator.dml.QueryOperator; +import org.reactivestreams.Publisher; +import org.slf4j.Logger; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Collection; +import java.util.function.Supplier; + +/** + * @className ClickhouseReactiveDefaultRepository + * @Description TODO + * @Author zhong + * @Date 2024/1/19 9:39 + * @Vesion 1.0 + */ +public class ClickhouseReactiveDefaultRepository extends ClickhouseDefaultRepository implements ReactiveRepository { + private final Logger logger; + + public ClickhouseReactiveDefaultRepository(DatabaseOperator operator, String table, Class type, ResultWrapper wrapper) { + this(operator, + () -> operator + .getMetadata() + .getTable(table) + .orElseThrow(() -> new UnsupportedOperationException("table [" + table + "] doesn't exist")), type, wrapper); + } + + public ClickhouseReactiveDefaultRepository(DatabaseOperator operator, RDBTableMetadata table, Class type, ResultWrapper wrapper) { + this(operator, () -> table, type, wrapper); + } + + public ClickhouseReactiveDefaultRepository(DatabaseOperator operator, Supplier table, Class type, ResultWrapper wrapper) { + super(operator, table, wrapper); + initMapping(type); + this.logger = getLogger(type); + } + + private static Logger getLogger(Class type) { + return org.slf4j.LoggerFactory.getLogger(type); + } + + @Override + public Mono newInstance() { + return Mono.fromSupplier(wrapper::newRowInstance); + } + + @Override + public Mono findById(Mono primaryKey) { + return primaryKey + .flatMap(k -> createQuery().where(getIdColumn(), k).fetchOne()); + } + + @Override + public Flux findById(Flux key) { + return key.collectList() + .filter(CollectionUtils::isNotEmpty) + .flatMapMany(idList -> createQuery().where().in(getIdColumn(), idList).fetch()); + } + + @Override + public Mono deleteById(Publisher key) { + return Flux.from(key) + .collectList() + .filter(CollectionUtils::isNotEmpty) + .flatMap(list -> createDelete().where().in(getIdColumn(), list).execute()) + .defaultIfEmpty(0); + } + + @Override + public Mono updateById(K id, Mono data) { + return data + .flatMap(_data -> createUpdate() + .where(getIdColumn(), id) + .set(_data) + .execute()); + } + + @Override + public Mono save(Publisher data) { + return Flux + .from(data) + .collectList() + .filter(CollectionUtils::isNotEmpty) + .flatMap(list -> doSave(list).reactive().as(this::setupLogger)) + .defaultIfEmpty(SaveResult.of(0, 0)); + } + + @Override + public Mono insert(Publisher data) { + return Flux + .from(data) + .buffer(100) + .as(this::insertBatch); + } + + @Override + public Mono insertBatch(Publisher> data) { + return Flux + .from(data) + .filter(CollectionUtils::isNotEmpty) + .flatMap(e -> doInsert(e).reactive()) + .reduce(Math::addExact) + .defaultIfEmpty(0) + .as(this::setupLogger); + } + + @Override + public ReactiveQuery createQuery() { + return new DefaultReactiveQuery<>(getTable() + , mapping + , operator.dml() + , wrapper + , logger + , getDefaultContextKeyValue()); + } + + @Override + public ReactiveUpdate createUpdate() { + return new DefaultReactiveUpdate<>( + getTable() + , operator.dml().update(getTable().getFullName()) + , mapping + , logger + , getDefaultContextKeyValue()); + } + + @Override + public ReactiveDelete createDelete() { + return new DefaultReactiveDelete(getTable() + , operator.dml().delete(getTable().getFullName()) + , logger + , getDefaultContextKeyValue() + ); + } + + + private Mono setupLogger(Mono async) { + return async.contextWrite(ctx -> ctx.put(Logger.class, logger)); + } + + private Flux setupLogger(Flux async) { + return async.contextWrite(ctx -> ctx.put(Logger.class, logger)); + } + + + @Override + public QueryOperator nativeQuery() { + return operator + .dml() + .query(getTable()); + } +} diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/Helper.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/Helper.java index 20fb658..1871b42 100644 --- a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/Helper.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/Helper.java @@ -85,9 +85,7 @@ public Object get() { wrapper.setMapping(table .getFeature(MappingFeatureType.columnPropertyMapping.createFeatureId(clazz)) .orElseThrow(NullPointerException::new)); - - - return new DefaultReactiveRepository<>(operator, table, clazz, wrapper); + return new ClickhouseReactiveDefaultRepository<>(operator, table, clazz, wrapper); } } From 2cd2c515d1c8bac8181da16e504e99af40c2d913 Mon Sep 17 00:00:00 2001 From: PengyuDeng <89559616+PengyuDeng@users.noreply.github.com> Date: Thu, 7 Mar 2024 15:58:20 +0800 Subject: [PATCH 16/16] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=AF=AD?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ClickhouseTableMetadataParser.java | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseTableMetadataParser.java b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseTableMetadataParser.java index a5f956a..40e7197 100644 --- a/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseTableMetadataParser.java +++ b/src/main/java/org/hswebframework/ezorm/rdb/supports/clickhouse/ClickhouseTableMetadataParser.java @@ -1,11 +1,23 @@ package org.hswebframework.ezorm.rdb.supports.clickhouse; +import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSqlExecutor; +import org.hswebframework.ezorm.rdb.mapping.defaults.record.RecordResultWrapper; +import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata; +import org.hswebframework.ezorm.rdb.metadata.RDBIndexMetadata; import org.hswebframework.ezorm.rdb.metadata.RDBSchemaMetadata; import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata; +import org.hswebframework.ezorm.rdb.metadata.parser.IndexMetadataParser; import org.hswebframework.ezorm.rdb.supports.commons.RDBTableMetadataParser; +import org.hswebframework.utils.StringUtils; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import java.util.HashMap; import java.util.List; +import java.util.Map; + +import static org.hswebframework.ezorm.rdb.executor.SqlRequests.template; +import static org.hswebframework.ezorm.rdb.executor.wrapper.ResultWrappers.singleMap; /** * @className Clickhouse @@ -24,7 +36,7 @@ public class ClickhouseTableMetadataParser extends RDBTableMetadataParser { "numeric_scale as `data_scale`,", "column_comment as `comment`,", "table_name as `table_name`,", - "case when is_nullable=0 then 0 else 1 end ", + "case is_nullable when 0 then 0 else 1 end ", "from information_schema.columns where table_schema=#{schema} and table_name like #{table}"); private static final String TABLE_COMMENT_SQL = String.join(" ", @@ -71,5 +83,65 @@ public List parseAll() { public Flux parseAllReactive() { return super.fastParseAllReactive(); } + @Override + public Mono parseByNameReactive(String name) { + return tableExistsReactive(name) + .filter(Boolean::booleanValue) + .flatMap(ignore -> { + RDBTableMetadata metaData = createTable(name); + metaData.setName(name); + metaData.setAlias(name); + Map param = new HashMap<>(); + param.put("table", name); + param.put("schema", schema.getName()); + ReactiveSqlExecutor reactiveSqlExecutor = getReactiveSqlExecutor(); + //列 + Mono> columns = reactiveSqlExecutor + .select(template(getTableMetaSql(null), param), new RecordResultWrapper()) + .map(record -> { + RDBColumnMetadata column = metaData.newColumn(); + applyColumnInfo(column, record); + if (!StringUtils.isNullOrEmpty(column.getAlias())){ + column.setAlias(getAlias(column.getName())); + } + metaData.addColumn(column); + return column; + }) + .collectList(); + //注释 + Mono> comments = reactiveSqlExecutor + .select(template(getTableCommentSql(name), param), singleMap()) + .doOnNext(comment -> metaData.setComment(String.valueOf(comment.get("comment")))) + .singleOrEmpty(); + + //加载索引 + Flux index = schema.findFeature(IndexMetadataParser.ID) + .map(parser -> parser.parseTableIndexReactive(name)) + .orElseGet(Flux::empty) + .doOnNext(metaData::addIndex); + return Flux + .merge(columns, comments, index) + .then(Mono.just(metaData)); + }) + ; + } + private String getAlias(String name) {//处理驼峰命名 + StringBuilder result = new StringBuilder(); + boolean nextUpperCase = false; + for (int i = 0; i < name.length(); i++) { + char currentChar = name.charAt(i); + if (currentChar == '_') { + nextUpperCase = true; + } else { + if (nextUpperCase) { + result.append(Character.toUpperCase(currentChar)); + nextUpperCase = false; + } else { + result.append(Character.toLowerCase(currentChar)); + } + } + } + return result.toString(); + } }