Skip to content

Commit 4e603fa

Browse files
author
Weasley
committed
Support that DTT can deduce the number of decimals for high precision data types
1 parent 2cbf338 commit 4e603fa

File tree

18 files changed

+248
-46
lines changed

18 files changed

+248
-46
lines changed

mydtt-plus-spring-boot-starter/src/main/java/cn/alphahub/dtt/plus/config/DttProperties.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ public class DttProperties {
9595
*/
9696
@NestedConfigurationProperty
9797
private List<StringLengthMapper> stringLengthMapper;
98+
/**
99+
* The mapper configuration for handling the number of decimals for high precision data types
100+
*/
101+
@NestedConfigurationProperty
102+
private HighPrecisionDataMapper highPrecisionDataMapper;
98103

99104
/**
100105
* The configuration property of DTT-MyBatis,<br>
@@ -349,4 +354,67 @@ public static class LengthProperties {
349354
private Integer length;
350355
}
351356
}
357+
358+
/**
359+
* The mapper of high precision data types
360+
*/
361+
@Data
362+
@ConfigurationProperties(prefix = "alphahub.dtt.high-precision-data-mapper")
363+
public static class HighPrecisionDataMapper {
364+
/**
365+
* The default high precision data type of Java.
366+
*/
367+
private String highPrecisionDataType = "BigDecimal";
368+
/**
369+
* The default integer part length of high precision data type.
370+
*/
371+
private Integer defaultIntegerLength = 10;
372+
/**
373+
* The default decimal part length of high precision data type.
374+
*/
375+
private Integer defaultDecimalLength = 6;
376+
/**
377+
* The precision configuration list for some text.
378+
*/
379+
@NestedConfigurationProperty
380+
private List<PrecisionConfigurationProperties> precisionConfigs;
381+
382+
/**
383+
* The precision configuration list for some text. i.e:
384+
* <p>
385+
* Take <b>MySQL<b> as an example, if you have the following configuration.
386+
* <pre>
387+
* alphahub:
388+
* dtt:
389+
* high-precision-data-mapper:
390+
* high-precision-data-type: BigDecimal
391+
* default-integer-length: 10
392+
* default-decimal-length: 6
393+
* precision-configs:
394+
* - text: price,amount
395+
* integer-length: 10
396+
* decimal-length: 2
397+
* </pre>
398+
* <p>
399+
* When a column of some table contains 'price' or 'amount',
400+
* DTT will infer the data type of the database point for this column as: decimal(10,2)
401+
*/
402+
@Data
403+
@ConfigurationProperties(prefix = "alphahub.dtt.high-precision-data-mapper.precision-configs")
404+
public static class PrecisionConfigurationProperties {
405+
/**
406+
* The text property is the content you want some column contained,
407+
* Multiple 'text' be separated by commas(","). i.e: price,amount
408+
*/
409+
private String text;
410+
/**
411+
* The length of integer part
412+
*/
413+
private Integer integerLength;
414+
/**
415+
* The length of decimal part
416+
*/
417+
private Integer decimalLength;
418+
}
419+
}
352420
}

mydtt-plus-spring-boot-starter/src/main/java/cn/alphahub/dtt/plus/entity/ContextWrapper.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import java.util.Map;
1414
import java.util.concurrent.atomic.AtomicReference;
1515

16+
import static cn.alphahub.dtt.plus.config.DttProperties.HighPrecisionDataMapper;
17+
import static cn.alphahub.dtt.plus.config.DttProperties.HighPrecisionDataMapper.PrecisionConfigurationProperties;
1618
import static cn.alphahub.dtt.plus.config.DttProperties.StringLengthMapper;
1719

1820
/**
@@ -44,6 +46,10 @@ public class ContextWrapper implements Serializable {
4446
* text length handler
4547
*/
4648
private TextLengthHandler textLengthHandler;
49+
/**
50+
* The high precision data handler
51+
*/
52+
private HighPrecisionDataHandler highPrecisionDataHandler;
4753
/**
4854
* 运行时间统计
4955
*/
@@ -88,4 +94,23 @@ public static class TextLengthHandler implements Serializable {
8894
*/
8995
private Map<String, Integer> textLengthProperties;
9096
}
97+
98+
/**
99+
* High precision data handler
100+
*/
101+
@Data
102+
@NoArgsConstructor
103+
@AllArgsConstructor
104+
public static class HighPrecisionDataHandler implements Serializable {
105+
/**
106+
* High precision data mapper
107+
*/
108+
private HighPrecisionDataMapper highPrecisionDataMapper;
109+
/**
110+
* key: Some text of column
111+
* <br>
112+
* value: The precision configuration properties
113+
*/
114+
private Map<String, PrecisionConfigurationProperties> highPrecisionDataConfigMap;
115+
}
91116
}

mydtt-plus-spring-boot-starter/src/main/java/cn/alphahub/dtt/plus/framework/InitDttClient.java

Lines changed: 63 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343
import java.util.concurrent.atomic.AtomicReference;
4444
import java.util.stream.Collectors;
4545

46-
import static cn.alphahub.dtt.plus.config.DttProperties.StringLengthMapper;
47-
import static cn.alphahub.dtt.plus.config.DttProperties.StringLengthMapper.LengthProperties;
46+
import static cn.alphahub.dtt.plus.config.DttProperties.HighPrecisionDataMapper.PrecisionConfigurationProperties;
47+
import static cn.alphahub.dtt.plus.entity.ContextWrapper.HighPrecisionDataHandler;
4848
import static cn.alphahub.dtt.plus.framework.InitDttHandler.getEnableDtt;
4949

5050
/**
@@ -111,7 +111,6 @@ public Map<DatabaseType, DttTableHandler<ModelEntity>> tableHandlerClient(Applic
111111
* @param dttProperties dttProperties
112112
* @return DTT context wrapper
113113
*/
114-
@SuppressWarnings({"all"})
115114
@Bean
116115
@DependsOn({"commentParserClient", "commentParserClient"})
117116
public ContextWrapper contextWrapper(@Qualifier("commentParserClient") Map<ParserType, DttCommentParser<ModelEntity>> commentParserClient,
@@ -129,26 +128,11 @@ public ContextWrapper contextWrapper(@Qualifier("commentParserClient") Map<Parse
129128
.dttRunDetail(new ContextWrapper.DttRunDetail(LocalDateTime.now()))
130129
.build();
131130

132-
List<StringLengthMapper> lengthMappers = dttProperties.getStringLengthMapper();
133-
if (ObjectUtils.isNotEmpty(lengthMappers)) {
134-
Map<DatabaseType, StringLengthMapper> mapperMap = lengthMappers.stream().collect(Collectors.toMap(StringLengthMapper::getDatabaseType, v -> v));
135-
if (ObjectUtils.isNotEmpty(mapperMap)) {
136-
StringLengthMapper stringLengthMapper = mapperMap.get(databaseHandler.getDbType());
137-
if (ObjectUtils.allNotNull(stringLengthMapper)) {
138-
List<LengthProperties> lengthConfigs = stringLengthMapper.getLengthConfigs();
139-
if (ObjectUtils.isNotEmpty(lengthConfigs)) {
140-
Map<String, Integer> textLengthPropertiesMap = lengthConfigs.stream().collect(Collectors.toMap(LengthProperties::getText, LengthProperties::getLength));
141-
if (ObjectUtils.isNotEmpty(textLengthPropertiesMap)) {
142-
// Get the length of the 'String' type configured by the user
143-
ContextWrapper.TextLengthHandler handler = new ContextWrapper.TextLengthHandler();
144-
handler.setStringLengthMapper(stringLengthMapper);
145-
handler.setTextLengthProperties(textLengthPropertiesMap);
146-
wrapper.setTextLengthHandler(handler);
147-
}
148-
}
149-
}
150-
}
151-
}
131+
// parse string length mapper
132+
parseStringLengthMapper(dttProperties, databaseHandler, wrapper);
133+
134+
// Parse high precision data handler
135+
parseHighPrecisionDataHandler(wrapper, dttProperties);
152136

153137
return wrapper;
154138
}
@@ -202,4 +186,60 @@ public DatabaseProperty databaseProperty(DataSource dataSource,
202186
property.setDatabaseName(databaseName);
203187
return property;
204188
}
189+
190+
191+
/**
192+
* Parse the high precision data handler
193+
*
194+
* @param wrapper The wrapper of DTT context
195+
* @param dttProperties The properties of DTT
196+
* @param databaseHandler The handler of DTT supported database
197+
*/
198+
protected void parseStringLengthMapper(DttProperties dttProperties, DatabaseHandler databaseHandler, ContextWrapper wrapper) {
199+
List<DttProperties.StringLengthMapper> lengthMappers = dttProperties.getStringLengthMapper();
200+
if (ObjectUtils.isNotEmpty(lengthMappers)) {
201+
Map<DatabaseType, DttProperties.StringLengthMapper> mapperMap = lengthMappers.stream().collect(Collectors.toMap(DttProperties.StringLengthMapper::getDatabaseType, v -> v));
202+
if (ObjectUtils.isNotEmpty(mapperMap)) {
203+
DttProperties.StringLengthMapper stringLengthMapper = mapperMap.get(databaseHandler.getDbType());
204+
if (ObjectUtils.allNotNull(stringLengthMapper)) {
205+
List<DttProperties.StringLengthMapper.LengthProperties> lengthConfigs = stringLengthMapper.getLengthConfigs();
206+
if (ObjectUtils.isNotEmpty(lengthConfigs)) {
207+
Map<String, Integer> textLengthPropertiesMap = lengthConfigs.stream().collect(Collectors.toMap(DttProperties.StringLengthMapper.LengthProperties::getText, DttProperties.StringLengthMapper.LengthProperties::getLength));
208+
if (ObjectUtils.isNotEmpty(textLengthPropertiesMap)) {
209+
// Get the length of the 'String' type configured by the user
210+
ContextWrapper.TextLengthHandler handler = new ContextWrapper.TextLengthHandler();
211+
handler.setStringLengthMapper(stringLengthMapper);
212+
handler.setTextLengthProperties(textLengthPropertiesMap);
213+
wrapper.setTextLengthHandler(handler);
214+
}
215+
}
216+
}
217+
}
218+
}
219+
}
220+
221+
/**
222+
* Parse the high precision data handler
223+
*
224+
* @param contextWrapper The wrapper of DTT context
225+
* @param dttProperties The properties of DTT
226+
*/
227+
protected void parseHighPrecisionDataHandler(ContextWrapper contextWrapper, DttProperties dttProperties) {
228+
Map<String, PrecisionConfigurationProperties> highPrecisionDataConfigMap = new ConcurrentHashMap<>(256);
229+
List<PrecisionConfigurationProperties> precisionConfigs = dttProperties.getHighPrecisionDataMapper().getPrecisionConfigs();
230+
if (CollectionUtils.isNotEmpty(precisionConfigs)) {
231+
precisionConfigs.forEach(properties -> {
232+
String[] textArray = properties.getText().split(",");
233+
if (ObjectUtils.isNotEmpty(textArray)) {
234+
for (String text : textArray) {
235+
highPrecisionDataConfigMap.put(text, properties);
236+
}
237+
}
238+
});
239+
}
240+
HighPrecisionDataHandler dataHandler = new HighPrecisionDataHandler();
241+
dataHandler.setHighPrecisionDataConfigMap(highPrecisionDataConfigMap);
242+
dataHandler.setHighPrecisionDataMapper(dttProperties.getHighPrecisionDataMapper());
243+
contextWrapper.setHighPrecisionDataHandler(dataHandler);
244+
}
205245
}

mydtt-plus-spring-boot-starter/src/main/java/cn/alphahub/dtt/plus/framework/InitDttHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@
5757
@Data
5858
@Component
5959
@AutoConfigureAfter({InitDttClient.class})
60-
@ConfigurationPropertiesScan({"cn.alphahub.dtt.plus.config"})
61-
@EnableConfigurationProperties({DttProperties.class, DataTypeMapperProperties.class, AllInOneTableProperties.class, LengthProperties.class})
6260
@ConditionalOnBean(annotation = {EnableDtt.class})
61+
@ConfigurationPropertiesScan({"cn.alphahub.dtt.plus.config"})
62+
@EnableConfigurationProperties({DttProperties.class, DataTypeMapperProperties.class, AllInOneTableProperties.class, LengthProperties.class,})
6363
public class InitDttHandler implements ApplicationRunner {
6464
/**
6565
* 域模型集合, 默认大小:512

mydtt-plus-spring-boot-starter/src/main/java/cn/alphahub/dtt/plus/framework/core/DefaultDb2TableHandler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public String create(ParseFactory<ModelEntity> parseFactory) {
4242
return null;
4343
}
4444

45+
deduceDecimalPrecision(model);
46+
4547
ContextWrapper contextWrapper = SpringUtil.getBean(ContextWrapper.class);
4648
model.getDetails().forEach(detail -> {
4749
if (Objects.equals(Enum.class.getSimpleName(), detail.getJavaDataType())) {

mydtt-plus-spring-boot-starter/src/main/java/cn/alphahub/dtt/plus/framework/core/DefaultMariadbTableHandler.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public String create(ParseFactory<ModelEntity> parseFactory) {
3939
logger.warn("表结构元数据解析结果不能为空 {}", model);
4040
return null;
4141
}
42+
deduceDecimalPrecision(model);
4243
logger.info("正在组建建表语句,模型数据: {}", JacksonUtil.toJson(model));
4344
if (StringUtils.isNoneBlank(model.getDatabaseName())) {
4445
String databaseName = model.getDatabaseName();

mydtt-plus-spring-boot-starter/src/main/java/cn/alphahub/dtt/plus/framework/core/DefaultMysqlTableHandler.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,16 @@ public class DefaultMysqlTableHandler extends DttAggregationRunner implements Dt
3434
*/
3535
@Override
3636
public String create(ParseFactory<ModelEntity> parseFactory) {
37-
if (logger.isDebugEnabled()) logger.debug("使用mysql默认建表实现 {}", JacksonUtil.toJson(parseFactory.getModel()));
37+
if (logger.isDebugEnabled())
38+
logger.debug("使用mysql默认建表实现 {}", JacksonUtil.toJson(parseFactory.getModel()));
3839
ModelEntity model = parseFactory.getModel();
3940
if (null == model || CollectionUtils.isEmpty(model.getDetails())) {
4041
logger.warn("表结构元数据解析结果不能为空 {}", model);
4142
return null;
4243
}
4344

45+
deduceDecimalPrecision(model);
46+
4447
if (logger.isInfoEnabled()) {
4548
logger.info("正在组建建表语句,模型数据: {}", JacksonUtil.toJson(model));
4649
}

mydtt-plus-spring-boot-starter/src/main/java/cn/alphahub/dtt/plus/framework/core/DefaultOracleTableHandler.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public String create(ParseFactory<ModelEntity> parseFactory) {
5353

5454
//处理Oracle数据类型
5555
handlingOracleDataTypes(model);
56+
deduceDecimalPrecision(model);
5657

5758
if (oracleDataMapperProperties.getEnableColumnUpperCase().equals(true)) toRootUpperCase(() -> model);
5859

mydtt-plus-spring-boot-starter/src/main/java/cn/alphahub/dtt/plus/framework/core/DefaultSqlserverTableHandler.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
import org.springframework.stereotype.Component;
1515
import org.springframework.util.CollectionUtils;
1616

17+
import java.util.Arrays;
18+
import java.util.List;
19+
import java.util.Locale;
1720
import java.util.Objects;
1821
import java.util.Properties;
1922

@@ -54,10 +57,28 @@ public String create(ParseFactory<ModelEntity> parseFactory) {
5457
});
5558

5659
VelocityContext velocityContext = new VelocityContext();
57-
velocityContext.put("defaultCollate", sqlserverDataMapperProperties.getDefaultCollate());
60+
velocityContext.put("defaultCollate", getDefaultCollate(sqlserverDataMapperProperties));
5861
String template = resolve(() -> model, velocityContext);
5962
String[] pureSQL = template.split("GO\n");
6063
batchExecute(pureSQL);
6164
return template;
6265
}
66+
67+
68+
/**
69+
* Get default collate
70+
* <p>
71+
* Solve Chinese garbled characters
72+
*
73+
* @param properties The mapper of Java data type mapping with sqlserver
74+
* @return collate
75+
*/
76+
private String getDefaultCollate(SqlserverDataMapperProperties properties) {
77+
Locale locale = Locale.getDefault();
78+
List<String> simplifiedChinese = Arrays.asList("zh", "zh-CN", "zh-Hans", "zh-Hans-CN");
79+
List<String> traditionalChinese = Arrays.asList("zh-HK", "zh-TW", "zh-Hans-HK", "zh-Hans-TW");
80+
if (simplifiedChinese.contains(locale.toLanguageTag())) return "Chinese_PRC_CI_AS";
81+
if (traditionalChinese.contains(locale.toLanguageTag())) return "Chinese_Taiwan_Stroke_CI_AS";
82+
return properties.getDefaultCollate();
83+
}
6384
}

mydtt-plus-spring-boot-starter/src/main/java/cn/alphahub/dtt/plus/framework/core/DttTableHandler.java

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,31 @@
11
package cn.alphahub.dtt.plus.framework.core;
22

33

4+
import cn.alphahub.dtt.plus.config.DttProperties;
5+
import cn.alphahub.dtt.plus.entity.ContextWrapper;
46
import cn.alphahub.dtt.plus.entity.ModelEntity;
57
import cn.alphahub.dtt.plus.util.SysUtil;
8+
import cn.hutool.extra.spring.SpringUtil;
9+
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
610
import org.apache.commons.lang3.StringUtils;
7-
import org.springframework.util.CollectionUtils;
811
import org.springframework.util.ObjectUtils;
912

1013
import java.util.ArrayList;
1114
import java.util.Collections;
1215
import java.util.List;
16+
import java.util.Map;
1317
import java.util.Properties;
1418
import java.util.Set;
1519
import java.util.stream.Collectors;
1620

21+
import static cn.alphahub.dtt.plus.config.DttProperties.HighPrecisionDataMapper;
22+
import static cn.alphahub.dtt.plus.entity.ContextWrapper.HighPrecisionDataHandler;
23+
1724
/**
1825
* 创建数据库建表语句上层接口
1926
*
2027
* @author weasley
21-
* @version 1.0
22-
* @date 2022/7/10
28+
* @version 1.0.0
2329
*/
2430
@FunctionalInterface
2531
public interface DttTableHandler<T> extends DttContext<T> {
@@ -117,4 +123,33 @@ default List<String[]> splitArrayToBatchList(String[] sqlArray, int batchSize) {
117123
return splitList;
118124
}
119125

126+
/**
127+
* Deduce the number of decimals for high precision data types
128+
*
129+
* @param model The model be processed
130+
*/
131+
default void deduceDecimalPrecision(ModelEntity model) {
132+
if (null == model || CollectionUtils.isEmpty(model.getDetails())) return;
133+
134+
HighPrecisionDataHandler precisionDataHandler = SpringUtil.getBean(ContextWrapper.class).getHighPrecisionDataHandler();
135+
HighPrecisionDataMapper precisionDataMapper = precisionDataHandler.getHighPrecisionDataMapper();
136+
137+
model.getDetails().forEach(detail -> {
138+
if (precisionDataMapper.getHighPrecisionDataType().compareToIgnoreCase(detail.getJavaDataType()) == 0) {
139+
String dbDataType = detail.getDatabaseDataType();
140+
String inferDataType = "";
141+
if (CollectionUtils.isNotEmpty(precisionDataHandler.getHighPrecisionDataConfigMap())) {
142+
for (Map.Entry<String, DttProperties.HighPrecisionDataMapper.PrecisionConfigurationProperties> entry : precisionDataHandler.getHighPrecisionDataConfigMap().entrySet()) {
143+
if (detail.getFiledName().toLowerCase().contains(entry.getKey())) {
144+
inferDataType = detail.getDatabaseDataType() + "(" + entry.getValue().getIntegerLength() + "," + entry.getValue().getDecimalLength() + ")";
145+
break;
146+
}
147+
}
148+
}
149+
String inferDbDataTypeWithDefaultPrecision = dbDataType + "(" + precisionDataMapper.getDefaultIntegerLength() + "," + precisionDataMapper.getDefaultDecimalLength() + ")";
150+
detail.setDatabaseDataType(StringUtils.defaultIfBlank(inferDataType, inferDbDataTypeWithDefaultPrecision));
151+
}
152+
});
153+
}
154+
120155
}

0 commit comments

Comments
 (0)