mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-11-01 03:28:41 +08:00 
			
		
		
		
	【功能优化】 产品发布创建超级表优化
This commit is contained in:
		| @ -1,14 +1,18 @@ | |||||||
| package cn.iocoder.yudao.module.iot.domain; | package cn.iocoder.yudao.module.iot.domain; | ||||||
|  |  | ||||||
|  | import lombok.Builder; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
|  |  | ||||||
| import java.sql.SQLException; | import java.sql.SQLException; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 字段信息 VO | ||||||
|  |  */ | ||||||
| @Data | @Data | ||||||
|  | @Builder | ||||||
| public class FieldsVo { | public class FieldsVo { | ||||||
|     private static final long serialVersionUID = 1L; |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 字段名称 |      * 字段名称 | ||||||
| @ -24,24 +28,4 @@ public class FieldsVo { | |||||||
|      * 字段字节大小 |      * 字段字节大小 | ||||||
|      */ |      */ | ||||||
|     private Integer size; |     private Integer size; | ||||||
|  |  | ||||||
|     public static FieldsVo fieldsTranscoding(Fields fields) throws SQLException { |  | ||||||
| //        if (StringUtils.isBlank(fields.getFieldName()) || fields.getDataType() == null) { |  | ||||||
| //            throw new SQLException("invalid operation: fieldName or dataType can not be null"); |  | ||||||
| //        } |  | ||||||
| //        FieldsVo fieldsVo = new FieldsVo(); |  | ||||||
| //        fieldsVo.setFieldName(fields.getFieldName()); |  | ||||||
| //        fieldsVo.setDataType(fields.getDataType().getDataType()); |  | ||||||
| //        fieldsVo.setSize(fields.getSize()); |  | ||||||
| //        return fieldsVo; |  | ||||||
|         return null; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static List<FieldsVo> fieldsTranscoding(List<Fields> fieldsList) throws SQLException { |  | ||||||
|         List<FieldsVo> fieldsVoList = new ArrayList<>(); |  | ||||||
|         for (Fields fields : fieldsList) { |  | ||||||
|             fieldsVoList.add(fieldsTranscoding(fields)); |  | ||||||
|         } |  | ||||||
|         return fieldsVoList; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,7 +10,6 @@ import java.util.stream.Collectors; | |||||||
|  |  | ||||||
| /** | /** | ||||||
|  * FieldParser 类用于解析和转换物模型字段到 TDengine 字段 |  * FieldParser 类用于解析和转换物模型字段到 TDengine 字段 | ||||||
|  *  |  | ||||||
|  */ |  */ | ||||||
| public class FieldParser { | public class FieldParser { | ||||||
|  |  | ||||||
| @ -35,49 +34,58 @@ public class FieldParser { | |||||||
|      * @param property 物模型属性 |      * @param property 物模型属性 | ||||||
|      * @return TdField对象 |      * @return TdField对象 | ||||||
|      */ |      */ | ||||||
|     public static TdField parse(ThingModelProperty property) { |     public static TdFieldDO parse(ThingModelProperty property) { | ||||||
|         String fieldName = property.getIdentifier().toLowerCase(); |         String fieldName = property.getIdentifier().toLowerCase(); | ||||||
|         ThingModelDataType type = property.getDataType(); |         ThingModelDataType type = property.getDataType(); | ||||||
|  |  | ||||||
|         // 将物模型字段类型映射为td字段类型 |         // 将物模型字段类型映射为td字段类型 | ||||||
|         String fType = TYPE_MAPPING.get(type.getType().toUpperCase()); |         String fType = TYPE_MAPPING.get(type.getType().toUpperCase()); | ||||||
|  |  | ||||||
|         int len = -1; |  | ||||||
|         // 如果字段类型为NCHAR,默认长度为64 |         // 如果字段类型为NCHAR,默认长度为64 | ||||||
|  |         int dataLength = 0; | ||||||
|         if ("NCHAR".equals(fType)) { |         if ("NCHAR".equals(fType)) { | ||||||
|             len = 64; |             dataLength = 64; | ||||||
|         } |         } | ||||||
|  |         return new TdFieldDO(fieldName, fType, dataLength); | ||||||
|         return new TdField(fieldName, fType, len); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 获取物模型中的字段列表 |      * 从物模型中获取字段列表 | ||||||
|  |      * | ||||||
|  |      * @param thingModel 物模型响应对象 | ||||||
|  |      * @return 字段列表 | ||||||
|      */ |      */ | ||||||
|     public static List<TdField> parse(ThingModelRespVO thingModel) { |     public static List<TdFieldDO> parse(ThingModelRespVO thingModel) { | ||||||
|         return thingModel.getModel().getProperties().stream().map(FieldParser::parse).collect(Collectors.toList()); |         return thingModel.getModel().getProperties().stream() | ||||||
|  |                 .map(FieldParser::parse) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 将从库中查出来的字段信息转换为td字段对象 |      * 将从库中查出来的字段信息转换为 TDengine 字段对象 | ||||||
|  |      * | ||||||
|  |      * @param rows 从库中查出的字段信息列表 | ||||||
|  |      * @return 转换后的 TDengine 字段对象列表 | ||||||
|      */ |      */ | ||||||
|     public static List<TdField> parse(List<List<Object>> rows) { |     public static List<TdFieldDO> parse(List<List<Object>> rows) { | ||||||
|         return rows.stream().map(row -> { |         return rows.stream().map(row -> { | ||||||
|             String type = row.get(1).toString().toUpperCase(); |             String type = row.get(1).toString().toUpperCase(); | ||||||
|             return new TdField( |             int dataLength = "NCHAR".equals(type) ? Integer.parseInt(row.get(2).toString()) : -1; | ||||||
|  |             return new TdFieldDO( | ||||||
|                     row.get(0).toString(), |                     row.get(0).toString(), | ||||||
|                     type, |                     type, | ||||||
|                     type.equals("NCHAR") ? Integer.parseInt(row.get(2).toString()) : -1); |                     dataLength | ||||||
|  |             ); | ||||||
|         }).collect(Collectors.toList()); |         }).collect(Collectors.toList()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 获取字段字义 |      * 获取字段字义 | ||||||
|      */ |      */ | ||||||
|     public static String getFieldDefine(TdField field) { |     public static String getFieldDefine(TdFieldDO field) { | ||||||
|         return "`" + field.getName() + "`" + " " |         return "`" + field.getFieldName() + "`" + " " | ||||||
|                 + (field.getLength() > 0 ? String.format("%s(%d)", field.getType(), field.getLength()) |                 + (field.getDataLength() > 0 ? String.format("%s(%d)", field.getDataType(), field.getDataLength()) | ||||||
|                         : field.getType()); |                 : field.getDataType()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @ -36,4 +36,4 @@ public class TableData { | |||||||
|      * 超级表名称 |      * 超级表名称 | ||||||
|      */ |      */ | ||||||
|     private String superTableName; |     private String superTableName; | ||||||
| } | } | ||||||
| @ -45,7 +45,7 @@ public class TableManager { | |||||||
|     /** |     /** | ||||||
|      * 获取创建表sql |      * 获取创建表sql | ||||||
|      */ |      */ | ||||||
|     public static String getCreateSTableSql(String tbName, List<TdField> fields, TdField... tags) { |     public static String getCreateSTableSql(String tbName, List<TdFieldDO> fields, TdFieldDO... tags) { | ||||||
|         if (fields.isEmpty()) { |         if (fields.isEmpty()) { | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
| @ -53,7 +53,7 @@ public class TableManager { | |||||||
|         // 生成字段片段 |         // 生成字段片段 | ||||||
|         StringBuilder sbField = new StringBuilder("time TIMESTAMP,"); |         StringBuilder sbField = new StringBuilder("time TIMESTAMP,"); | ||||||
|  |  | ||||||
|         for (TdField field : fields) { |         for (TdFieldDO field : fields) { | ||||||
|             sbField.append(FieldParser.getFieldDefine(field)); |             sbField.append(FieldParser.getFieldDefine(field)); | ||||||
|             sbField.append(","); |             sbField.append(","); | ||||||
|         } |         } | ||||||
| @ -63,7 +63,7 @@ public class TableManager { | |||||||
|  |  | ||||||
|         // 生成tag |         // 生成tag | ||||||
|         StringBuilder sbTag = new StringBuilder(); |         StringBuilder sbTag = new StringBuilder(); | ||||||
|         for (TdField tag : tags) { |         for (TdFieldDO tag : tags) { | ||||||
|             sbTag.append(FieldParser.getFieldDefine(tag)) |             sbTag.append(FieldParser.getFieldDefine(tag)) | ||||||
|                     .append(","); |                     .append(","); | ||||||
|         } |         } | ||||||
| @ -76,7 +76,7 @@ public class TableManager { | |||||||
|     /** |     /** | ||||||
|      * 获取创建普通表sql |      * 获取创建普通表sql | ||||||
|      */ |      */ | ||||||
|     public static String getCreateCTableSql(String tbName, List<TdField> fields) { |     public static String getCreateCTableSql(String tbName, List<TdFieldDO> fields) { | ||||||
|         if (fields.size() == 0) { |         if (fields.size() == 0) { | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
| @ -84,7 +84,7 @@ public class TableManager { | |||||||
|         //生成字段片段 |         //生成字段片段 | ||||||
|         StringBuilder sbField = new StringBuilder("time timestamp,"); |         StringBuilder sbField = new StringBuilder("time timestamp,"); | ||||||
|  |  | ||||||
|         for (TdField field : fields) { |         for (TdFieldDO field : fields) { | ||||||
|             sbField.append(FieldParser.getFieldDefine(field)); |             sbField.append(FieldParser.getFieldDefine(field)); | ||||||
|             sbField.append(","); |             sbField.append(","); | ||||||
|         } |         } | ||||||
| @ -116,9 +116,9 @@ public class TableManager { | |||||||
|     /** |     /** | ||||||
|      * 获取添加字段sql |      * 获取添加字段sql | ||||||
|      */ |      */ | ||||||
|     public static String getAddSTableColumnSql(String tbName, List<TdField> fields) { |     public static String getAddSTableColumnSql(String tbName, List<TdFieldDO> fields) { | ||||||
|         StringBuilder sbAdd = new StringBuilder(); |         StringBuilder sbAdd = new StringBuilder(); | ||||||
|         for (TdField field : fields) { |         for (TdFieldDO field : fields) { | ||||||
|             sbAdd.append(String.format(ALTER_STABLE_ADD_COL_TPL, |             sbAdd.append(String.format(ALTER_STABLE_ADD_COL_TPL, | ||||||
|                     tbName, |                     tbName, | ||||||
|                     FieldParser.getFieldDefine(field) |                     FieldParser.getFieldDefine(field) | ||||||
| @ -130,9 +130,9 @@ public class TableManager { | |||||||
|     /** |     /** | ||||||
|      * 获取修改字段sql |      * 获取修改字段sql | ||||||
|      */ |      */ | ||||||
|     public static String getModifySTableColumnSql(String tbName, List<TdField> fields) { |     public static String getModifySTableColumnSql(String tbName, List<TdFieldDO> fields) { | ||||||
|         StringBuilder sbModify = new StringBuilder(); |         StringBuilder sbModify = new StringBuilder(); | ||||||
|         for (TdField field : fields) { |         for (TdFieldDO field : fields) { | ||||||
|             sbModify.append(String.format(ALTER_STABLE_MODIFY_COL_TPL, |             sbModify.append(String.format(ALTER_STABLE_MODIFY_COL_TPL, | ||||||
|                     tbName, |                     tbName, | ||||||
|                     FieldParser.getFieldDefine(field) |                     FieldParser.getFieldDefine(field) | ||||||
| @ -144,15 +144,15 @@ public class TableManager { | |||||||
|     /** |     /** | ||||||
|      * 获取删除字段sql |      * 获取删除字段sql | ||||||
|      */ |      */ | ||||||
|     public static String getDropSTableColumnSql(String tbName, List<TdField> fields) { |     public static String getDropSTableColumnSql(String tbName, List<TdFieldDO> fields) { | ||||||
|         StringBuilder sbDrop = new StringBuilder(); |         StringBuilder sbDrop = new StringBuilder(); | ||||||
|         for (TdField field : fields) { |         for (TdFieldDO field : fields) { | ||||||
|             sbDrop.append(String.format(ALTER_STABLE_DROP_COL_TPL, |             sbDrop.append(String.format(ALTER_STABLE_DROP_COL_TPL, | ||||||
|                     tbName, |                     tbName, | ||||||
|                     field.getName() |                     field.getFieldName() | ||||||
|             )); |             )); | ||||||
|         } |         } | ||||||
|         return sbDrop.toString(); |         return sbDrop.toString(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @ -1,6 +1,7 @@ | |||||||
| package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; | package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; | ||||||
| 
 | 
 | ||||||
| import lombok.AllArgsConstructor; | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Builder; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| import lombok.NoArgsConstructor; | import lombok.NoArgsConstructor; | ||||||
| 
 | 
 | ||||||
| @ -10,20 +11,21 @@ import lombok.NoArgsConstructor; | |||||||
| @Data | @Data | ||||||
| @NoArgsConstructor | @NoArgsConstructor | ||||||
| @AllArgsConstructor | @AllArgsConstructor | ||||||
| public class TdField { | @Builder | ||||||
|  | public class TdFieldDO { | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 字段名称 |      * 字段名称 | ||||||
|      */ |      */ | ||||||
|     private String name; |     private String fieldName; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 字段类型 |      * 字段类型 | ||||||
|      */ |      */ | ||||||
|     private String type; |     private String dataType; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 字段长度 |      * 字段长度 | ||||||
|      */ |      */ | ||||||
|     private int length; |     private Integer dataLength = 0; | ||||||
| } | } | ||||||
| @ -17,13 +17,25 @@ public class TdResponse { | |||||||
|     public static final int CODE_SUCCESS = 0; |     public static final int CODE_SUCCESS = 0; | ||||||
|     public static final int CODE_TB_NOT_EXIST = 866; |     public static final int CODE_TB_NOT_EXIST = 866; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 状态 | ||||||
|  |      */ | ||||||
|     private String status; |     private String status; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 错误码 | ||||||
|  |      */ | ||||||
|     private int code; |     private int code; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 错误信息 | ||||||
|  |      */ | ||||||
|     private String desc; |     private String desc; | ||||||
|  |  | ||||||
|     //[["time","TIMESTAMP",8,""],["powerstate","TINYINT",1,""],["brightness","INT",4,""],["deviceid","NCHAR",32,"TAG"]] |     /** | ||||||
|     private List<Object[]> data; |      * 列信息 | ||||||
|  |      * [["time","TIMESTAMP",8,""],["powerstate","TINYINT",1,""],["brightness","INT",4,""],["deviceid","NCHAR",32,"TAG"]] | ||||||
|  |      */ | ||||||
|  |     private List data; | ||||||
|  |  | ||||||
| } | } | ||||||
| @ -14,23 +14,23 @@ import org.springframework.stereotype.Service; | |||||||
| @Service | @Service | ||||||
| public class TdRestApi { | public class TdRestApi { | ||||||
|  |  | ||||||
|     @Value("${spring.datasource.dynamic.datasource.master.url}") |     @Value("${spring.datasource.dynamic.datasource.tdengine.url}") | ||||||
|     private String url; |     private String url; | ||||||
|  |  | ||||||
|     @Value("${spring.datasource.dynamic.datasource.master.username}") |     @Value("${spring.datasource.dynamic.datasource.tdengine.username}") | ||||||
|     private String username; |     private String username; | ||||||
|  |  | ||||||
|     @Value("${spring.datasource.dynamic.datasource.master.password}") |     @Value("${spring.datasource.dynamic.datasource.tdengine.password}") | ||||||
|     private String password; |     private String password; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取 REST API URL | ||||||
|  |      */ | ||||||
|     private String getRestApiUrl() { |     private String getRestApiUrl() { | ||||||
|         //jdbc:TAOS-RS://127.0.0.1:6041/iotkit?xxxx |         String restUrl = url.replace("jdbc:TAOS-RS://", "") | ||||||
|         String restUrl = url.replace("jdbc:TAOS-RS://" , "") |                 .replaceAll("\\?.*", ""); | ||||||
|                 .replaceAll("\\?.*" , ""); |  | ||||||
|         // /rest/sql/iotkit |  | ||||||
|         int idx = restUrl.lastIndexOf("/"); |         int idx = restUrl.lastIndexOf("/"); | ||||||
|         //127.0.0.1:6041/rest/sql/iotkit |         return String.format("%s/rest/sql/%s", restUrl.substring(0, idx), restUrl.substring(idx + 1)); | ||||||
|         return String.format("%s/rest/sql/%s" , restUrl.substring(0, idx), restUrl.substring(idx + 1)); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -48,11 +48,10 @@ public class TdRestApi { | |||||||
|      * 执行sql |      * 执行sql | ||||||
|      */ |      */ | ||||||
|     public TdResponse execSql(String sql) { |     public TdResponse execSql(String sql) { | ||||||
|         log.info("exec td sql:{}" , sql); |         log.info("exec td sql:{}", sql); | ||||||
|         HttpRequest request = newApiRequest(sql); |         HttpRequest request = newApiRequest(sql); | ||||||
|         HttpResponse response = request.execute(); |         HttpResponse response = request.execute(); | ||||||
|         return JSONUtil.toBean(response.body(), TdResponse.class); |         return JSONUtil.toBean(response.body(), TdResponse.class); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| } |  | ||||||
| @ -1,5 +1,6 @@ | |||||||
| package cn.iocoder.yudao.module.iot.dal.tdengine; | package cn.iocoder.yudao.module.iot.dal.tdengine; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; | ||||||
| import cn.iocoder.yudao.module.iot.domain.FieldsVo; | import cn.iocoder.yudao.module.iot.domain.FieldsVo; | ||||||
| import cn.iocoder.yudao.module.iot.domain.SelectDto; | import cn.iocoder.yudao.module.iot.domain.SelectDto; | ||||||
| import cn.iocoder.yudao.module.iot.domain.TableDto; | import cn.iocoder.yudao.module.iot.domain.TableDto; | ||||||
| @ -17,24 +18,80 @@ import java.util.Map; | |||||||
| @DS("tdengine") | @DS("tdengine") | ||||||
| public interface TdEngineMapper { | public interface TdEngineMapper { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 创建数据库 | ||||||
|  |      * | ||||||
|  |      * @param dataBaseName 数据库名称 | ||||||
|  |      */ | ||||||
|  |     @InterceptorIgnore(tenantLine = "true") | ||||||
|     void createDatabase(@Param("dataBaseName") String dataBaseName); |     void createDatabase(@Param("dataBaseName") String dataBaseName); | ||||||
|  |  | ||||||
|     void createSuperTable(@Param("schemaFields") List<FieldsVo> schemaFields, |     /** | ||||||
|                           @Param("tagsFields") List<FieldsVo> tagsFields, |      * 创建超级表 | ||||||
|  |      * | ||||||
|  |      * @param schemaFields   schema字段 | ||||||
|  |      * @param tagsFields     tags字段 | ||||||
|  |      * @param dataBaseName   数据库名称 | ||||||
|  |      * @param superTableName 超级表名称 | ||||||
|  |      */ | ||||||
|  |     @InterceptorIgnore(tenantLine = "true") | ||||||
|  |     void createSuperTable(@Param("schemaFields") List<TdFieldDO> schemaFields, | ||||||
|  |                           @Param("tagsFields") List<TdFieldDO> tagsFields, | ||||||
|                           @Param("dataBaseName") String dataBaseName, |                           @Param("dataBaseName") String dataBaseName, | ||||||
|                           @Param("superTableName") String superTableName); |                           @Param("superTableName") String superTableName); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 查看超级表 - 显示当前数据库下的所有超级表信息 | ||||||
|  |      * SQL:SHOW STABLES [LIKE tb_name_wildcard]; | ||||||
|  |      * | ||||||
|  |      * @param dataBaseName   数据库名称 | ||||||
|  |      * @param superTableName 超级表名称 | ||||||
|  |      */ | ||||||
|  |     @InterceptorIgnore(tenantLine = "true") | ||||||
|  |     List<Map<String, Object>> showSuperTables(@Param("dataBaseName") String dataBaseName, | ||||||
|  |                                               @Param("superTableName") String superTableName); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 查看超级表 - 获取超级表的结构信息 | ||||||
|  |      * SQL:DESCRIBE [db_name.]stb_name; | ||||||
|  |      * <p> | ||||||
|  |      * * @param dataBaseName 数据库名称 | ||||||
|  |      * * @param superTableName 超级表名称 | ||||||
|  |      */ | ||||||
|  |     @InterceptorIgnore(tenantLine = "true") | ||||||
|  |     List<Map<String, Object>> describeSuperTable(@Param("dataBaseName") String dataBaseName, | ||||||
|  |                                                  @Param("superTableName") String superTableName); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 为超级表添加列 | ||||||
|  |      * | ||||||
|  |      * @param dataBaseName   数据库名称 | ||||||
|  |      * @param superTableName 超级表名称 | ||||||
|  |      * @param field          字段信息 | ||||||
|  |      */ | ||||||
|  |     @InterceptorIgnore(tenantLine = "true") | ||||||
|  |     void addColumnForSuperTable(@Param("dataBaseName") String dataBaseName, | ||||||
|  |                                 @Param("superTableName") String superTableName, | ||||||
|  |                                 @Param("field") TdFieldDO field); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 为超级表删除列 | ||||||
|  |      * | ||||||
|  |      * @param dataBaseName   数据库名称 | ||||||
|  |      * @param superTableName 超级表名称 | ||||||
|  |      * @param field          字段信息 | ||||||
|  |      */ | ||||||
|  |     @InterceptorIgnore(tenantLine = "true") | ||||||
|  |     void dropColumnForSuperTable(@Param("dataBaseName") String dataBaseName, | ||||||
|  |                                  @Param("superTableName") String superTableName, | ||||||
|  |                                  @Param("field") TdFieldDO field); | ||||||
|  |  | ||||||
|     void createTable(TableDto tableDto); |     void createTable(TableDto tableDto); | ||||||
|  |  | ||||||
|     void insertData(TableDto tableDto); |     void insertData(TableDto tableDto); | ||||||
|  |  | ||||||
|     List<Map<String, Object>> selectByTimestamp(SelectDto selectDto); |     List<Map<String, Object>> selectByTimestamp(SelectDto selectDto); | ||||||
|  |  | ||||||
|     void addColumnForSuperTable(@Param("superTableName") String superTableName, |  | ||||||
|                                 @Param("fieldsVo") FieldsVo fieldsVo); |  | ||||||
|  |  | ||||||
|     void dropColumnForSuperTable(@Param("superTableName") String superTableName, |  | ||||||
|                                  @Param("fieldsVo") FieldsVo fieldsVo); |  | ||||||
|  |  | ||||||
|     void addTagForSuperTable(@Param("superTableName") String superTableName, |     void addTagForSuperTable(@Param("superTableName") String superTableName, | ||||||
|                              @Param("fieldsVo") FieldsVo fieldsVo); |                              @Param("fieldsVo") FieldsVo fieldsVo); | ||||||
| @ -44,14 +101,6 @@ public interface TdEngineMapper { | |||||||
|  |  | ||||||
|     Map<String, Long> getCountByTimestamp(SelectDto selectDto); |     Map<String, Long> getCountByTimestamp(SelectDto selectDto); | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 检查表是否存在 |  | ||||||
|      * |  | ||||||
|      * @param dataBaseName 数据库名称 |  | ||||||
|      * @param tableName    表名称 |  | ||||||
|      */ |  | ||||||
|     Integer checkTableExists(@Param("dataBaseName") String dataBaseName, @Param("tableName") String tableName); |  | ||||||
|  |  | ||||||
|     Map<String, Object> getLastData(SelectDto selectDto); |     Map<String, Object> getLastData(SelectDto selectDto); | ||||||
|  |  | ||||||
|     List<Map<String, Object>> getHistoryData(SelectVisualDto selectVisualDto); |     List<Map<String, Object>> getHistoryData(SelectVisualDto selectVisualDto); | ||||||
| @ -62,13 +111,5 @@ public interface TdEngineMapper { | |||||||
|  |  | ||||||
|     List<Map<String, Object>> getLastDataByTags(TagsSelectDao tagsSelectDao); |     List<Map<String, Object>> getLastDataByTags(TagsSelectDao tagsSelectDao); | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 创建超级表 |  | ||||||
|      * |  | ||||||
|      * @param sql sql |  | ||||||
|      * @return 返回值 |  | ||||||
|      */ |  | ||||||
|     @InterceptorIgnore(tenantLine = "true") |  | ||||||
|     Integer createSuperTableDevice(String sql); |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,19 +1,22 @@ | |||||||
| package cn.iocoder.yudao.module.iot.service.tdengine; | package cn.iocoder.yudao.module.iot.service.tdengine; | ||||||
|  |  | ||||||
| import cn.hutool.json.JSONUtil; | import cn.hutool.core.collection.CollUtil; | ||||||
| import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; | import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; | ||||||
| import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; | import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*; | import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; | ||||||
|  | import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; | ||||||
|  | import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdRestApi; | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; | import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; | ||||||
| import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper; |  | ||||||
| import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; | import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; | ||||||
| import jakarta.annotation.Resource; | import jakarta.annotation.Resource; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.springframework.beans.factory.annotation.Value; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
|  |  | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
| import java.util.Objects; | import java.util.Objects; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
| @ -22,147 +25,206 @@ import java.util.stream.Collectors; | |||||||
| public class IotDbStructureDataServiceImpl implements IotDbStructureDataService { | public class IotDbStructureDataServiceImpl implements IotDbStructureDataService { | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private TdEngineMapper tdEngineMapper; |     private TdEngineService tdEngineService; | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private TdRestApi tdRestApi; |     private TdRestApi tdRestApi; | ||||||
|  |  | ||||||
|  |     @Value("${spring.datasource.dynamic.datasource.tdengine.url}") | ||||||
|  |     private String url; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) { |     public void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) { | ||||||
|         // 获取物模型中的属性定义 |         // 1. 解析物模型,获得字段列表 | ||||||
|         List<TdField> fields = FieldParser.parse(thingModel); |         List<TdFieldDO> schemaFields = new ArrayList<>(); | ||||||
|         String tbName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); |         schemaFields.add(TdFieldDO.builder(). | ||||||
|  |                 fieldName("time"). | ||||||
|  |                 dataType("TIMESTAMP"). | ||||||
|  |                 build()); | ||||||
|  |         schemaFields.addAll(FieldParser.parse(thingModel)); | ||||||
|  |  | ||||||
|         // 生成创建超级表的 SQL |         // 3. 设置超级表的标签 | ||||||
|         String sql = TableManager.getCreateSTableSql(tbName, fields, new TdField("device_id", "NCHAR", 64)); |         List<TdFieldDO> tagsFields = new ArrayList<>(); | ||||||
|         if (sql == null) { |         tagsFields.add(TdFieldDO.builder(). | ||||||
|             log.warn("生成的 SQL 为空,无法创建超级表"); |                 fieldName("product_key"). | ||||||
|             return; |                 dataType("NCHAR"). | ||||||
|         } |                 dataLength(64). | ||||||
|         log.info("执行 SQL: {}", sql); |                 build()); | ||||||
|  |         tagsFields.add(TdFieldDO.builder(). | ||||||
|  |                 fieldName("device_key"). | ||||||
|  |                 dataType("NCHAR"). | ||||||
|  |                 dataLength(64). | ||||||
|  |                 build()); | ||||||
|  |         tagsFields.add(TdFieldDO.builder(). | ||||||
|  |                 fieldName("device_name"). | ||||||
|  |                 dataType("NCHAR"). | ||||||
|  |                 dataLength(64). | ||||||
|  |                 build()); | ||||||
|  |         // 年 | ||||||
|  |         tagsFields.add(TdFieldDO.builder(). | ||||||
|  |                 fieldName("year"). | ||||||
|  |                 dataType("INT"). | ||||||
|  |                 build()); | ||||||
|  |         // 月 | ||||||
|  |         tagsFields.add(TdFieldDO.builder(). | ||||||
|  |                 fieldName("month"). | ||||||
|  |                 dataType("INT"). | ||||||
|  |                 build()); | ||||||
|  |         // 日 | ||||||
|  |         tagsFields.add(TdFieldDO.builder(). | ||||||
|  |                 fieldName("day"). | ||||||
|  |                 dataType("INT"). | ||||||
|  |                 build()); | ||||||
|  |         // 时 | ||||||
|  |         tagsFields.add(TdFieldDO.builder(). | ||||||
|  |                 fieldName("hour"). | ||||||
|  |                 dataType("INT"). | ||||||
|  |                 build()); | ||||||
|  |  | ||||||
|         // 执行 SQL 创建超级表 |  | ||||||
|         tdEngineMapper.createSuperTableDevice(sql); |         // 4. 获取超级表的名称 | ||||||
|  |         String superTableName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); | ||||||
|  |  | ||||||
|  |         // 5. 创建超级表 | ||||||
|  |         String dataBaseName = url.substring(url.lastIndexOf("/") + 1); | ||||||
|  |         tdEngineService.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType) { |     public void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType) { | ||||||
|         try { |         try { | ||||||
|             // 获取旧字段信息 |  | ||||||
|             String tbName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); |             String tbName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); | ||||||
|             String sql = TableManager.getDescTableSql(tbName); |             List<TdFieldDO> oldFields = getTableFields(tbName); | ||||||
|             TdResponse response = tdRestApi.execSql(sql); |             List<TdFieldDO> newFields = FieldParser.parse(thingModel); | ||||||
|             if (response.getCode() != TdResponse.CODE_SUCCESS) { |  | ||||||
|                 throw new RuntimeException("获取表描述错误: " + JSONUtil.toJsonStr(response)); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             List<TdField> oldFields = FieldParser.parse(response.getData()); |             updateTableFields(tbName, oldFields, newFields); | ||||||
|             List<TdField> newFields = FieldParser.parse(thingModel); |  | ||||||
|  |  | ||||||
|             // 找出新增的字段 |  | ||||||
|             List<TdField> addFields = newFields.stream() |  | ||||||
|                     .filter(f -> oldFields.stream().noneMatch(old -> old.getName().equals(f.getName()))) |  | ||||||
|                     .collect(Collectors.toList()); |  | ||||||
|             if (!addFields.isEmpty()) { |  | ||||||
|                 sql = TableManager.getAddSTableColumnSql(tbName, addFields); |  | ||||||
|                 response = tdRestApi.execSql(sql); |  | ||||||
|                 if (response.getCode() != TdResponse.CODE_SUCCESS) { |  | ||||||
|                     throw new RuntimeException("添加表字段错误: " + JSONUtil.toJsonStr(response)); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             // 找出修改的字段 |  | ||||||
|             List<TdField> modifyFields = newFields.stream() |  | ||||||
|                     .filter(f -> oldFields.stream().anyMatch(old -> |  | ||||||
|                             old.getName().equals(f.getName()) && |  | ||||||
|                                     (!old.getType().equals(f.getType()) || old.getLength() != f.getLength()))) |  | ||||||
|                     .collect(Collectors.toList()); |  | ||||||
|             if (!modifyFields.isEmpty()) { |  | ||||||
|                 sql = TableManager.getModifySTableColumnSql(tbName, modifyFields); |  | ||||||
|                 response = tdRestApi.execSql(sql); |  | ||||||
|                 if (response.getCode() != TdResponse.CODE_SUCCESS) { |  | ||||||
|                     throw new RuntimeException("修改表字段错误: " + JSONUtil.toJsonStr(response)); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             // 找出删除的字段 |  | ||||||
|             List<TdField> dropFields = oldFields.stream() |  | ||||||
|                     .filter(f -> !"time".equals(f.getName()) && !"device_id".equals(f.getName()) && |  | ||||||
|                             newFields.stream().noneMatch(n -> n.getName().equals(f.getName()))) |  | ||||||
|                     .collect(Collectors.toList()); |  | ||||||
|             if (!dropFields.isEmpty()) { |  | ||||||
|                 sql = TableManager.getDropSTableColumnSql(tbName, dropFields); |  | ||||||
|                 response = tdRestApi.execSql(sql); |  | ||||||
|                 if (response.getCode() != TdResponse.CODE_SUCCESS) { |  | ||||||
|                     throw new RuntimeException("删除表字段错误: " + JSONUtil.toJsonStr(response)); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } catch (Throwable e) { |         } catch (Throwable e) { | ||||||
|             log.error("更新物模型超级表失败", e); |             log.error("更新物模型超级表失败", e); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // 获取表字段 | ||||||
|  |     private List<TdFieldDO> getTableFields(String tableName) { | ||||||
|  |         List<TdFieldDO> fields = new ArrayList<>(); | ||||||
|  |         // 获取超级表的描述信息 | ||||||
|  |         List<Map<String, Object>> maps = tdEngineService.describeSuperTable(url.substring(url.lastIndexOf("/") + 1), tableName); | ||||||
|  |         if (maps != null) { | ||||||
|  |             // 过滤掉 note 字段为 TAG 的记录 | ||||||
|  |             maps = maps.stream().filter(map -> !"TAG".equals(map.get("note"))).toList(); | ||||||
|  |             // 过滤掉 time 字段 | ||||||
|  |             maps = maps.stream().filter(map -> !"time".equals(map.get("field"))).toList(); | ||||||
|  |             // 解析字段信息 | ||||||
|  |             fields = FieldParser.parse(maps.stream() | ||||||
|  |                     .map(map -> List.of(map.get("field"), map.get("type"), map.get("length"))) | ||||||
|  |                     .collect(Collectors.toList())); | ||||||
|  |         } | ||||||
|  |         return fields; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // 更新表字段 | ||||||
|  |     private void updateTableFields(String tableName, List<TdFieldDO> oldFields, List<TdFieldDO> newFields) { | ||||||
|  |         // 获取新增字段 | ||||||
|  |         List<TdFieldDO> addFields = getAddFields(oldFields, newFields); | ||||||
|  |         // 获取修改字段 | ||||||
|  |         List<TdFieldDO> modifyFields = getModifyFields(oldFields, newFields); | ||||||
|  |         // 获取删除字段 | ||||||
|  |         List<TdFieldDO> dropFields = getDropFields(oldFields, newFields); | ||||||
|  |  | ||||||
|  |         String dataBaseName = url.substring(url.lastIndexOf("/") + 1); | ||||||
|  |         // 添加新增字段 | ||||||
|  |         if (CollUtil.isNotEmpty(addFields)) { | ||||||
|  |             tdEngineService.addColumnForSuperTable(dataBaseName,tableName, addFields); | ||||||
|  |         } | ||||||
|  |         // 删除旧字段 | ||||||
|  |         if (CollUtil.isNotEmpty(dropFields)) { | ||||||
|  |             tdEngineService.dropColumnForSuperTable(dataBaseName,tableName, dropFields); | ||||||
|  |         } | ||||||
|  |         // 修改字段(先删除再添加) | ||||||
|  |         if (CollUtil.isNotEmpty(modifyFields)) { | ||||||
|  |             tdEngineService.dropColumnForSuperTable(dataBaseName,tableName, modifyFields); | ||||||
|  |             tdEngineService.addColumnForSuperTable(dataBaseName,tableName, modifyFields); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // 获取新增字段 | ||||||
|  |     private List<TdFieldDO> getAddFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) { | ||||||
|  |         return newFields.stream() | ||||||
|  |                 .filter(f -> oldFields.stream().noneMatch(old -> old.getFieldName().equals(f.getFieldName()))) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // 获取修改字段 | ||||||
|  |     private List<TdFieldDO> getModifyFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) { | ||||||
|  |         return newFields.stream() | ||||||
|  |                 .filter(f -> oldFields.stream().anyMatch(old -> | ||||||
|  |                         old.getFieldName().equals(f.getFieldName()) && | ||||||
|  |                                 (!old.getDataType().equals(f.getDataType()) || !Objects.equals(old.getDataLength(), f.getDataLength())))) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // 获取删除字段 | ||||||
|  |     private List<TdFieldDO> getDropFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) { | ||||||
|  |         return oldFields.stream() | ||||||
|  |                 .filter(f -> !"time".equals(f.getFieldName()) && !"device_id".equals(f.getFieldName()) && | ||||||
|  |                         newFields.stream().noneMatch(n -> n.getFieldName().equals(f.getFieldName()))) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void createSuperTableDataModel(IotProductDO product, List<IotThinkModelFunctionDO> functionList) { |     public void createSuperTableDataModel(IotProductDO product, List<IotThinkModelFunctionDO> functionList) { | ||||||
|         // 1. 生成 ThingModelRespVO |         ThingModelRespVO thingModel = buildThingModel(product, functionList); | ||||||
|         ThingModelRespVO thingModel = new ThingModelRespVO(); |  | ||||||
|         thingModel.setId(product.getId()); |  | ||||||
|         thingModel.setProductKey(product.getProductKey()); |  | ||||||
|  |  | ||||||
|         // 1.1 设置属性、服务和事件 |         if (thingModel.getModel().getProperties().isEmpty()) { | ||||||
|         ThingModelRespVO.Model model = new ThingModelRespVO.Model(); |  | ||||||
|         List<ThingModelProperty> properties = new ArrayList<>(); |  | ||||||
|  |  | ||||||
|         // 1.2 遍历功能列表并分类 |  | ||||||
|         for (IotThinkModelFunctionDO function : functionList) { |  | ||||||
|             if (Objects.requireNonNull(IotProductFunctionTypeEnum.valueOf(function.getType())) == IotProductFunctionTypeEnum.PROPERTY) { |  | ||||||
|                 ThingModelProperty property = new ThingModelProperty(); |  | ||||||
|                 property.setIdentifier(function.getIdentifier()); |  | ||||||
|                 property.setName(function.getName()); |  | ||||||
|                 property.setDescription(function.getDescription()); |  | ||||||
|                 property.setDataType(function.getProperty().getDataType()); |  | ||||||
|                 properties.add(property); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // 1.3 判断属性列表是否为空 |  | ||||||
|         if (properties.isEmpty()) { |  | ||||||
|             log.warn("物模型属性列表为空,不创建超级表"); |             log.warn("物模型属性列表为空,不创建超级表"); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         model.setProperties(properties); |         String superTableName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey()); | ||||||
|         thingModel.setModel(model); |         String dataBaseName = url.substring(url.lastIndexOf("/") + 1); | ||||||
|  |         Integer tableExists = tdEngineService.checkSuperTableExists(dataBaseName, superTableName); | ||||||
|  |  | ||||||
|         // 2. 判断是否已经创建,如果已经创建则进行更新 |         if (tableExists != null && tableExists > 0) { | ||||||
|         String tbName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey()); |  | ||||||
|         Integer iot = tdEngineMapper.checkTableExists("ruoyi_vue_pro", tbName); |  | ||||||
|         if (iot != null && iot > 0) { |  | ||||||
|             // 3. 更新 |  | ||||||
|             updateSuperTable(thingModel, product.getDeviceType()); |             updateSuperTable(thingModel, product.getDeviceType()); | ||||||
|         } else { |         } else { | ||||||
|             // 4. 创建 |  | ||||||
|             createSuperTable(thingModel, product.getDeviceType()); |             createSuperTable(thingModel, product.getDeviceType()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     private ThingModelRespVO buildThingModel(IotProductDO product, List<IotThinkModelFunctionDO> functionList) { | ||||||
|      * 根据产品key获取产品属性超级表名 |         ThingModelRespVO thingModel = new ThingModelRespVO(); | ||||||
|      */ |         thingModel.setId(product.getId()); | ||||||
|     static String getProductPropertySTableName(Integer deviceType, String productKey) { |         thingModel.setProductKey(product.getProductKey()); | ||||||
|         if (deviceType == 1) { |  | ||||||
|             return String.format("gateway_sub_" + productKey).toLowerCase(); |         ThingModelRespVO.Model model = new ThingModelRespVO.Model(); | ||||||
|         } else if (deviceType == 2) { |         List<ThingModelProperty> properties = functionList.stream() | ||||||
|             return String.format("gateway_" + productKey).toLowerCase(); |                 .filter(function -> IotProductFunctionTypeEnum.PROPERTY.equals(IotProductFunctionTypeEnum.valueOf(function.getType()))) | ||||||
|         } else { |                 .map(this::buildThingModelProperty) | ||||||
|             return String.format("device_" + productKey).toLowerCase(); |                 .collect(Collectors.toList()); | ||||||
|         } |  | ||||||
|  |         model.setProperties(properties); | ||||||
|  |         thingModel.setModel(model); | ||||||
|  |  | ||||||
|  |         return thingModel; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     private ThingModelProperty buildThingModelProperty(IotThinkModelFunctionDO function) { | ||||||
|      * 根据deviceId获取设备属性表名 |         ThingModelProperty property = new ThingModelProperty(); | ||||||
|      */ |         property.setIdentifier(function.getIdentifier()); | ||||||
|     static String getDevicePropertyTableName(String deviceType, String productKey, String deviceKey) { |         property.setName(function.getName()); | ||||||
|         return String.format(deviceType + "_" + productKey + "_" + deviceKey).toLowerCase(); |         property.setDescription(function.getDescription()); | ||||||
|  |         property.setDataType(function.getProperty().getDataType()); | ||||||
|  |         return property; | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     static String getProductPropertySTableName(Integer deviceType, String productKey) { | ||||||
|  |         return switch (deviceType) { | ||||||
|  |             case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase(); | ||||||
|  |             case 2 -> String.format("gateway_%s", productKey).toLowerCase(); | ||||||
|  |             default -> String.format("device_%s", productKey).toLowerCase(); | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static String getDevicePropertyTableName(String deviceType, String productKey, String deviceKey) { | ||||||
|  |         return String.format("%s_%s_%s", deviceType, productKey, deviceKey).toLowerCase(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,6 +1,6 @@ | |||||||
| package cn.iocoder.yudao.module.iot.service.tdengine; | package cn.iocoder.yudao.module.iot.service.tdengine; | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.module.iot.domain.FieldsVo; | import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; | ||||||
| import cn.iocoder.yudao.module.iot.domain.SelectDto; | import cn.iocoder.yudao.module.iot.domain.SelectDto; | ||||||
| import cn.iocoder.yudao.module.iot.domain.TableDto; | import cn.iocoder.yudao.module.iot.domain.TableDto; | ||||||
| import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; | import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; | ||||||
| @ -27,12 +27,44 @@ public interface TdEngineService { | |||||||
|      * |      * | ||||||
|      * @param schemaFields   schema字段 |      * @param schemaFields   schema字段 | ||||||
|      * @param tagsFields     tags字段 |      * @param tagsFields     tags字段 | ||||||
|      * @param dataBaseName   数据库名称 |  | ||||||
|      * @param superTableName 超级表名称 |      * @param superTableName 超级表名称 | ||||||
|      * @throws Exception 异常 |  | ||||||
|      */ |      */ | ||||||
|     void createSuperTable(List<FieldsVo> schemaFields, List<FieldsVo> tagsFields, String dataBaseName, |     void createSuperTable(List<TdFieldDO> schemaFields, List<TdFieldDO> tagsFields, String dataBaseName, String superTableName); | ||||||
|                           String superTableName) throws Exception; |  | ||||||
|  |     /** | ||||||
|  |      * 检查超级表是否存在 | ||||||
|  |      */ | ||||||
|  |     Integer checkSuperTableExists(String dataBaseName, String superTableName); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取超级表的结构信息 | ||||||
|  |      */ | ||||||
|  |     List<Map<String, Object>> describeSuperTable(String dataBaseName, String superTableName); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 为超级表添加列 | ||||||
|  |      * | ||||||
|  |      * @param dataBaseName 数据库名称 | ||||||
|  |      * @param superTableName 超级表名称 | ||||||
|  |      * @param fieldsVo       字段信息 | ||||||
|  |      */ | ||||||
|  |     void addColumnForSuperTable(String dataBaseName,String superTableName, List<TdFieldDO> fieldsVo); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 为超级表删除列 | ||||||
|  |      * | ||||||
|  |      * @param dataBaseName 数据库名称 | ||||||
|  |      * @param superTableName 超级表名称 | ||||||
|  |      * @param fieldsVo       字段信息 | ||||||
|  |      */ | ||||||
|  |     void dropColumnForSuperTable(String dataBaseName,String superTableName, List<TdFieldDO> fieldsVo); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 为超级表添加tag | ||||||
|  |      */ | ||||||
|  |     Long getCountByTimesTamp(SelectDto selectDto) throws Exception; | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 创建表 |      * 创建表 | ||||||
| @ -59,37 +91,6 @@ public interface TdEngineService { | |||||||
|      */ |      */ | ||||||
|     List<Map<String, Object>> selectByTimesTamp(SelectDto selectDto) throws Exception; |     List<Map<String, Object>> selectByTimesTamp(SelectDto selectDto) throws Exception; | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 为超级表添加列 |  | ||||||
|      * |  | ||||||
|      * @param superTableName 超级表名称 |  | ||||||
|      * @param fieldsVo       字段信息 |  | ||||||
|      * @throws Exception 异常 |  | ||||||
|      */ |  | ||||||
|     void addColumnForSuperTable(String superTableName, FieldsVo fieldsVo) throws Exception; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 为超级表删除列 |  | ||||||
|      * |  | ||||||
|      * @param superTableName 超级表名称 |  | ||||||
|      * @param fieldsVo       字段信息 |  | ||||||
|      * @throws Exception 异常 |  | ||||||
|      */ |  | ||||||
|     void dropColumnForSuperTable(String superTableName, FieldsVo fieldsVo) throws Exception; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 为超级表添加tag |  | ||||||
|      */ |  | ||||||
|     Long getCountByTimesTamp(SelectDto selectDto) throws Exception; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 检查表是否存在 |  | ||||||
|      * |  | ||||||
|      * @return 1存在 0不存在 |  | ||||||
|      * @throws Exception 异常 |  | ||||||
|      */ |  | ||||||
|     Integer checkTableExists(SelectDto selectDto) throws Exception; |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 初始化超级表 |      * 初始化超级表 | ||||||
|      * |      * | ||||||
| @ -138,4 +139,6 @@ public interface TdEngineService { | |||||||
|      * @return 数据 |      * @return 数据 | ||||||
|      */ |      */ | ||||||
|     List<Map<String, Object>> getAggregateData(SelectVisualDto selectVisualDto); |     List<Map<String, Object>> getAggregateData(SelectVisualDto selectVisualDto); | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,10 +1,12 @@ | |||||||
| package cn.iocoder.yudao.module.iot.service.tdengine; | package cn.iocoder.yudao.module.iot.service.tdengine; | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.module.iot.domain.FieldsVo; | import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; | ||||||
|  | import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper; | ||||||
| import cn.iocoder.yudao.module.iot.domain.SelectDto; | import cn.iocoder.yudao.module.iot.domain.SelectDto; | ||||||
| import cn.iocoder.yudao.module.iot.domain.TableDto; | import cn.iocoder.yudao.module.iot.domain.TableDto; | ||||||
| import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; | import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; | ||||||
| import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; | import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; | ||||||
|  | import jakarta.annotation.Resource; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
|  |  | ||||||
| @ -15,25 +17,27 @@ import java.util.Map; | |||||||
| @Slf4j | @Slf4j | ||||||
| public class TdEngineServiceImpl implements TdEngineService { | public class TdEngineServiceImpl implements TdEngineService { | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private TdEngineMapper tdEngineMapper; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void createDateBase(String dataBaseName) { |     public void createDateBase(String dataBaseName) { | ||||||
|  |         tdEngineMapper.createDatabase(dataBaseName); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void createSuperTable(List<FieldsVo> schemaFields, List<FieldsVo> tagsFields, String dataBaseName, String superTableName) { |     public void createSuperTable(List<TdFieldDO> schemaFields, List<TdFieldDO> tagsFields, String dataBaseName, String superTableName) { | ||||||
|  |         tdEngineMapper.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void createTable(TableDto tableDto) { |     public void createTable(TableDto tableDto) { | ||||||
|  |         tdEngineMapper.createTable(tableDto); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void insertData(TableDto tableDto) { |     public void insertData(TableDto tableDto) { | ||||||
|  |         tdEngineMapper.insertData(tableDto); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @ -42,13 +46,17 @@ public class TdEngineServiceImpl implements TdEngineService { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void addColumnForSuperTable(String superTableName, FieldsVo fieldsVo) { |     public void addColumnForSuperTable(String dataBaseName,String superTableName, List<TdFieldDO> fields) { | ||||||
|  |         for (TdFieldDO field : fields) { | ||||||
|  |             tdEngineMapper.addColumnForSuperTable(dataBaseName,superTableName, field); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void dropColumnForSuperTable(String superTableName, FieldsVo fieldsVo) { |     public void dropColumnForSuperTable(String dataBaseName,String superTableName, List<TdFieldDO> fields) { | ||||||
|  |         for (TdFieldDO field : fields) { | ||||||
|  |             tdEngineMapper.dropColumnForSuperTable(dataBaseName,superTableName, field); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @ -56,11 +64,6 @@ public class TdEngineServiceImpl implements TdEngineService { | |||||||
|         return 0L; |         return 0L; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public Integer checkTableExists(SelectDto selectDto) { |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void initSTableFrame(String msg) { |     public void initSTableFrame(String msg) { | ||||||
|  |  | ||||||
| @ -90,4 +93,15 @@ public class TdEngineServiceImpl implements TdEngineService { | |||||||
|     public List<Map<String, Object>> getAggregateData(SelectVisualDto selectVisualDto) { |     public List<Map<String, Object>> getAggregateData(SelectVisualDto selectVisualDto) { | ||||||
|         return List.of(); |         return List.of(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Integer checkSuperTableExists(String dataBaseName, String superTableName) { | ||||||
|  |         List<Map<String, Object>> results = tdEngineMapper.showSuperTables(dataBaseName, superTableName); | ||||||
|  |         return results == null || results.isEmpty() ? 0 : results.size(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<Map<String, Object>> describeSuperTable(String dataBaseName, String superTableName) { | ||||||
|  |         return tdEngineMapper.describeSuperTable(dataBaseName, superTableName); | ||||||
|  |     } | ||||||
| } | } | ||||||
| @ -174,8 +174,10 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe | |||||||
|     public void createSuperTableDataModel(Long productId) { |     public void createSuperTableDataModel(Long productId) { | ||||||
|         // 1. 查询产品 |         // 1. 查询产品 | ||||||
|         IotProductDO product = productService.getProduct(productId); |         IotProductDO product = productService.getProduct(productId); | ||||||
|  |  | ||||||
|         // 2. 查询产品的物模型功能列表 |         // 2. 查询产品的物模型功能列表 | ||||||
|         List<IotThinkModelFunctionDO> functionList = thinkModelFunctionMapper.selectListByProductId(productId); |         List<IotThinkModelFunctionDO> functionList = thinkModelFunctionMapper.selectListByProductId(productId); | ||||||
|  |  | ||||||
|         // 3. 生成 TDengine 的数据模型 |         // 3. 生成 TDengine 的数据模型 | ||||||
|         dbStructureDataService.createSuperTableDataModel(product, functionList); |         dbStructureDataService.createSuperTableDataModel(product, functionList); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
|     </update> |     </update> | ||||||
|  |  | ||||||
|     <update id="createSuperTable"> |     <update id="createSuperTable"> | ||||||
|         create table if not exists #{dataBaseName}.#{superTableName} |         CREATE STABLE IF NOT EXISTS ${dataBaseName}.${superTableName} | ||||||
|         <foreach item="item" collection="schemaFields" separator="," |         <foreach item="item" collection="schemaFields" separator="," | ||||||
|                  open="(" close=")" index=""> |                  open="(" close=")" index=""> | ||||||
|             <if test="item.fieldName != null || item.fieldName != ''"> |             <if test="item.fieldName != null || item.fieldName != ''"> | ||||||
| @ -16,46 +16,48 @@ | |||||||
|             </if> |             </if> | ||||||
|             <if test="item.dataType != null || item.dataType != ''"> |             <if test="item.dataType != null || item.dataType != ''"> | ||||||
|                 <choose> |                 <choose> | ||||||
|                     <when test="item.dataType == 'timestamp'"> |                     <when test="item.dataType == 'TIMESTAMP'"> | ||||||
|                         timestamp |                         TIMESTAMP | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'tinyint'"> |                     <when test="item.dataType == 'TINYINT'"> | ||||||
|                         tinyint |                         TINYINT | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'smallint'"> |                     <when test="item.dataType == 'SMALLINT'"> | ||||||
|                         smallint |                         SMALLINT | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'int'"> |                     <when test="item.dataType == 'INT'"> | ||||||
|                         int |                         INT | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'bigint'"> |                     <when test="item.dataType == 'BIGINT'"> | ||||||
|                         bigint |                         BIGINT | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'float'"> |                     <when test="item.dataType == 'FLOAT'"> | ||||||
|                         float |                         FLOAT | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'double'"> |                     <when test="item.dataType == 'DOUBLE'"> | ||||||
|                         double |                         DOUBLE | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'binary'"> |                     <when test="item.dataType == 'BINARY'"> | ||||||
|                         binary |                         BINARY | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'nchar'"> |                     <when test="item.dataType == 'NCHAR'"> | ||||||
|                         nchar |                         NCHAR | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'bool'"> |                     <when test="item.dataType == 'BOOL'"> | ||||||
|                         bool |                         BOOL | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'json'"> |                     <when test="item.dataType == 'JSON'"> | ||||||
|                         json |                         JSON | ||||||
|                     </when> |                     </when> | ||||||
|                 </choose> |                 </choose> | ||||||
|             </if> |             </if> | ||||||
|             <if test="item.size != null"> |             <if test="item.dataLength > 0"> | ||||||
|                 (#{item.size}) |                 ( | ||||||
|  |                 ${item.dataLength} | ||||||
|  |                 ) | ||||||
|             </if> |             </if> | ||||||
|         </foreach> |         </foreach> | ||||||
|         tags |         TAGS | ||||||
|         <!--tdEngine不支持动态tags里的数据类型,只能使用choose标签比对--> |         <!--tdEngine不支持动态tags里的数据类型,只能使用choose标签比对--> | ||||||
|         <foreach item="item" collection="tagsFields" separator="," |         <foreach item="item" collection="tagsFields" separator="," | ||||||
|                  open="(" close=")" index=""> |                  open="(" close=")" index=""> | ||||||
| @ -64,43 +66,45 @@ | |||||||
|             </if> |             </if> | ||||||
|             <if test="item.dataType != null || item.dataType != ''"> |             <if test="item.dataType != null || item.dataType != ''"> | ||||||
|                 <choose> |                 <choose> | ||||||
|                     <when test="item.dataType == 'timestamp'"> |                     <when test="item.dataType == 'TIMESTAMP'"> | ||||||
|                         timestamp |                         TIMESTAMP | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'tinyint'"> |                     <when test="item.dataType == 'TINYINT'"> | ||||||
|                         tinyint |                         TINYINT | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'smallint'"> |                     <when test="item.dataType == 'SMALLINT'"> | ||||||
|                         smallint |                         SMALLINT | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'int'"> |                     <when test="item.dataType == 'INT'"> | ||||||
|                         int |                         INT | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'bigint'"> |                     <when test="item.dataType == 'BIGINT'"> | ||||||
|                         bigint |                         BIGINT | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'float'"> |                     <when test="item.dataType == 'FLOAT'"> | ||||||
|                         float |                         FLOAT | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'double'"> |                     <when test="item.dataType == 'DOUBLE'"> | ||||||
|                         double |                         DOUBLE | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'binary'"> |                     <when test="item.dataType == 'BINARY'"> | ||||||
|                         binary |                         BINARY | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'nchar'"> |                     <when test="item.dataType == 'NCHAR'"> | ||||||
|                         nchar |                         NCHAR | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'bool'"> |                     <when test="item.dataType == 'BOOL'"> | ||||||
|                         bool |                         BOOL | ||||||
|                     </when> |                     </when> | ||||||
|                     <when test="item.dataType == 'json'"> |                     <when test="item.dataType == 'JSON'"> | ||||||
|                         json |                         JSON | ||||||
|                     </when> |                     </when> | ||||||
|                 </choose> |                 </choose> | ||||||
|             </if> |             </if> | ||||||
|             <if test="item.size != null"> |             <if test="item.dataLength > 0"> | ||||||
|                 (#{item.size}) |                 ( | ||||||
|  |                 ${item.dataLength} | ||||||
|  |                 ) | ||||||
|             </if> |             </if> | ||||||
|         </foreach> |         </foreach> | ||||||
|     </update> |     </update> | ||||||
| @ -135,7 +139,6 @@ | |||||||
|         </foreach> |         </foreach> | ||||||
|     </insert> |     </insert> | ||||||
|  |  | ||||||
|  |  | ||||||
|     <select id="selectByTimestamp" parameterType="cn.iocoder.yudao.module.iot.domain.SelectDto" |     <select id="selectByTimestamp" parameterType="cn.iocoder.yudao.module.iot.domain.SelectDto" | ||||||
|             resultType="Map"> |             resultType="Map"> | ||||||
|         select * from #{dataBaseName}.#{tableName} |         select * from #{dataBaseName}.#{tableName} | ||||||
| @ -146,66 +149,58 @@ | |||||||
|     </select> |     </select> | ||||||
|  |  | ||||||
|     <update id="addColumnForSuperTable"> |     <update id="addColumnForSuperTable"> | ||||||
|         ALTER |         ALTER STABLE ${dataBaseName}.${superTableName} ADD COLUMN | ||||||
|         STABLE |         <if test="field.fieldName != null || field.fieldName != ''"> | ||||||
|         #{superTableName} |             #{field.fieldName} | ||||||
|         ADD |  | ||||||
|         COLUMN |  | ||||||
|         <if test="fieldsVo.fieldName != null || fieldsVo.fieldName != ''"> |  | ||||||
|             #{fieldsVo.fieldName} |  | ||||||
|         </if> |         </if> | ||||||
|         <if test="fieldsVo.dataType != null || fieldsVo.dataType != ''"> |         <if test="field.dataType != null || field.dataType != ''"> | ||||||
|             <choose> |             <choose> | ||||||
|                 <when test="fieldsVo.dataType == 'timestamp'"> |                 <when test="field.dataType == 'TIMESTAMP'"> | ||||||
|                     timestamp |                     TIMESTAMP | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'tinyint'"> |                 <when test="field.dataType == 'TINYINT'"> | ||||||
|                     tinyint |                     TINYINT | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'smallint'"> |                 <when test="field.dataType == 'SMALLINT'"> | ||||||
|                     smallint |                     SMALLINT | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'int'"> |                 <when test="field.dataType == 'INT'"> | ||||||
|                     int |                     INT | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'bigint'"> |                 <when test="field.dataType == 'BIGINT'"> | ||||||
|                     bigint |                     BIGINT | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'float'"> |                 <when test="field.dataType == 'FLOAT'"> | ||||||
|                     float |                     FLOAT | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'double'"> |                 <when test="field.dataType == 'DOUBLE'"> | ||||||
|                     double |                     DOUBLE | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'binary'"> |                 <when test="field.dataType == 'BINARY'"> | ||||||
|                     binary |                     BINARY | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'nchar'"> |                 <when test="field.dataType == 'NCHAR'"> | ||||||
|                     nchar |                     NCHAR | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'bool'"> |                 <when test="field.dataType == 'BOOL'"> | ||||||
|                     bool |                     BOOL | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'json'"> |                 <when test="field.dataType == 'JSON'"> | ||||||
|                     json |                     JSON | ||||||
|                 </when> |                 </when> | ||||||
|             </choose> |             </choose> | ||||||
|         </if> |         </if> | ||||||
|         <if test="fieldsVo.size != null"> |         <if test="field.dataLength > 0"> | ||||||
|             ( |             ( | ||||||
|             #{fieldsVo.size} |             #{field.dataLength} | ||||||
|             ) |             ) | ||||||
|         </if> |         </if> | ||||||
|     </update> |     </update> | ||||||
|  |  | ||||||
|     <update id="dropColumnForSuperTable"> |     <update id="dropColumnForSuperTable"> | ||||||
|         ALTER |         ALTER STABLE ${dataBaseName}.${superTableName} DROP COLUMN | ||||||
|         STABLE |         <if test="field.fieldName != null || field.fieldName != ''"> | ||||||
|         #{superTableName} |             #{field.fieldName} | ||||||
|         DROP |  | ||||||
|         COLUMN |  | ||||||
|         <if test="fieldsVo.fieldName != null || fieldsVo.fieldName != ''"> |  | ||||||
|             #{fieldsVo.fieldName} |  | ||||||
|         </if> |         </if> | ||||||
|     </update> |     </update> | ||||||
|  |  | ||||||
| @ -215,49 +210,49 @@ | |||||||
|         #{superTableName} |         #{superTableName} | ||||||
|         ADD |         ADD | ||||||
|         TAG |         TAG | ||||||
|         <if test="fieldsVo.fieldName != null || fieldsVo.fieldName != ''"> |         <if test="field.fieldName != null || fieldDO.fieldName != ''"> | ||||||
|             #{fieldsVo.fieldName} |             #{fieldDO.fieldName} | ||||||
|         </if> |         </if> | ||||||
|         <if test="fieldsVo.dataType != null || fieldsVo.dataType != ''"> |         <if test="fieldDO.dataType != null || fieldDO.dataType != ''"> | ||||||
|             <choose> |             <choose> | ||||||
|                 <when test="fieldsVo.dataType == 'timestamp'"> |                 <when test="fieldDO.dataType == 'timestamp'"> | ||||||
|                     timestamp |                     timestamp | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'tinyint'"> |                 <when test="fieldDO.dataType == 'tinyint'"> | ||||||
|                     tinyint |                     tinyint | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'smallint'"> |                 <when test="fieldDO.dataType == 'smallint'"> | ||||||
|                     smallint |                     smallint | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'int'"> |                 <when test="fieldDO.dataType == 'int'"> | ||||||
|                     int |                     int | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'bigint'"> |                 <when test="fieldDO.dataType == 'bigint'"> | ||||||
|                     bigint |                     bigint | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'float'"> |                 <when test="fieldDO.dataType == 'float'"> | ||||||
|                     float |                     float | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'double'"> |                 <when test="fieldDO.dataType == 'double'"> | ||||||
|                     double |                     double | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'binary'"> |                 <when test="fieldDO.dataType == 'binary'"> | ||||||
|                     binary |                     binary | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'nchar'"> |                 <when test="fieldDO.dataType == 'nchar'"> | ||||||
|                     nchar |                     nchar | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'bool'"> |                 <when test="fieldDO.dataType == 'bool'"> | ||||||
|                     bool |                     bool | ||||||
|                 </when> |                 </when> | ||||||
|                 <when test="fieldsVo.dataType == 'json'"> |                 <when test="fieldDO.dataType == 'json'"> | ||||||
|                     json |                     json | ||||||
|                 </when> |                 </when> | ||||||
|             </choose> |             </choose> | ||||||
|         </if> |         </if> | ||||||
|         <if test="fieldsVo.size != null"> |         <if test="fieldDO.dataLength > 0"> | ||||||
|             ( |             ( | ||||||
|             #{fieldsVo.size} |             #{fieldDO.dataLength} | ||||||
|             ) |             ) | ||||||
|         </if> |         </if> | ||||||
|     </update> |     </update> | ||||||
| @ -279,11 +274,8 @@ | |||||||
|         FROM #{dataBaseName}.#{tableName} WHERE ${fieldName} BETWEEN #{startTime} AND #{endTime} |         FROM #{dataBaseName}.#{tableName} WHERE ${fieldName} BETWEEN #{startTime} AND #{endTime} | ||||||
|     </select> |     </select> | ||||||
|  |  | ||||||
|     <select id="checkTableExists" resultType="java.lang.Integer"> |     <select id="showSuperTables" resultType="java.util.Map"> | ||||||
|         SELECT COUNT(0) |         SHOW ${dataBaseName}.STABLES LIKE '${superTableName}' | ||||||
|         FROM information_schema.ins_tables |  | ||||||
|         WHERE db_name = #{dataBaseName} |  | ||||||
|           AND table_name = #{tableName} |  | ||||||
|     </select> |     </select> | ||||||
|  |  | ||||||
|     <select id="getLastData" resultType="java.util.Map"> |     <select id="getLastData" resultType="java.util.Map"> | ||||||
| @ -304,11 +296,13 @@ | |||||||
|         FROM #{dataBaseName}.#{tableName} WHERE ts BETWEEN #{startTime} AND #{endTime} |         FROM #{dataBaseName}.#{tableName} WHERE ts BETWEEN #{startTime} AND #{endTime} | ||||||
|         LIMIT #{num} |         LIMIT #{num} | ||||||
|     </select> |     </select> | ||||||
|  |  | ||||||
|     <select id="getRealtimeData" resultType="java.util.Map" |     <select id="getRealtimeData" resultType="java.util.Map" | ||||||
|             parameterType="cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto"> |             parameterType="cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto"> | ||||||
|         SELECT #{fieldName}, ts |         SELECT #{fieldName}, ts | ||||||
|         FROM #{dataBaseName}.#{tableName} LIMIT #{num} |         FROM #{dataBaseName}.#{tableName} LIMIT #{num} | ||||||
|     </select> |     </select> | ||||||
|  |  | ||||||
|     <select id="getAggregateData" resultType="java.util.Map" |     <select id="getAggregateData" resultType="java.util.Map" | ||||||
|             parameterType="cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto"> |             parameterType="cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto"> | ||||||
|         SELECT #{aggregate}(${fieldName}) |         SELECT #{aggregate}(${fieldName}) | ||||||
| @ -316,9 +310,8 @@ | |||||||
|         LIMIT #{num} |         LIMIT #{num} | ||||||
|     </select> |     </select> | ||||||
|  |  | ||||||
|  |     <select id="describeSuperTable" resultType="java.util.Map"> | ||||||
|     <insert id="createSuperTableDevice"> |         DESCRIBE ${dataBaseName}.${superTableName} | ||||||
|         ${sql} |     </select> | ||||||
|     </insert> |  | ||||||
|  |  | ||||||
| </mapper> | </mapper> | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 安浩浩
					安浩浩