Commit 7b5aa23d5cdc55779ff3048d6cc2e04e82b24b3e

Authored by 安浩浩
1 parent ea8dd67e

【功能优化】 产品发布创建超级表优化

Showing 13 changed files with 486 additions and 366 deletions
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java
1 1 package cn.iocoder.yudao.module.iot.domain;
2 2  
  3 +import lombok.Builder;
3 4 import lombok.Data;
4 5  
5 6 import java.sql.SQLException;
6 7 import java.util.ArrayList;
7 8 import java.util.List;
8 9  
  10 +/**
  11 + * 字段信息 VO
  12 + */
9 13 @Data
  14 +@Builder
10 15 public class FieldsVo {
11   - private static final long serialVersionUID = 1L;
12 16  
13 17 /**
14 18 * 字段名称
... ... @@ -24,24 +28,4 @@ public class FieldsVo {
24 28 * 字段字节大小
25 29 */
26 30 private Integer size;
27   -
28   - public static FieldsVo fieldsTranscoding(Fields fields) throws SQLException {
29   -// if (StringUtils.isBlank(fields.getFieldName()) || fields.getDataType() == null) {
30   -// throw new SQLException("invalid operation: fieldName or dataType can not be null");
31   -// }
32   -// FieldsVo fieldsVo = new FieldsVo();
33   -// fieldsVo.setFieldName(fields.getFieldName());
34   -// fieldsVo.setDataType(fields.getDataType().getDataType());
35   -// fieldsVo.setSize(fields.getSize());
36   -// return fieldsVo;
37   - return null;
38   - }
39   -
40   - public static List<FieldsVo> fieldsTranscoding(List<Fields> fieldsList) throws SQLException {
41   - List<FieldsVo> fieldsVoList = new ArrayList<>();
42   - for (Fields fields : fieldsList) {
43   - fieldsVoList.add(fieldsTranscoding(fields));
44   - }
45   - return fieldsVoList;
46   - }
47 31 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java
... ... @@ -10,7 +10,6 @@ import java.util.stream.Collectors;
10 10  
11 11 /**
12 12 * FieldParser 类用于解析和转换物模型字段到 TDengine 字段
13   - *
14 13 */
15 14 public class FieldParser {
16 15  
... ... @@ -35,49 +34,58 @@ public class FieldParser {
35 34 * @param property 物模型属性
36 35 * @return TdField对象
37 36 */
38   - public static TdField parse(ThingModelProperty property) {
  37 + public static TdFieldDO parse(ThingModelProperty property) {
39 38 String fieldName = property.getIdentifier().toLowerCase();
40 39 ThingModelDataType type = property.getDataType();
41 40  
42 41 // 将物模型字段类型映射为td字段类型
43 42 String fType = TYPE_MAPPING.get(type.getType().toUpperCase());
44 43  
45   - int len = -1;
46 44 // 如果字段类型为NCHAR,默认长度为64
  45 + int dataLength = 0;
47 46 if ("NCHAR".equals(fType)) {
48   - len = 64;
  47 + dataLength = 64;
49 48 }
50   -
51   - return new TdField(fieldName, fType, len);
  49 + return new TdFieldDO(fieldName, fType, dataLength);
52 50 }
53 51  
54 52 /**
55   - * 获取物模型中的字段列表
  53 + * 从物模型中获取字段列表
  54 + *
  55 + * @param thingModel 物模型响应对象
  56 + * @return 字段列表
56 57 */
57   - public static List<TdField> parse(ThingModelRespVO thingModel) {
58   - return thingModel.getModel().getProperties().stream().map(FieldParser::parse).collect(Collectors.toList());
  58 + public static List<TdFieldDO> parse(ThingModelRespVO thingModel) {
  59 + return thingModel.getModel().getProperties().stream()
  60 + .map(FieldParser::parse)
  61 + .collect(Collectors.toList());
59 62 }
60 63  
61 64 /**
62   - * 将从库中查出来的字段信息转换为td字段对象
  65 + * 将从库中查出来的字段信息转换为 TDengine 字段对象
  66 + *
  67 + * @param rows 从库中查出的字段信息列表
  68 + * @return 转换后的 TDengine 字段对象列表
63 69 */
64   - public static List<TdField> parse(List<List<Object>> rows) {
  70 + public static List<TdFieldDO> parse(List<List<Object>> rows) {
65 71 return rows.stream().map(row -> {
66 72 String type = row.get(1).toString().toUpperCase();
67   - return new TdField(
  73 + int dataLength = "NCHAR".equals(type) ? Integer.parseInt(row.get(2).toString()) : -1;
  74 + return new TdFieldDO(
68 75 row.get(0).toString(),
69 76 type,
70   - type.equals("NCHAR") ? Integer.parseInt(row.get(2).toString()) : -1);
  77 + dataLength
  78 + );
71 79 }).collect(Collectors.toList());
72 80 }
73 81  
74 82 /**
75 83 * 获取字段字义
76 84 */
77   - public static String getFieldDefine(TdField field) {
78   - return "`" + field.getName() + "`" + " "
79   - + (field.getLength() > 0 ? String.format("%s(%d)", field.getType(), field.getLength())
80   - : field.getType());
  85 + public static String getFieldDefine(TdFieldDO field) {
  86 + return "`" + field.getFieldName() + "`" + " "
  87 + + (field.getDataLength() > 0 ? String.format("%s(%d)", field.getDataType(), field.getDataLength())
  88 + : field.getDataType());
81 89 }
82 90  
83 91 -}
  92 +}
84 93 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java
... ... @@ -36,4 +36,4 @@ public class TableData {
36 36 * 超级表名称
37 37 */
38 38 private String superTableName;
39 39 -}
  40 +}
40 41 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java
... ... @@ -45,7 +45,7 @@ public class TableManager {
45 45 /**
46 46 * 获取创建表sql
47 47 */
48   - public static String getCreateSTableSql(String tbName, List<TdField> fields, TdField... tags) {
  48 + public static String getCreateSTableSql(String tbName, List<TdFieldDO> fields, TdFieldDO... tags) {
49 49 if (fields.isEmpty()) {
50 50 return null;
51 51 }
... ... @@ -53,7 +53,7 @@ public class TableManager {
53 53 // 生成字段片段
54 54 StringBuilder sbField = new StringBuilder("time TIMESTAMP,");
55 55  
56   - for (TdField field : fields) {
  56 + for (TdFieldDO field : fields) {
57 57 sbField.append(FieldParser.getFieldDefine(field));
58 58 sbField.append(",");
59 59 }
... ... @@ -63,7 +63,7 @@ public class TableManager {
63 63  
64 64 // 生成tag
65 65 StringBuilder sbTag = new StringBuilder();
66   - for (TdField tag : tags) {
  66 + for (TdFieldDO tag : tags) {
67 67 sbTag.append(FieldParser.getFieldDefine(tag))
68 68 .append(",");
69 69 }
... ... @@ -76,7 +76,7 @@ public class TableManager {
76 76 /**
77 77 * 获取创建普通表sql
78 78 */
79   - public static String getCreateCTableSql(String tbName, List<TdField> fields) {
  79 + public static String getCreateCTableSql(String tbName, List<TdFieldDO> fields) {
80 80 if (fields.size() == 0) {
81 81 return null;
82 82 }
... ... @@ -84,7 +84,7 @@ public class TableManager {
84 84 //生成字段片段
85 85 StringBuilder sbField = new StringBuilder("time timestamp,");
86 86  
87   - for (TdField field : fields) {
  87 + for (TdFieldDO field : fields) {
88 88 sbField.append(FieldParser.getFieldDefine(field));
89 89 sbField.append(",");
90 90 }
... ... @@ -116,9 +116,9 @@ public class TableManager {
116 116 /**
117 117 * 获取添加字段sql
118 118 */
119   - public static String getAddSTableColumnSql(String tbName, List<TdField> fields) {
  119 + public static String getAddSTableColumnSql(String tbName, List<TdFieldDO> fields) {
120 120 StringBuilder sbAdd = new StringBuilder();
121   - for (TdField field : fields) {
  121 + for (TdFieldDO field : fields) {
122 122 sbAdd.append(String.format(ALTER_STABLE_ADD_COL_TPL,
123 123 tbName,
124 124 FieldParser.getFieldDefine(field)
... ... @@ -130,9 +130,9 @@ public class TableManager {
130 130 /**
131 131 * 获取修改字段sql
132 132 */
133   - public static String getModifySTableColumnSql(String tbName, List<TdField> fields) {
  133 + public static String getModifySTableColumnSql(String tbName, List<TdFieldDO> fields) {
134 134 StringBuilder sbModify = new StringBuilder();
135   - for (TdField field : fields) {
  135 + for (TdFieldDO field : fields) {
136 136 sbModify.append(String.format(ALTER_STABLE_MODIFY_COL_TPL,
137 137 tbName,
138 138 FieldParser.getFieldDefine(field)
... ... @@ -144,15 +144,15 @@ public class TableManager {
144 144 /**
145 145 * 获取删除字段sql
146 146 */
147   - public static String getDropSTableColumnSql(String tbName, List<TdField> fields) {
  147 + public static String getDropSTableColumnSql(String tbName, List<TdFieldDO> fields) {
148 148 StringBuilder sbDrop = new StringBuilder();
149   - for (TdField field : fields) {
  149 + for (TdFieldDO field : fields) {
150 150 sbDrop.append(String.format(ALTER_STABLE_DROP_COL_TPL,
151 151 tbName,
152   - field.getName()
  152 + field.getFieldName()
153 153 ));
154 154 }
155 155 return sbDrop.toString();
156 156 }
157 157  
158 158 -}
  159 +}
159 160 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdField.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java
1 1 package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine;
2 2  
3 3 import lombok.AllArgsConstructor;
  4 +import lombok.Builder;
4 5 import lombok.Data;
5 6 import lombok.NoArgsConstructor;
6 7  
... ... @@ -10,20 +11,21 @@ import lombok.NoArgsConstructor;
10 11 @Data
11 12 @NoArgsConstructor
12 13 @AllArgsConstructor
13   -public class TdField {
  14 +@Builder
  15 +public class TdFieldDO {
14 16  
15 17 /**
16 18 * 字段名称
17 19 */
18   - private String name;
  20 + private String fieldName;
19 21  
20 22 /**
21 23 * 字段类型
22 24 */
23   - private String type;
  25 + private String dataType;
24 26  
25 27 /**
26 28 * 字段长度
27 29 */
28   - private int length;
  30 + private Integer dataLength = 0;
29 31 }
30 32 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java
... ... @@ -17,13 +17,25 @@ public class TdResponse {
17 17 public static final int CODE_SUCCESS = 0;
18 18 public static final int CODE_TB_NOT_EXIST = 866;
19 19  
  20 + /**
  21 + * 状态
  22 + */
20 23 private String status;
21 24  
  25 + /**
  26 + * 错误码
  27 + */
22 28 private int code;
23 29  
  30 + /**
  31 + * 错误信息
  32 + */
24 33 private String desc;
25 34  
26   - //[["time","TIMESTAMP",8,""],["powerstate","TINYINT",1,""],["brightness","INT",4,""],["deviceid","NCHAR",32,"TAG"]]
27   - private List<Object[]> data;
  35 + /**
  36 + * 列信息
  37 + * [["time","TIMESTAMP",8,""],["powerstate","TINYINT",1,""],["brightness","INT",4,""],["deviceid","NCHAR",32,"TAG"]]
  38 + */
  39 + private List data;
28 40  
29 41 -}
  42 +}
30 43 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java
... ... @@ -14,23 +14,23 @@ import org.springframework.stereotype.Service;
14 14 @Service
15 15 public class TdRestApi {
16 16  
17   - @Value("${spring.datasource.dynamic.datasource.master.url}")
  17 + @Value("${spring.datasource.dynamic.datasource.tdengine.url}")
18 18 private String url;
19 19  
20   - @Value("${spring.datasource.dynamic.datasource.master.username}")
  20 + @Value("${spring.datasource.dynamic.datasource.tdengine.username}")
21 21 private String username;
22 22  
23   - @Value("${spring.datasource.dynamic.datasource.master.password}")
  23 + @Value("${spring.datasource.dynamic.datasource.tdengine.password}")
24 24 private String password;
25 25  
  26 + /**
  27 + * 获取 REST API URL
  28 + */
26 29 private String getRestApiUrl() {
27   - //jdbc:TAOS-RS://127.0.0.1:6041/iotkit?xxxx
28   - String restUrl = url.replace("jdbc:TAOS-RS://" , "")
29   - .replaceAll("\\?.*" , "");
30   - // /rest/sql/iotkit
  30 + String restUrl = url.replace("jdbc:TAOS-RS://", "")
  31 + .replaceAll("\\?.*", "");
31 32 int idx = restUrl.lastIndexOf("/");
32   - //127.0.0.1:6041/rest/sql/iotkit
33   - return String.format("%s/rest/sql/%s" , restUrl.substring(0, idx), restUrl.substring(idx + 1));
  33 + return String.format("%s/rest/sql/%s", restUrl.substring(0, idx), restUrl.substring(idx + 1));
34 34 }
35 35  
36 36  
... ... @@ -48,11 +48,10 @@ public class TdRestApi {
48 48 * 执行sql
49 49 */
50 50 public TdResponse execSql(String sql) {
51   - log.info("exec td sql:{}" , sql);
  51 + log.info("exec td sql:{}", sql);
52 52 HttpRequest request = newApiRequest(sql);
53 53 HttpResponse response = request.execute();
54 54 return JSONUtil.toBean(response.body(), TdResponse.class);
55 55 }
56 56  
57   -
58   -}
  57 +}
59 58 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java
1 1 package cn.iocoder.yudao.module.iot.dal.tdengine;
2 2  
  3 +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO;
3 4 import cn.iocoder.yudao.module.iot.domain.FieldsVo;
4 5 import cn.iocoder.yudao.module.iot.domain.SelectDto;
5 6 import cn.iocoder.yudao.module.iot.domain.TableDto;
... ... @@ -17,24 +18,80 @@ import java.util.Map;
17 18 @DS("tdengine")
18 19 public interface TdEngineMapper {
19 20  
  21 + /**
  22 + * 创建数据库
  23 + *
  24 + * @param dataBaseName 数据库名称
  25 + */
  26 + @InterceptorIgnore(tenantLine = "true")
20 27 void createDatabase(@Param("dataBaseName") String dataBaseName);
21 28  
22   - void createSuperTable(@Param("schemaFields") List<FieldsVo> schemaFields,
23   - @Param("tagsFields") List<FieldsVo> tagsFields,
  29 + /**
  30 + * 创建超级表
  31 + *
  32 + * @param schemaFields schema字段
  33 + * @param tagsFields tags字段
  34 + * @param dataBaseName 数据库名称
  35 + * @param superTableName 超级表名称
  36 + */
  37 + @InterceptorIgnore(tenantLine = "true")
  38 + void createSuperTable(@Param("schemaFields") List<TdFieldDO> schemaFields,
  39 + @Param("tagsFields") List<TdFieldDO> tagsFields,
24 40 @Param("dataBaseName") String dataBaseName,
25 41 @Param("superTableName") String superTableName);
26 42  
  43 + /**
  44 + * 查看超级表 - 显示当前数据库下的所有超级表信息
  45 + * SQL:SHOW STABLES [LIKE tb_name_wildcard];
  46 + *
  47 + * @param dataBaseName 数据库名称
  48 + * @param superTableName 超级表名称
  49 + */
  50 + @InterceptorIgnore(tenantLine = "true")
  51 + List<Map<String, Object>> showSuperTables(@Param("dataBaseName") String dataBaseName,
  52 + @Param("superTableName") String superTableName);
  53 +
  54 + /**
  55 + * 查看超级表 - 获取超级表的结构信息
  56 + * SQL:DESCRIBE [db_name.]stb_name;
  57 + * <p>
  58 + * * @param dataBaseName 数据库名称
  59 + * * @param superTableName 超级表名称
  60 + */
  61 + @InterceptorIgnore(tenantLine = "true")
  62 + List<Map<String, Object>> describeSuperTable(@Param("dataBaseName") String dataBaseName,
  63 + @Param("superTableName") String superTableName);
  64 +
  65 + /**
  66 + * 为超级表添加列
  67 + *
  68 + * @param dataBaseName 数据库名称
  69 + * @param superTableName 超级表名称
  70 + * @param field 字段信息
  71 + */
  72 + @InterceptorIgnore(tenantLine = "true")
  73 + void addColumnForSuperTable(@Param("dataBaseName") String dataBaseName,
  74 + @Param("superTableName") String superTableName,
  75 + @Param("field") TdFieldDO field);
  76 +
  77 + /**
  78 + * 为超级表删除列
  79 + *
  80 + * @param dataBaseName 数据库名称
  81 + * @param superTableName 超级表名称
  82 + * @param field 字段信息
  83 + */
  84 + @InterceptorIgnore(tenantLine = "true")
  85 + void dropColumnForSuperTable(@Param("dataBaseName") String dataBaseName,
  86 + @Param("superTableName") String superTableName,
  87 + @Param("field") TdFieldDO field);
  88 +
27 89 void createTable(TableDto tableDto);
28 90  
29 91 void insertData(TableDto tableDto);
30 92  
31 93 List<Map<String, Object>> selectByTimestamp(SelectDto selectDto);
32 94  
33   - void addColumnForSuperTable(@Param("superTableName") String superTableName,
34   - @Param("fieldsVo") FieldsVo fieldsVo);
35   -
36   - void dropColumnForSuperTable(@Param("superTableName") String superTableName,
37   - @Param("fieldsVo") FieldsVo fieldsVo);
38 95  
39 96 void addTagForSuperTable(@Param("superTableName") String superTableName,
40 97 @Param("fieldsVo") FieldsVo fieldsVo);
... ... @@ -44,14 +101,6 @@ public interface TdEngineMapper {
44 101  
45 102 Map<String, Long> getCountByTimestamp(SelectDto selectDto);
46 103  
47   - /**
48   - * 检查表是否存在
49   - *
50   - * @param dataBaseName 数据库名称
51   - * @param tableName 表名称
52   - */
53   - Integer checkTableExists(@Param("dataBaseName") String dataBaseName, @Param("tableName") String tableName);
54   -
55 104 Map<String, Object> getLastData(SelectDto selectDto);
56 105  
57 106 List<Map<String, Object>> getHistoryData(SelectVisualDto selectVisualDto);
... ... @@ -62,13 +111,5 @@ public interface TdEngineMapper {
62 111  
63 112 List<Map<String, Object>> getLastDataByTags(TagsSelectDao tagsSelectDao);
64 113  
65   - /**
66   - * 创建超级表
67   - *
68   - * @param sql sql
69   - * @return 返回值
70   - */
71   - @InterceptorIgnore(tenantLine = "true")
72   - Integer createSuperTableDevice(String sql);
73 114  
74 115 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java
1 1 package cn.iocoder.yudao.module.iot.service.tdengine;
2 2  
3   -import cn.hutool.json.JSONUtil;
  3 +import cn.hutool.core.collection.CollUtil;
4 4 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
5 5 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO;
6 6 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
7   -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*;
  7 +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser;
  8 +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO;
  9 +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdRestApi;
8 10 import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
9   -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper;
10 11 import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum;
11 12 import jakarta.annotation.Resource;
12 13 import lombok.extern.slf4j.Slf4j;
  14 +import org.springframework.beans.factory.annotation.Value;
13 15 import org.springframework.stereotype.Service;
14 16  
15 17 import java.util.ArrayList;
16 18 import java.util.List;
  19 +import java.util.Map;
17 20 import java.util.Objects;
18 21 import java.util.stream.Collectors;
19 22  
... ... @@ -22,147 +25,206 @@ import java.util.stream.Collectors;
22 25 public class IotDbStructureDataServiceImpl implements IotDbStructureDataService {
23 26  
24 27 @Resource
25   - private TdEngineMapper tdEngineMapper;
  28 + private TdEngineService tdEngineService;
26 29  
27 30 @Resource
28 31 private TdRestApi tdRestApi;
29 32  
  33 + @Value("${spring.datasource.dynamic.datasource.tdengine.url}")
  34 + private String url;
  35 +
30 36 @Override
31 37 public void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) {
32   - // 获取物模型中的属性定义
33   - List<TdField> fields = FieldParser.parse(thingModel);
34   - String tbName = getProductPropertySTableName(deviceType, thingModel.getProductKey());
35   -
36   - // 生成创建超级表的 SQL
37   - String sql = TableManager.getCreateSTableSql(tbName, fields, new TdField("device_id", "NCHAR", 64));
38   - if (sql == null) {
39   - log.warn("生成的 SQL 为空,无法创建超级表");
40   - return;
41   - }
42   - log.info("执行 SQL: {}", sql);
43   -
44   - // 执行 SQL 创建超级表
45   - tdEngineMapper.createSuperTableDevice(sql);
  38 + // 1. 解析物模型,获得字段列表
  39 + List<TdFieldDO> schemaFields = new ArrayList<>();
  40 + schemaFields.add(TdFieldDO.builder().
  41 + fieldName("time").
  42 + dataType("TIMESTAMP").
  43 + build());
  44 + schemaFields.addAll(FieldParser.parse(thingModel));
  45 +
  46 + // 3. 设置超级表的标签
  47 + List<TdFieldDO> tagsFields = new ArrayList<>();
  48 + tagsFields.add(TdFieldDO.builder().
  49 + fieldName("product_key").
  50 + dataType("NCHAR").
  51 + dataLength(64).
  52 + build());
  53 + tagsFields.add(TdFieldDO.builder().
  54 + fieldName("device_key").
  55 + dataType("NCHAR").
  56 + dataLength(64).
  57 + build());
  58 + tagsFields.add(TdFieldDO.builder().
  59 + fieldName("device_name").
  60 + dataType("NCHAR").
  61 + dataLength(64).
  62 + build());
  63 + // 年
  64 + tagsFields.add(TdFieldDO.builder().
  65 + fieldName("year").
  66 + dataType("INT").
  67 + build());
  68 + // 月
  69 + tagsFields.add(TdFieldDO.builder().
  70 + fieldName("month").
  71 + dataType("INT").
  72 + build());
  73 + // 日
  74 + tagsFields.add(TdFieldDO.builder().
  75 + fieldName("day").
  76 + dataType("INT").
  77 + build());
  78 + // 时
  79 + tagsFields.add(TdFieldDO.builder().
  80 + fieldName("hour").
  81 + dataType("INT").
  82 + build());
  83 +
  84 +
  85 + // 4. 获取超级表的名称
  86 + String superTableName = getProductPropertySTableName(deviceType, thingModel.getProductKey());
  87 +
  88 + // 5. 创建超级表
  89 + String dataBaseName = url.substring(url.lastIndexOf("/") + 1);
  90 + tdEngineService.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName);
46 91 }
47 92  
48 93 @Override
49 94 public void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType) {
50 95 try {
51   - // 获取旧字段信息
52 96 String tbName = getProductPropertySTableName(deviceType, thingModel.getProductKey());
53   - String sql = TableManager.getDescTableSql(tbName);
54   - TdResponse response = tdRestApi.execSql(sql);
55   - if (response.getCode() != TdResponse.CODE_SUCCESS) {
56   - throw new RuntimeException("获取表描述错误: " + JSONUtil.toJsonStr(response));
57   - }
58   -
59   - List<TdField> oldFields = FieldParser.parse(response.getData());
60   - List<TdField> newFields = FieldParser.parse(thingModel);
61   -
62   - // 找出新增的字段
63   - List<TdField> addFields = newFields.stream()
64   - .filter(f -> oldFields.stream().noneMatch(old -> old.getName().equals(f.getName())))
65   - .collect(Collectors.toList());
66   - if (!addFields.isEmpty()) {
67   - sql = TableManager.getAddSTableColumnSql(tbName, addFields);
68   - response = tdRestApi.execSql(sql);
69   - if (response.getCode() != TdResponse.CODE_SUCCESS) {
70   - throw new RuntimeException("添加表字段错误: " + JSONUtil.toJsonStr(response));
71   - }
72   - }
73   -
74   - // 找出修改的字段
75   - List<TdField> modifyFields = newFields.stream()
76   - .filter(f -> oldFields.stream().anyMatch(old ->
77   - old.getName().equals(f.getName()) &&
78   - (!old.getType().equals(f.getType()) || old.getLength() != f.getLength())))
79   - .collect(Collectors.toList());
80   - if (!modifyFields.isEmpty()) {
81   - sql = TableManager.getModifySTableColumnSql(tbName, modifyFields);
82   - response = tdRestApi.execSql(sql);
83   - if (response.getCode() != TdResponse.CODE_SUCCESS) {
84   - throw new RuntimeException("修改表字段错误: " + JSONUtil.toJsonStr(response));
85   - }
86   - }
87   -
88   - // 找出删除的字段
89   - List<TdField> dropFields = oldFields.stream()
90   - .filter(f -> !"time".equals(f.getName()) && !"device_id".equals(f.getName()) &&
91   - newFields.stream().noneMatch(n -> n.getName().equals(f.getName())))
92   - .collect(Collectors.toList());
93   - if (!dropFields.isEmpty()) {
94   - sql = TableManager.getDropSTableColumnSql(tbName, dropFields);
95   - response = tdRestApi.execSql(sql);
96   - if (response.getCode() != TdResponse.CODE_SUCCESS) {
97   - throw new RuntimeException("删除表字段错误: " + JSONUtil.toJsonStr(response));
98   - }
99   - }
  97 + List<TdFieldDO> oldFields = getTableFields(tbName);
  98 + List<TdFieldDO> newFields = FieldParser.parse(thingModel);
  99 +
  100 + updateTableFields(tbName, oldFields, newFields);
100 101 } catch (Throwable e) {
101 102 log.error("更新物模型超级表失败", e);
102 103 }
103 104 }
104 105  
105   - @Override
106   - public void createSuperTableDataModel(IotProductDO product, List<IotThinkModelFunctionDO> functionList) {
107   - // 1. 生成 ThingModelRespVO
108   - ThingModelRespVO thingModel = new ThingModelRespVO();
109   - thingModel.setId(product.getId());
110   - thingModel.setProductKey(product.getProductKey());
  106 + // 获取表字段
  107 + private List<TdFieldDO> getTableFields(String tableName) {
  108 + List<TdFieldDO> fields = new ArrayList<>();
  109 + // 获取超级表的描述信息
  110 + List<Map<String, Object>> maps = tdEngineService.describeSuperTable(url.substring(url.lastIndexOf("/") + 1), tableName);
  111 + if (maps != null) {
  112 + // 过滤掉 note 字段为 TAG 的记录
  113 + maps = maps.stream().filter(map -> !"TAG".equals(map.get("note"))).toList();
  114 + // 过滤掉 time 字段
  115 + maps = maps.stream().filter(map -> !"time".equals(map.get("field"))).toList();
  116 + // 解析字段信息
  117 + fields = FieldParser.parse(maps.stream()
  118 + .map(map -> List.of(map.get("field"), map.get("type"), map.get("length")))
  119 + .collect(Collectors.toList()));
  120 + }
  121 + return fields;
  122 + }
111 123  
112   - // 1.1 设置属性、服务和事件
113   - ThingModelRespVO.Model model = new ThingModelRespVO.Model();
114   - List<ThingModelProperty> properties = new ArrayList<>();
115   -
116   - // 1.2 遍历功能列表并分类
117   - for (IotThinkModelFunctionDO function : functionList) {
118   - if (Objects.requireNonNull(IotProductFunctionTypeEnum.valueOf(function.getType())) == IotProductFunctionTypeEnum.PROPERTY) {
119   - ThingModelProperty property = new ThingModelProperty();
120   - property.setIdentifier(function.getIdentifier());
121   - property.setName(function.getName());
122   - property.setDescription(function.getDescription());
123   - property.setDataType(function.getProperty().getDataType());
124   - properties.add(property);
125   - }
  124 + // 更新表字段
  125 + private void updateTableFields(String tableName, List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
  126 + // 获取新增字段
  127 + List<TdFieldDO> addFields = getAddFields(oldFields, newFields);
  128 + // 获取修改字段
  129 + List<TdFieldDO> modifyFields = getModifyFields(oldFields, newFields);
  130 + // 获取删除字段
  131 + List<TdFieldDO> dropFields = getDropFields(oldFields, newFields);
  132 +
  133 + String dataBaseName = url.substring(url.lastIndexOf("/") + 1);
  134 + // 添加新增字段
  135 + if (CollUtil.isNotEmpty(addFields)) {
  136 + tdEngineService.addColumnForSuperTable(dataBaseName,tableName, addFields);
  137 + }
  138 + // 删除旧字段
  139 + if (CollUtil.isNotEmpty(dropFields)) {
  140 + tdEngineService.dropColumnForSuperTable(dataBaseName,tableName, dropFields);
126 141 }
  142 + // 修改字段(先删除再添加)
  143 + if (CollUtil.isNotEmpty(modifyFields)) {
  144 + tdEngineService.dropColumnForSuperTable(dataBaseName,tableName, modifyFields);
  145 + tdEngineService.addColumnForSuperTable(dataBaseName,tableName, modifyFields);
  146 + }
  147 + }
  148 +
  149 + // 获取新增字段
  150 + private List<TdFieldDO> getAddFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
  151 + return newFields.stream()
  152 + .filter(f -> oldFields.stream().noneMatch(old -> old.getFieldName().equals(f.getFieldName())))
  153 + .collect(Collectors.toList());
  154 + }
  155 +
  156 + // 获取修改字段
  157 + private List<TdFieldDO> getModifyFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
  158 + return newFields.stream()
  159 + .filter(f -> oldFields.stream().anyMatch(old ->
  160 + old.getFieldName().equals(f.getFieldName()) &&
  161 + (!old.getDataType().equals(f.getDataType()) || !Objects.equals(old.getDataLength(), f.getDataLength()))))
  162 + .collect(Collectors.toList());
  163 + }
  164 +
  165 + // 获取删除字段
  166 + private List<TdFieldDO> getDropFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
  167 + return oldFields.stream()
  168 + .filter(f -> !"time".equals(f.getFieldName()) && !"device_id".equals(f.getFieldName()) &&
  169 + newFields.stream().noneMatch(n -> n.getFieldName().equals(f.getFieldName())))
  170 + .collect(Collectors.toList());
  171 + }
  172 +
  173 + @Override
  174 + public void createSuperTableDataModel(IotProductDO product, List<IotThinkModelFunctionDO> functionList) {
  175 + ThingModelRespVO thingModel = buildThingModel(product, functionList);
127 176  
128   - // 1.3 判断属性列表是否为空
129   - if (properties.isEmpty()) {
  177 + if (thingModel.getModel().getProperties().isEmpty()) {
130 178 log.warn("物模型属性列表为空,不创建超级表");
131 179 return;
132 180 }
133 181  
134   - model.setProperties(properties);
135   - thingModel.setModel(model);
  182 + String superTableName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey());
  183 + String dataBaseName = url.substring(url.lastIndexOf("/") + 1);
  184 + Integer tableExists = tdEngineService.checkSuperTableExists(dataBaseName, superTableName);
136 185  
137   - // 2. 判断是否已经创建,如果已经创建则进行更新
138   - String tbName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey());
139   - Integer iot = tdEngineMapper.checkTableExists("ruoyi_vue_pro", tbName);
140   - if (iot != null && iot > 0) {
141   - // 3. 更新
  186 + if (tableExists != null && tableExists > 0) {
142 187 updateSuperTable(thingModel, product.getDeviceType());
143 188 } else {
144   - // 4. 创建
145 189 createSuperTable(thingModel, product.getDeviceType());
146 190 }
147 191 }
148 192  
149   - /**
150   - * 根据产品key获取产品属性超级表名
151   - */
  193 + private ThingModelRespVO buildThingModel(IotProductDO product, List<IotThinkModelFunctionDO> functionList) {
  194 + ThingModelRespVO thingModel = new ThingModelRespVO();
  195 + thingModel.setId(product.getId());
  196 + thingModel.setProductKey(product.getProductKey());
  197 +
  198 + ThingModelRespVO.Model model = new ThingModelRespVO.Model();
  199 + List<ThingModelProperty> properties = functionList.stream()
  200 + .filter(function -> IotProductFunctionTypeEnum.PROPERTY.equals(IotProductFunctionTypeEnum.valueOf(function.getType())))
  201 + .map(this::buildThingModelProperty)
  202 + .collect(Collectors.toList());
  203 +
  204 + model.setProperties(properties);
  205 + thingModel.setModel(model);
  206 +
  207 + return thingModel;
  208 + }
  209 +
  210 + private ThingModelProperty buildThingModelProperty(IotThinkModelFunctionDO function) {
  211 + ThingModelProperty property = new ThingModelProperty();
  212 + property.setIdentifier(function.getIdentifier());
  213 + property.setName(function.getName());
  214 + property.setDescription(function.getDescription());
  215 + property.setDataType(function.getProperty().getDataType());
  216 + return property;
  217 + }
  218 +
152 219 static String getProductPropertySTableName(Integer deviceType, String productKey) {
153   - if (deviceType == 1) {
154   - return String.format("gateway_sub_" + productKey).toLowerCase();
155   - } else if (deviceType == 2) {
156   - return String.format("gateway_" + productKey).toLowerCase();
157   - } else {
158   - return String.format("device_" + productKey).toLowerCase();
159   - }
  220 + return switch (deviceType) {
  221 + case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase();
  222 + case 2 -> String.format("gateway_%s", productKey).toLowerCase();
  223 + default -> String.format("device_%s", productKey).toLowerCase();
  224 + };
160 225 }
161 226  
162   - /**
163   - * 根据deviceId获取设备属性表名
164   - */
165 227 static String getDevicePropertyTableName(String deviceType, String productKey, String deviceKey) {
166   - return String.format(deviceType + "_" + productKey + "_" + deviceKey).toLowerCase();
  228 + return String.format("%s_%s_%s", deviceType, productKey, deviceKey).toLowerCase();
167 229 }
168 230 -}
  231 +}
169 232 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineService.java
1 1 package cn.iocoder.yudao.module.iot.service.tdengine;
2 2  
3   -import cn.iocoder.yudao.module.iot.domain.FieldsVo;
  3 +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO;
4 4 import cn.iocoder.yudao.module.iot.domain.SelectDto;
5 5 import cn.iocoder.yudao.module.iot.domain.TableDto;
6 6 import cn.iocoder.yudao.module.iot.domain.TagsSelectDao;
... ... @@ -27,68 +27,69 @@ public interface TdEngineService {
27 27 *
28 28 * @param schemaFields schema字段
29 29 * @param tagsFields tags字段
30   - * @param dataBaseName 数据库名称
31 30 * @param superTableName 超级表名称
32   - * @throws Exception 异常
33 31 */
34   - void createSuperTable(List<FieldsVo> schemaFields, List<FieldsVo> tagsFields, String dataBaseName,
35   - String superTableName) throws Exception;
  32 + void createSuperTable(List<TdFieldDO> schemaFields, List<TdFieldDO> tagsFields, String dataBaseName, String superTableName);
36 33  
37 34 /**
38   - * 创建表
39   - *
40   - * @param tableDto 表信息
41   - * @throws Exception 异常
  35 + * 检查超级表是否存在
42 36 */
43   - void createTable(TableDto tableDto) throws Exception;
  37 + Integer checkSuperTableExists(String dataBaseName, String superTableName);
44 38  
45   - /**
46   - * 插入数据
47   - *
48   - * @param tableDto 表信息
49   - * @throws Exception 异常
50   - */
51   - void insertData(TableDto tableDto) throws Exception;
52 39  
53 40 /**
54   - * 根据时间戳查询数据
55   - *
56   - * @param selectDto 查询条件
57   - * @return 数据
58   - * @throws Exception 异常
  41 + * 获取超级表的结构信息
59 42 */
60   - List<Map<String, Object>> selectByTimesTamp(SelectDto selectDto) throws Exception;
  43 + List<Map<String, Object>> describeSuperTable(String dataBaseName, String superTableName);
61 44  
62 45 /**
63 46 * 为超级表添加列
64 47 *
  48 + * @param dataBaseName 数据库名称
65 49 * @param superTableName 超级表名称
66 50 * @param fieldsVo 字段信息
67   - * @throws Exception 异常
68 51 */
69   - void addColumnForSuperTable(String superTableName, FieldsVo fieldsVo) throws Exception;
  52 + void addColumnForSuperTable(String dataBaseName,String superTableName, List<TdFieldDO> fieldsVo);
70 53  
71 54 /**
72 55 * 为超级表删除列
73 56 *
  57 + * @param dataBaseName 数据库名称
74 58 * @param superTableName 超级表名称
75 59 * @param fieldsVo 字段信息
76   - * @throws Exception 异常
77 60 */
78   - void dropColumnForSuperTable(String superTableName, FieldsVo fieldsVo) throws Exception;
  61 + void dropColumnForSuperTable(String dataBaseName,String superTableName, List<TdFieldDO> fieldsVo);
79 62  
80 63 /**
81 64 * 为超级表添加tag
82 65 */
83 66 Long getCountByTimesTamp(SelectDto selectDto) throws Exception;
84 67  
  68 +
  69 + /**
  70 + * 创建表
  71 + *
  72 + * @param tableDto 表信息
  73 + * @throws Exception 异常
  74 + */
  75 + void createTable(TableDto tableDto) throws Exception;
  76 +
85 77 /**
86   - * 检查表是否存在
  78 + * 插入数据
87 79 *
88   - * @return 1存在 0不存在
  80 + * @param tableDto 表信息
89 81 * @throws Exception 异常
90 82 */
91   - Integer checkTableExists(SelectDto selectDto) throws Exception;
  83 + void insertData(TableDto tableDto) throws Exception;
  84 +
  85 + /**
  86 + * 根据时间戳查询数据
  87 + *
  88 + * @param selectDto 查询条件
  89 + * @return 数据
  90 + * @throws Exception 异常
  91 + */
  92 + List<Map<String, Object>> selectByTimesTamp(SelectDto selectDto) throws Exception;
92 93  
93 94 /**
94 95 * 初始化超级表
... ... @@ -138,4 +139,6 @@ public interface TdEngineService {
138 139 * @return 数据
139 140 */
140 141 List<Map<String, Object>> getAggregateData(SelectVisualDto selectVisualDto);
  142 +
  143 +
141 144 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineServiceImpl.java
1 1 package cn.iocoder.yudao.module.iot.service.tdengine;
2 2  
3   -import cn.iocoder.yudao.module.iot.domain.FieldsVo;
  3 +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO;
  4 +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper;
4 5 import cn.iocoder.yudao.module.iot.domain.SelectDto;
5 6 import cn.iocoder.yudao.module.iot.domain.TableDto;
6 7 import cn.iocoder.yudao.module.iot.domain.TagsSelectDao;
7 8 import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto;
  9 +import jakarta.annotation.Resource;
8 10 import lombok.extern.slf4j.Slf4j;
9 11 import org.springframework.stereotype.Service;
10 12  
... ... @@ -15,25 +17,27 @@ import java.util.Map;
15 17 @Slf4j
16 18 public class TdEngineServiceImpl implements TdEngineService {
17 19  
  20 + @Resource
  21 + private TdEngineMapper tdEngineMapper;
18 22  
19 23 @Override
20 24 public void createDateBase(String dataBaseName) {
21   -
  25 + tdEngineMapper.createDatabase(dataBaseName);
22 26 }
23 27  
24 28 @Override
25   - public void createSuperTable(List<FieldsVo> schemaFields, List<FieldsVo> tagsFields, String dataBaseName, String superTableName) {
26   -
  29 + public void createSuperTable(List<TdFieldDO> schemaFields, List<TdFieldDO> tagsFields, String dataBaseName, String superTableName) {
  30 + tdEngineMapper.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName);
27 31 }
28 32  
29 33 @Override
30 34 public void createTable(TableDto tableDto) {
31   -
  35 + tdEngineMapper.createTable(tableDto);
32 36 }
33 37  
34 38 @Override
35 39 public void insertData(TableDto tableDto) {
36   -
  40 + tdEngineMapper.insertData(tableDto);
37 41 }
38 42  
39 43 @Override
... ... @@ -42,13 +46,17 @@ public class TdEngineServiceImpl implements TdEngineService {
42 46 }
43 47  
44 48 @Override
45   - public void addColumnForSuperTable(String superTableName, FieldsVo fieldsVo) {
46   -
  49 + public void addColumnForSuperTable(String dataBaseName,String superTableName, List<TdFieldDO> fields) {
  50 + for (TdFieldDO field : fields) {
  51 + tdEngineMapper.addColumnForSuperTable(dataBaseName,superTableName, field);
  52 + }
47 53 }
48 54  
49 55 @Override
50   - public void dropColumnForSuperTable(String superTableName, FieldsVo fieldsVo) {
51   -
  56 + public void dropColumnForSuperTable(String dataBaseName,String superTableName, List<TdFieldDO> fields) {
  57 + for (TdFieldDO field : fields) {
  58 + tdEngineMapper.dropColumnForSuperTable(dataBaseName,superTableName, field);
  59 + }
52 60 }
53 61  
54 62 @Override
... ... @@ -57,11 +65,6 @@ public class TdEngineServiceImpl implements TdEngineService {
57 65 }
58 66  
59 67 @Override
60   - public Integer checkTableExists(SelectDto selectDto) {
61   - return 0;
62   - }
63   -
64   - @Override
65 68 public void initSTableFrame(String msg) {
66 69  
67 70 }
... ... @@ -90,4 +93,15 @@ public class TdEngineServiceImpl implements TdEngineService {
90 93 public List<Map<String, Object>> getAggregateData(SelectVisualDto selectVisualDto) {
91 94 return List.of();
92 95 }
  96 +
  97 + @Override
  98 + public Integer checkSuperTableExists(String dataBaseName, String superTableName) {
  99 + List<Map<String, Object>> results = tdEngineMapper.showSuperTables(dataBaseName, superTableName);
  100 + return results == null || results.isEmpty() ? 0 : results.size();
  101 + }
  102 +
  103 + @Override
  104 + public List<Map<String, Object>> describeSuperTable(String dataBaseName, String superTableName) {
  105 + return tdEngineMapper.describeSuperTable(dataBaseName, superTableName);
  106 + }
93 107 }
94 108 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
... ... @@ -174,8 +174,10 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
174 174 public void createSuperTableDataModel(Long productId) {
175 175 // 1. 查询产品
176 176 IotProductDO product = productService.getProduct(productId);
  177 +
177 178 // 2. 查询产品的物模型功能列表
178 179 List<IotThinkModelFunctionDO> functionList = thinkModelFunctionMapper.selectListByProductId(productId);
  180 +
179 181 // 3. 生成 TDengine 的数据模型
180 182 dbStructureDataService.createSuperTableDataModel(product, functionList);
181 183 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml
... ... @@ -8,7 +8,7 @@
8 8 </update>
9 9  
10 10 <update id="createSuperTable">
11   - create table if not exists #{dataBaseName}.#{superTableName}
  11 + CREATE STABLE IF NOT EXISTS ${dataBaseName}.${superTableName}
12 12 <foreach item="item" collection="schemaFields" separator=","
13 13 open="(" close=")" index="">
14 14 <if test="item.fieldName != null || item.fieldName != ''">
... ... @@ -16,46 +16,48 @@
16 16 </if>
17 17 <if test="item.dataType != null || item.dataType != ''">
18 18 <choose>
19   - <when test="item.dataType == 'timestamp'">
20   - timestamp
  19 + <when test="item.dataType == 'TIMESTAMP'">
  20 + TIMESTAMP
21 21 </when>
22   - <when test="item.dataType == 'tinyint'">
23   - tinyint
  22 + <when test="item.dataType == 'TINYINT'">
  23 + TINYINT
24 24 </when>
25   - <when test="item.dataType == 'smallint'">
26   - smallint
  25 + <when test="item.dataType == 'SMALLINT'">
  26 + SMALLINT
27 27 </when>
28   - <when test="item.dataType == 'int'">
29   - int
  28 + <when test="item.dataType == 'INT'">
  29 + INT
30 30 </when>
31   - <when test="item.dataType == 'bigint'">
32   - bigint
  31 + <when test="item.dataType == 'BIGINT'">
  32 + BIGINT
33 33 </when>
34   - <when test="item.dataType == 'float'">
35   - float
  34 + <when test="item.dataType == 'FLOAT'">
  35 + FLOAT
36 36 </when>
37   - <when test="item.dataType == 'double'">
38   - double
  37 + <when test="item.dataType == 'DOUBLE'">
  38 + DOUBLE
39 39 </when>
40   - <when test="item.dataType == 'binary'">
41   - binary
  40 + <when test="item.dataType == 'BINARY'">
  41 + BINARY
42 42 </when>
43   - <when test="item.dataType == 'nchar'">
44   - nchar
  43 + <when test="item.dataType == 'NCHAR'">
  44 + NCHAR
45 45 </when>
46   - <when test="item.dataType == 'bool'">
47   - bool
  46 + <when test="item.dataType == 'BOOL'">
  47 + BOOL
48 48 </when>
49   - <when test="item.dataType == 'json'">
50   - json
  49 + <when test="item.dataType == 'JSON'">
  50 + JSON
51 51 </when>
52 52 </choose>
53 53 </if>
54   - <if test="item.size != null">
55   - (#{item.size})
  54 + <if test="item.dataLength > 0">
  55 + (
  56 + ${item.dataLength}
  57 + )
56 58 </if>
57 59 </foreach>
58   - tags
  60 + TAGS
59 61 <!--tdEngine不支持动态tags里的数据类型,只能使用choose标签比对-->
60 62 <foreach item="item" collection="tagsFields" separator=","
61 63 open="(" close=")" index="">
... ... @@ -64,43 +66,45 @@
64 66 </if>
65 67 <if test="item.dataType != null || item.dataType != ''">
66 68 <choose>
67   - <when test="item.dataType == 'timestamp'">
68   - timestamp
  69 + <when test="item.dataType == 'TIMESTAMP'">
  70 + TIMESTAMP
69 71 </when>
70   - <when test="item.dataType == 'tinyint'">
71   - tinyint
  72 + <when test="item.dataType == 'TINYINT'">
  73 + TINYINT
72 74 </when>
73   - <when test="item.dataType == 'smallint'">
74   - smallint
  75 + <when test="item.dataType == 'SMALLINT'">
  76 + SMALLINT
75 77 </when>
76   - <when test="item.dataType == 'int'">
77   - int
  78 + <when test="item.dataType == 'INT'">
  79 + INT
78 80 </when>
79   - <when test="item.dataType == 'bigint'">
80   - bigint
  81 + <when test="item.dataType == 'BIGINT'">
  82 + BIGINT
81 83 </when>
82   - <when test="item.dataType == 'float'">
83   - float
  84 + <when test="item.dataType == 'FLOAT'">
  85 + FLOAT
84 86 </when>
85   - <when test="item.dataType == 'double'">
86   - double
  87 + <when test="item.dataType == 'DOUBLE'">
  88 + DOUBLE
87 89 </when>
88   - <when test="item.dataType == 'binary'">
89   - binary
  90 + <when test="item.dataType == 'BINARY'">
  91 + BINARY
90 92 </when>
91   - <when test="item.dataType == 'nchar'">
92   - nchar
  93 + <when test="item.dataType == 'NCHAR'">
  94 + NCHAR
93 95 </when>
94   - <when test="item.dataType == 'bool'">
95   - bool
  96 + <when test="item.dataType == 'BOOL'">
  97 + BOOL
96 98 </when>
97   - <when test="item.dataType == 'json'">
98   - json
  99 + <when test="item.dataType == 'JSON'">
  100 + JSON
99 101 </when>
100 102 </choose>
101 103 </if>
102   - <if test="item.size != null">
103   - (#{item.size})
  104 + <if test="item.dataLength > 0">
  105 + (
  106 + ${item.dataLength}
  107 + )
104 108 </if>
105 109 </foreach>
106 110 </update>
... ... @@ -135,7 +139,6 @@
135 139 </foreach>
136 140 </insert>
137 141  
138   -
139 142 <select id="selectByTimestamp" parameterType="cn.iocoder.yudao.module.iot.domain.SelectDto"
140 143 resultType="Map">
141 144 select * from #{dataBaseName}.#{tableName}
... ... @@ -146,66 +149,58 @@
146 149 </select>
147 150  
148 151 <update id="addColumnForSuperTable">
149   - ALTER
150   - STABLE
151   - #{superTableName}
152   - ADD
153   - COLUMN
154   - <if test="fieldsVo.fieldName != null || fieldsVo.fieldName != ''">
155   - #{fieldsVo.fieldName}
  152 + ALTER STABLE ${dataBaseName}.${superTableName} ADD COLUMN
  153 + <if test="field.fieldName != null || field.fieldName != ''">
  154 + #{field.fieldName}
156 155 </if>
157   - <if test="fieldsVo.dataType != null || fieldsVo.dataType != ''">
  156 + <if test="field.dataType != null || field.dataType != ''">
158 157 <choose>
159   - <when test="fieldsVo.dataType == 'timestamp'">
160   - timestamp
  158 + <when test="field.dataType == 'TIMESTAMP'">
  159 + TIMESTAMP
161 160 </when>
162   - <when test="fieldsVo.dataType == 'tinyint'">
163   - tinyint
  161 + <when test="field.dataType == 'TINYINT'">
  162 + TINYINT
164 163 </when>
165   - <when test="fieldsVo.dataType == 'smallint'">
166   - smallint
  164 + <when test="field.dataType == 'SMALLINT'">
  165 + SMALLINT
167 166 </when>
168   - <when test="fieldsVo.dataType == 'int'">
169   - int
  167 + <when test="field.dataType == 'INT'">
  168 + INT
170 169 </when>
171   - <when test="fieldsVo.dataType == 'bigint'">
172   - bigint
  170 + <when test="field.dataType == 'BIGINT'">
  171 + BIGINT
173 172 </when>
174   - <when test="fieldsVo.dataType == 'float'">
175   - float
  173 + <when test="field.dataType == 'FLOAT'">
  174 + FLOAT
176 175 </when>
177   - <when test="fieldsVo.dataType == 'double'">
178   - double
  176 + <when test="field.dataType == 'DOUBLE'">
  177 + DOUBLE
179 178 </when>
180   - <when test="fieldsVo.dataType == 'binary'">
181   - binary
  179 + <when test="field.dataType == 'BINARY'">
  180 + BINARY
182 181 </when>
183   - <when test="fieldsVo.dataType == 'nchar'">
184   - nchar
  182 + <when test="field.dataType == 'NCHAR'">
  183 + NCHAR
185 184 </when>
186   - <when test="fieldsVo.dataType == 'bool'">
187   - bool
  185 + <when test="field.dataType == 'BOOL'">
  186 + BOOL
188 187 </when>
189   - <when test="fieldsVo.dataType == 'json'">
190   - json
  188 + <when test="field.dataType == 'JSON'">
  189 + JSON
191 190 </when>
192 191 </choose>
193 192 </if>
194   - <if test="fieldsVo.size != null">
  193 + <if test="field.dataLength > 0">
195 194 (
196   - #{fieldsVo.size}
  195 + #{field.dataLength}
197 196 )
198 197 </if>
199 198 </update>
200 199  
201 200 <update id="dropColumnForSuperTable">
202   - ALTER
203   - STABLE
204   - #{superTableName}
205   - DROP
206   - COLUMN
207   - <if test="fieldsVo.fieldName != null || fieldsVo.fieldName != ''">
208   - #{fieldsVo.fieldName}
  201 + ALTER STABLE ${dataBaseName}.${superTableName} DROP COLUMN
  202 + <if test="field.fieldName != null || field.fieldName != ''">
  203 + #{field.fieldName}
209 204 </if>
210 205 </update>
211 206  
... ... @@ -215,49 +210,49 @@
215 210 #{superTableName}
216 211 ADD
217 212 TAG
218   - <if test="fieldsVo.fieldName != null || fieldsVo.fieldName != ''">
219   - #{fieldsVo.fieldName}
  213 + <if test="field.fieldName != null || fieldDO.fieldName != ''">
  214 + #{fieldDO.fieldName}
220 215 </if>
221   - <if test="fieldsVo.dataType != null || fieldsVo.dataType != ''">
  216 + <if test="fieldDO.dataType != null || fieldDO.dataType != ''">
222 217 <choose>
223   - <when test="fieldsVo.dataType == 'timestamp'">
  218 + <when test="fieldDO.dataType == 'timestamp'">
224 219 timestamp
225 220 </when>
226   - <when test="fieldsVo.dataType == 'tinyint'">
  221 + <when test="fieldDO.dataType == 'tinyint'">
227 222 tinyint
228 223 </when>
229   - <when test="fieldsVo.dataType == 'smallint'">
  224 + <when test="fieldDO.dataType == 'smallint'">
230 225 smallint
231 226 </when>
232   - <when test="fieldsVo.dataType == 'int'">
  227 + <when test="fieldDO.dataType == 'int'">
233 228 int
234 229 </when>
235   - <when test="fieldsVo.dataType == 'bigint'">
  230 + <when test="fieldDO.dataType == 'bigint'">
236 231 bigint
237 232 </when>
238   - <when test="fieldsVo.dataType == 'float'">
  233 + <when test="fieldDO.dataType == 'float'">
239 234 float
240 235 </when>
241   - <when test="fieldsVo.dataType == 'double'">
  236 + <when test="fieldDO.dataType == 'double'">
242 237 double
243 238 </when>
244   - <when test="fieldsVo.dataType == 'binary'">
  239 + <when test="fieldDO.dataType == 'binary'">
245 240 binary
246 241 </when>
247   - <when test="fieldsVo.dataType == 'nchar'">
  242 + <when test="fieldDO.dataType == 'nchar'">
248 243 nchar
249 244 </when>
250   - <when test="fieldsVo.dataType == 'bool'">
  245 + <when test="fieldDO.dataType == 'bool'">
251 246 bool
252 247 </when>
253   - <when test="fieldsVo.dataType == 'json'">
  248 + <when test="fieldDO.dataType == 'json'">
254 249 json
255 250 </when>
256 251 </choose>
257 252 </if>
258   - <if test="fieldsVo.size != null">
  253 + <if test="fieldDO.dataLength > 0">
259 254 (
260   - #{fieldsVo.size}
  255 + #{fieldDO.dataLength}
261 256 )
262 257 </if>
263 258 </update>
... ... @@ -279,11 +274,8 @@
279 274 FROM #{dataBaseName}.#{tableName} WHERE ${fieldName} BETWEEN #{startTime} AND #{endTime}
280 275 </select>
281 276  
282   - <select id="checkTableExists" resultType="java.lang.Integer">
283   - SELECT COUNT(0)
284   - FROM information_schema.ins_tables
285   - WHERE db_name = #{dataBaseName}
286   - AND table_name = #{tableName}
  277 + <select id="showSuperTables" resultType="java.util.Map">
  278 + SHOW ${dataBaseName}.STABLES LIKE '${superTableName}'
287 279 </select>
288 280  
289 281 <select id="getLastData" resultType="java.util.Map">
... ... @@ -304,11 +296,13 @@
304 296 FROM #{dataBaseName}.#{tableName} WHERE ts BETWEEN #{startTime} AND #{endTime}
305 297 LIMIT #{num}
306 298 </select>
  299 +
307 300 <select id="getRealtimeData" resultType="java.util.Map"
308 301 parameterType="cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto">
309 302 SELECT #{fieldName}, ts
310 303 FROM #{dataBaseName}.#{tableName} LIMIT #{num}
311 304 </select>
  305 +
312 306 <select id="getAggregateData" resultType="java.util.Map"
313 307 parameterType="cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto">
314 308 SELECT #{aggregate}(${fieldName})
... ... @@ -316,9 +310,8 @@
316 310 LIMIT #{num}
317 311 </select>
318 312  
319   -
320   - <insert id="createSuperTableDevice">
321   - ${sql}
322   - </insert>
  313 + <select id="describeSuperTable" resultType="java.util.Map">
  314 + DESCRIBE ${dataBaseName}.${superTableName}
  315 + </select>
323 316  
324 317 </mapper>
... ...