Browse Source

新增:增加 IOT 物模型

安浩浩 7 months ago
parent
commit
18e789d4fb
13 changed files with 588 additions and 4 deletions
  1. 4 1
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
  2. 96 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
  3. 63 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java
  4. 90 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java
  5. 38 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
  6. 26 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
  7. 44 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java
  8. 25 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
  9. 2 3
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
  10. 43 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java
  11. 74 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
  12. 12 0
      yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml
  13. 71 0
      yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java

+ 4 - 1
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java

@@ -9,8 +9,11 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
  */
 public interface ErrorCodeConstants {
 
-    // ========== 产品相关  1-050-001-000 ============
+    // ========== IoT 产品相关  1-050-001-000 ============
     ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在");
     ErrorCode PRODUCT_IDENTIFICATION_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在");
     ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除");
+
+    // ========== IoT 产品物模型 1-050-002-000 ============
+    ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在");
 }

+ 96 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http

@@ -0,0 +1,96 @@
+### 请求 /iot/think-model-function/create 接口 => 成功
+POST {{baseUrl}}/iot/think-model-function/create
+Content-Type: application/json
+tenant-id: {{adminTenentId}}
+Authorization: Bearer {{token}}
+
+{
+  "productKey": "123456",
+  "properties": [
+    {
+      "identifier": "CurrentTemperature",
+      "name": "当前温度",
+      "accessMode": "r",
+      "required": true,
+      "dataType": {
+        "type": "float",
+        "specs": {
+          "min": "-40",
+          "max": "120",
+          "unit": "°C",
+          "unitName": "摄氏度",
+          "step": "0.1"
+        }
+      }
+    },
+    {
+      "identifier": "CurrentHumidity",
+      "name": "当前湿度",
+      "accessMode": "r",
+      "required": true,
+      "dataType": {
+        "type": "float",
+        "specs": {
+          "min": "0",
+          "max": "100",
+          "unit": "%",
+          "unitName": "百分比",
+          "step": "0.1"
+        }
+      }
+    }
+  ],
+  "services": "{}",
+  "events": "{}"
+}
+
+### 请求 /iot/think-model-function/update 接口 => 成功
+PUT {{baseUrl}}/iot/think-model-function/update
+Content-Type: application/json
+tenant-id: {{adminTenentId}}
+Authorization: Bearer {{token}}
+
+{
+  "productKey": "123456",
+  "properties": [
+    {
+      "identifier": "CurrentTemperature",
+      "name": "当前温度",
+      "accessMode": "r",
+      "required": true,
+      "dataType": {
+        "type": "float",
+        "specs": {
+          "min": "-40",
+          "max": "130",
+          "unit": "°C",
+          "unitName": "摄氏度",
+          "step": "0.1"
+        }
+      }
+    },
+    {
+      "identifier": "CurrentHumidity",
+      "name": "当前湿度",
+      "accessMode": "r",
+      "required": true,
+      "dataType": {
+        "type": "float",
+        "specs": {
+          "min": "0",
+          "max": "100",
+          "unit": "%",
+          "unitName": "百分比",
+          "step": "0.1"
+        }
+      }
+    }
+  ],
+  "services": "{}",
+  "events": "{}"
+}
+
+### 请求 /iot/think-model-function/get 接口 => 成功
+GET {{baseUrl}}/iot/think-model-function/get?productKey=123456
+tenant-id: {{adminTenentId}}
+Authorization: Bearer {{token}}

+ 63 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java

@@ -0,0 +1,63 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction;
+
+import org.springframework.web.bind.annotation.*;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import jakarta.validation.*;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.*;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
+import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService;
+
+@Tag(name = "管理后台 - IoT 产品物模型")
+@RestController
+@RequestMapping("/iot/think-model-function")
+@Validated
+public class IotThinkModelFunctionController {
+
+    @Resource
+    private IotThinkModelFunctionService thinkModelFunctionService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建IoT 产品物模型")
+    @PreAuthorize("@ss.hasPermission('iot:think-model-function:create')")
+    public CommonResult<Long> createThinkModelFunction(@Valid @RequestBody IotThinkModelFunctionSaveReqVO createReqVO) {
+        return success(thinkModelFunctionService.createThinkModelFunction(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新IoT 产品物模型")
+    @PreAuthorize("@ss.hasPermission('iot:think-model-function:update')")
+    public CommonResult<Boolean> updateThinkModelFunction(@Valid @RequestBody IotThinkModelFunctionSaveReqVO updateReqVO) {
+        thinkModelFunctionService.updateThinkModelFunctionByProductKey(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除IoT 产品物模型")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('iot:think-model-function:delete')")
+    public CommonResult<Boolean> deleteThinkModelFunction(@RequestParam("id") Long id) {
+        thinkModelFunctionService.deleteThinkModelFunction(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得IoT 产品物模型")
+    @Parameter(name = "productKey", description = "产品Key", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')")
+    public CommonResult<IotThinkModelFunctionRespVO> getThinkModelFunctionByProductKey(@RequestParam("productKey")  String productKey) {
+        IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunctionByProductKey(productKey);
+        return success(BeanUtils.toBean(thinkModelFunction, IotThinkModelFunctionRespVO.class));
+    }
+
+}

+ 90 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java

@@ -0,0 +1,90 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - IoT 产品物模型属性")
+@Data
+public class IotThingModelProperty {
+
+    @Schema(description = "属性标识符")
+    private String identifier;
+
+    @Schema(description = "属性名称")
+    private String name;
+
+    @Schema(description = "访问模式 (r/rw)")
+    private String accessMode;
+
+    @Schema(description = "是否必需")
+    private boolean required;
+
+    @Schema(description = "数据类型")
+    private DataType dataType;
+
+    @Schema(description = "数据类型")
+    @Data
+    public static class DataType {
+
+        @Schema(description = "数据类型(float, double, struct, enum等)")
+        private String type;
+
+        @Schema(description = "单一类型的规格(适用于float, double等)")
+        private Specs specs;
+
+        @Schema(description = "结构体字段(适用于struct类型)")
+        private List<StructField> structSpecs;
+
+        @Schema(description = "规格")
+        @Data
+        public static class Specs {
+
+            @Schema(description = "最小值")
+            private String min;
+
+            @Schema(description = "最大值")
+            private String max;
+
+            @Schema(description = "单位符号")
+            private String unit;
+
+            @Schema(description = "单位名称")
+            private String unitName;
+
+            @Schema(description = "步进值")
+            private String step;
+        }
+
+        @Schema(description = "结构体字段")
+        @Data
+        public static class StructField {
+
+            @Schema(description = "字段标识符")
+            private String identifier;
+
+            @Schema(description = "字段名称")
+            private String name;
+
+            @Schema(description = "字段的数据类型")
+            private DataType dataType;
+        }
+    }
+
+    @Schema(description = "枚举规格")
+    @Data
+    public static class EnumSpecs {
+
+        @Schema(description = "枚举值")
+        private int value;
+
+        @Schema(description = "枚举名称")
+        private String name;
+
+        public EnumSpecs(int value, String name) {
+            this.value = value;
+            this.name = name;
+        }
+    }
+}

+ 38 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - IoT 产品物模型 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotThinkModelFunctionRespVO {
+
+    @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816")
+    @ExcelProperty("产品ID")
+    private Long id;
+
+    @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("产品标识")
+    private String productKey;
+
+    @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("属性列表")
+    private String properties;
+
+    @Schema(description = "服务列表")
+    @ExcelProperty("服务列表")
+    private String services;
+
+    @Schema(description = "事件列表")
+    @ExcelProperty("事件列表")
+    private String events;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 26 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java

@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import jakarta.validation.constraints.*;
+
+@Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO")
+@Data
+public class IotThinkModelFunctionSaveReqVO {
+
+    @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "产品标识不能为空")
+    private String productKey;
+
+    @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "属性列表不能为空")
+    private List<IotThingModelProperty> properties;
+
+    @Schema(description = "服务列表")
+    private String services;
+
+    @Schema(description = "事件列表")
+    private String events;
+
+}

+ 44 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java

@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction;
+
+import lombok.*;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * IoT 产品物模型 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("iot_think_model_function")
+@KeySequence("iot_think_model_function_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class IotThinkModelFunctionDO extends BaseDO {
+
+    /**
+     * 产品ID
+     */
+    @TableId
+    private Long id;
+    /**
+     * 产品标识
+     */
+    private String productKey;
+    /**
+     * 属性列表
+     */
+    private String properties;
+    /**
+     * 服务列表
+     */
+    private String services;
+    /**
+     * 事件列表
+     */
+    private String events;
+
+}

+ 25 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * IoT 产品物模型 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface IotThinkModelFunctionMapper extends BaseMapperX<IotThinkModelFunctionDO> {
+
+    default IotThinkModelFunctionDO selectByProductKey(String productKey) {
+        return selectOne(new LambdaQueryWrapperX<IotThinkModelFunctionDO>().eq(IotThinkModelFunctionDO::getProductKey, productKey));
+    }
+
+    default int updateByProductKey(IotThinkModelFunctionDO thinkModelFunction) {
+        return update(thinkModelFunction, new LambdaQueryWrapperX<IotThinkModelFunctionDO>()
+                .eq(IotThinkModelFunctionDO::getProductKey, thinkModelFunction.getProductKey())
+        );
+    }
+}

+ 2 - 3
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java

@@ -16,8 +16,7 @@ import java.util.Objects;
 import java.util.UUID;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS;
-import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_STATUS_NOT_DELETE;
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
 
 /**
  * IoT 产品 Service 实现类
@@ -54,7 +53,7 @@ public class IotProductServiceImpl implements IotProductService {
         }
         // 2. 校验唯一性
         if (productMapper.selectByProductKey(productKey) != null) {
-            throw exception(PRODUCT_NOT_EXISTS);
+            throw exception(PRODUCT_IDENTIFICATION_EXISTS);
         }
         createReqVO.setProductKey(productKey);
     }

+ 43 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
+
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
+import jakarta.validation.Valid;
+
+/**
+ * IoT 产品物模型 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface IotThinkModelFunctionService {
+
+    /**
+     * 创建IoT 产品物模型
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO createReqVO);
+
+    /**
+     * 删除IoT 产品物模型
+     *
+     * @param id 编号
+     */
+    void deleteThinkModelFunction(Long id);
+
+    /**
+     * 获得IoT 产品物模型
+     *
+     * @param productKey 产品Key
+     * @return IoT 产品物模型
+     */
+    IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey);
+
+    /**
+     * 更新IoT 产品物模型
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateThinkModelFunctionByProductKey(@Valid IotThinkModelFunctionSaveReqVO updateReqVO);
+}

+ 74 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java

@@ -0,0 +1,74 @@
+package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
+
+import cn.hutool.json.JSONUtil;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
+import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS;
+
+/**
+ * IoT 产品物模型 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionService {
+
+    @Resource
+    private IotThinkModelFunctionMapper thinkModelFunctionMapper;
+
+    @Override
+    public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) {
+        // 插入
+        IotThinkModelFunctionDO thinkModelFunction = BeanUtils.toBean(createReqVO, IotThinkModelFunctionDO.class);
+        // properties 字段,需要转换成 JSON
+        thinkModelFunction.setProperties(JSONUtil.toJsonStr(createReqVO.getProperties()));
+        thinkModelFunctionMapper.insert(thinkModelFunction);
+        // 返回
+        return thinkModelFunction.getId();
+    }
+
+    @Override
+    public void deleteThinkModelFunction(Long id) {
+        // 校验存在
+        validateThinkModelFunctionExists(id);
+        // 删除
+        thinkModelFunctionMapper.deleteById(id);
+    }
+
+    private void validateThinkModelFunctionExists(Long id) {
+        if (thinkModelFunctionMapper.selectById(id) == null) {
+            throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS);
+        }
+    }
+
+    private void validateThinkModelFunctionExistsByProductKey(String productKey) {
+        if (thinkModelFunctionMapper.selectByProductKey(productKey) == null) {
+            throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey) {
+        return thinkModelFunctionMapper.selectByProductKey(productKey);
+    }
+
+    @Override
+    public void updateThinkModelFunctionByProductKey(IotThinkModelFunctionSaveReqVO updateReqVO) {
+        // 校验存在
+        validateThinkModelFunctionExistsByProductKey(updateReqVO.getProductKey());
+        // 更新
+        IotThinkModelFunctionDO thinkModelFunction = BeanUtils.toBean(updateReqVO, IotThinkModelFunctionDO.class);
+        // properties 字段,需要转换成 JSON
+        thinkModelFunction.setProperties(JSONUtil.toJsonStr(updateReqVO.getProperties()));
+        thinkModelFunctionMapper.updateByProductKey(thinkModelFunction);
+    }
+
+}

+ 12 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>

+ 71 - 0
yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java

@@ -0,0 +1,71 @@
+package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
+
+import org.junit.jupiter.api.Test;
+
+import jakarta.annotation.Resource;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.*;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
+import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper;
+
+import org.springframework.context.annotation.Import;
+
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * {@link IotThinkModelFunctionServiceImpl} 的单元测试类
+ *
+ * @author 芋道源码
+ */
+@Import(IotThinkModelFunctionServiceImpl.class)
+public class IotThinkModelFunctionServiceImplTest extends BaseDbUnitTest {
+
+    @Resource
+    private IotThinkModelFunctionServiceImpl thinkModelFunctionService;
+
+    @Resource
+    private IotThinkModelFunctionMapper thinkModelFunctionMapper;
+
+    @Test
+    public void testCreateThinkModelFunction_success() {
+        // 准备参数
+        IotThinkModelFunctionSaveReqVO createReqVO = randomPojo(IotThinkModelFunctionSaveReqVO.class);
+
+        // 调用
+        Long thinkModelFunctionId = thinkModelFunctionService.createThinkModelFunction(createReqVO);
+        // 断言
+        assertNotNull(thinkModelFunctionId);
+        // 校验记录的属性是否正确
+        IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionMapper.selectById(thinkModelFunctionId);
+        assertPojoEquals(createReqVO, thinkModelFunction, "id");
+    }
+
+    @Test
+    public void testDeleteThinkModelFunction_success() {
+        // mock 数据
+        IotThinkModelFunctionDO dbThinkModelFunction = randomPojo(IotThinkModelFunctionDO.class);
+        thinkModelFunctionMapper.insert(dbThinkModelFunction);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Long id = dbThinkModelFunction.getId();
+
+        // 调用
+        thinkModelFunctionService.deleteThinkModelFunction(id);
+       // 校验数据不存在了
+       assertNull(thinkModelFunctionMapper.selectById(id));
+    }
+
+    @Test
+    public void testDeleteThinkModelFunction_notExists() {
+        // 准备参数
+        Long id = randomLongId();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> thinkModelFunctionService.deleteThinkModelFunction(id), THINK_MODEL_FUNCTION_NOT_EXISTS);
+    }
+
+}