فهرست منبع

feat(managesdk): 添加高级查询功能支持

- 在 QueryResourcesParams 中新增 AdvancedQuery 字段
- 实现完整的高级查询参数结构定义
- 提供多种查询操作符包括等于、不等于、大小比较等
- 支持逻辑操作符 AND、OR 的条件组合
- 实现嵌套条件组和条件项的数据结构
- 提供便捷的查询构建函数如 Equal、Like、AndGroup 等
- 添加详细的高级查询使用文档和多个实用示例
- 支持与传统查询参数混合使用的能力
haolongfei 2 هفته پیش
والد
کامیت
55b4b9ef36
3فایلهای تغییر یافته به همراه601 افزوده شده و 15 حذف شده
  1. 430 0
      ADVANCED_QUERY_USAGE.md
  2. 155 0
      advanced_query.go
  3. 16 15
      model.go

+ 430 - 0
ADVANCED_QUERY_USAGE.md

@@ -0,0 +1,430 @@
+# 高级查询使用说明
+
+## 概述
+
+高级查询模块提供了类似 Navicat 数据筛选的灵活查询条件构建能力,支持复杂的条件组合和嵌套。
+
+## 核心概念
+
+### 1. 查询操作符 (QueryOperator)
+
+| 操作符 | 常量 | 说明 | 示例 |
+|--------|------|------|------|
+| 等于 | `OperatorEqual` | 字段值等于指定值 | `name = "测试"` |
+| 不等于 | `OperatorNotEqual` | 字段值不等于指定值 | `status != "deleted"` |
+| 大于 | `OperatorGreaterThan` | 字段值大于指定值 | `quantity > 10` |
+| 大于等于 | `OperatorGreaterEqual` | 字段值大于等于指定值 | `price >= 100` |
+| 小于 | `OperatorLessThan` | 字段值小于指定值 | `stock < 50` |
+| 小于等于 | `OperatorLessEqual` | 字段值小于等于指定值 | `age <= 18` |
+| 包含 | `OperatorLike` | 字段值包含指定字符串 | `name LIKE "%测试%"` |
+| 不包含 | `OperatorNotLike` | 字段值不包含指定字符串 | `name NOT LIKE "%测试%"` |
+| 开头是 | `OperatorStartsWith` | 字段值以指定字符串开头 | `code LIKE "ABC%"` |
+| 结尾是 | `OperatorEndsWith` | 字段值以指定字符串结尾 | `email LIKE "%@qq.com"` |
+| 为空 | `OperatorIsNull` | 字段值为 NULL | `deleted_at IS NULL` |
+| 不为空 | `OperatorIsNotNull` | 字段值不为 NULL | `email IS NOT NULL` |
+| 在列表中 | `OperatorIn` | 字段值在指定列表中 | `status IN ('active', 'pending')` |
+| 不在列表中 | `OperatorNotIn` | 字段值不在指定列表中 | `status NOT IN ('deleted', 'archived')` |
+
+### 2. 逻辑操作符 (LogicOperator)
+
+| 操作符 | 常量 | 说明 |
+|--------|------|------|
+| 与 | `LogicAnd` | 所有条件都必须满足 |
+| 或 | `LogicOr` | 满足任意一个条件即可 |
+
+### 3. 数据结构
+
+```go
+// 单个查询条件
+type QueryCondition struct {
+    Field    string        // 字段名
+    Operator QueryOperator // 操作符
+    Value    any           // 比较值(可选)
+}
+
+// 条件项(可以是单个条件或嵌套的条件组)
+type ConditionItem struct {
+    Condition       *ConditionGroup // 嵌套条件组
+    SingleCondition *QueryCondition // 单个条件
+}
+
+// 条件组
+type ConditionGroup struct {
+    Conditions []ConditionItem // 条件列表
+    Logic      LogicOperator   // 组内逻辑关系
+}
+
+// 高级查询参数
+type AdvancedQueryParams struct {
+    ConditionGroups []ConditionGroup // 条件组列表
+    GroupLogic      LogicOperator    // 组间逻辑关系
+}
+```
+
+## 快捷函数
+
+### 单条件快捷函数
+
+```go
+// 等于
+Equal("name", "测试资源")
+
+// 不等于
+NotEqual("status", "deleted")
+
+// 大于
+GreaterThan("quantity", 10)
+
+// 大于等于
+GreaterEqual("price", 100)
+
+// 小于
+LessThan("stock", 50)
+
+// 小于等于
+LessEqual("age", 18)
+
+// 包含(模糊匹配)
+Like("name", "测试")
+
+// 不包含
+NotLike("name", "测试")
+
+// 开头是
+StartsWith("code", "ABC")
+
+// 结尾是
+EndsWith("email", "@qq.com")
+
+// 为空
+IsNull("deleted_at")
+
+// 不为空
+IsNotNull("email")
+
+// 在列表中
+In("category", []any{"设备", "耗材", "工具"})
+
+// 不在列表中
+NotIn("status", []any{"deleted", "archived"})
+```
+
+### 条件组快捷函数
+
+```go
+// AND 条件组(所有条件都必须满足)
+AndGroup(
+    Equal("name", "测试"),
+    GreaterThan("quantity", 10),
+    IsNotNull("code"),
+)
+
+// OR 条件组(满足任意一个条件即可)
+OrGroup(
+    Equal("category", "设备"),
+    Equal("category", "耗材"),
+    Like("name", "测试"),
+)
+```
+
+### 完整查询快捷函数
+
+```go
+// AND 查询(所有条件组都必须满足)
+AndQuery(
+    AndGroup(Equal("name", "测试"), GreaterThan("quantity", 10)),
+    OrGroup(Equal("category", "设备"), Equal("category", "耗材")),
+)
+
+// OR 查询(满足任意一个条件组即可)
+OrQuery(
+    AndGroup(Equal("status", "active"), GreaterThan("quantity", 0)),
+    AndGroup(Equal("status", "pending"), IsNotNull("approved_by")),
+)
+```
+
+## 使用示例
+
+### 示例 1:简单条件查询
+
+查询名称包含"测试"且数量大于 10 的资源:
+
+```go
+params := managesdk.QueryResourcesParams{
+    TenantID: "tenant123",
+    AdvancedQuery: &managesdk.AdvancedQueryParams{
+        ConditionGroups: []managesdk.ConditionGroup{
+            managesdk.AndGroup(
+                managesdk.Like("name", "测试"),
+                managesdk.GreaterThan("quantity", 10),
+            ),
+        },
+        GroupLogic: managesdk.LogicAnd,
+    },
+    BaseQueryParams: managesdk.BaseQueryParams{
+        PageNo:   1,
+        PageSize: 10,
+    },
+}
+
+result, err := client.Manage().Query(params)
+```
+
+等价于 SQL:
+```sql
+WHERE (name LIKE '%测试%' AND quantity > 10)
+```
+
+### 示例 2:OR 条件查询
+
+查询分类为"设备"或"耗材"的资源:
+
+```go
+params := managesdk.QueryResourcesParams{
+    TenantID: "tenant123",
+    AdvancedQuery: &managesdk.AdvancedQueryParams{
+        ConditionGroups: []managesdk.ConditionGroup{
+            managesdk.OrGroup(
+                managesdk.Equal("category", "设备"),
+                managesdk.Equal("category", "耗材"),
+            ),
+        },
+        GroupLogic: managesdk.LogicAnd,
+    },
+    PageNo:   1,
+    PageSize: 10,
+}
+```
+
+等价于 SQL:
+```sql
+WHERE (category = '设备' OR category = '耗材')
+```
+
+### 示例 3:使用 IN 操作符
+
+查询多个分类的资源:
+
+```go
+params := managesdk.QueryResourcesParams{
+    TenantID: "tenant123",
+    AdvancedQuery: &managesdk.AdvancedQueryParams{
+        ConditionGroups: []managesdk.ConditionGroup{
+            {
+                Conditions: []managesdk.ConditionItem{
+                    managesdk.In("category", []any{"设备", "耗材", "工具"}),
+                },
+                Logic: managesdk.LogicAnd,
+            },
+        },
+        GroupLogic: managesdk.LogicAnd,
+    },
+    PageNo:   1,
+    PageSize: 10,
+}
+```
+
+等价于 SQL:
+```sql
+WHERE category IN ('设备', '耗材', '工具')
+```
+
+### 示例 4:复杂嵌套查询
+
+查询满足以下条件的资源:
+- (名称包含"测试" AND 数量 > 10) OR (分类是"设备" AND 状态不为空)
+
+```go
+params := managesdk.QueryResourcesParams{
+    TenantID: "tenant123",
+    AdvancedQuery: managesdk.OrQuery(
+        managesdk.AndGroup(
+            managesdk.Like("name", "测试"),
+            managesdk.GreaterThan("quantity", 10),
+        ),
+        managesdk.AndGroup(
+            managesdk.Equal("category", "设备"),
+            managesdk.IsNotNull("status"),
+        ),
+    ),
+    PageNo:   1,
+    PageSize: 10,
+}
+```
+
+等价于 SQL:
+```sql
+WHERE ((name LIKE '%测试%' AND quantity > 10) OR (category = '设备' AND status IS NOT NULL))
+```
+
+### 示例 5:多条件组组合
+
+查询满足以下条件的资源:
+- (名称包含"测试" AND 数量 > 10)
+- AND (分类是"设备" OR 分类是"耗材")
+- AND (状态不为空)
+
+```go
+params := managesdk.QueryResourcesParams{
+    TenantID: "tenant123",
+    AdvancedQuery: managesdk.AndQuery(
+        // 条件组1:名称和数量
+        managesdk.AndGroup(
+            managesdk.Like("name", "测试"),
+            managesdk.GreaterThan("quantity", 10),
+        ),
+        // 条件组2:分类
+        managesdk.OrGroup(
+            managesdk.Equal("category", "设备"),
+            managesdk.Equal("category", "耗材"),
+        ),
+        // 条件组3:状态
+        managesdk.AndGroup(
+            managesdk.IsNotNull("status"),
+        ),
+    ),
+    PageNo:   1,
+    PageSize: 10,
+}
+```
+
+等价于 SQL:
+```sql
+WHERE ((name LIKE '%测试%' AND quantity > 10) 
+       AND (category = '设备' OR category = '耗材') 
+       AND (status IS NOT NULL))
+```
+
+### 示例 6:深层嵌套查询
+
+查询满足以下条件的资源:
+- ((名称包含"A" OR 名称包含"B") AND 数量 > 0) OR ((分类是"设备" AND 状态是"可用"))
+
+```go
+params := managesdk.QueryResourcesParams{
+    TenantID: "tenant123",
+    AdvancedQuery: managesdk.OrQuery(
+        // 条件组1
+        managesdk.AndGroup(
+            // 嵌套的 OR 条件
+            managesdk.NewNestedConditionGroup(
+                managesdk.OrGroup(
+                    managesdk.Like("name", "A"),
+                    managesdk.Like("name", "B"),
+                ),
+            ),
+            managesdk.GreaterThan("quantity", 0),
+        ),
+        // 条件组2
+        managesdk.AndGroup(
+            managesdk.Equal("category", "设备"),
+            managesdk.Equal("status", "available"),
+        ),
+    ),
+    PageNo:   1,
+    PageSize: 10,
+}
+```
+
+等价于 SQL:
+```sql
+WHERE (((name LIKE '%A%' OR name LIKE '%B%') AND quantity > 0) 
+       OR (category = '设备' AND status = 'available'))
+```
+
+### 示例 7:范围查询
+
+查询数量在 10 到 100 之间的资源:
+
+```go
+params := managesdk.QueryResourcesParams{
+    TenantID: "tenant123",
+    AdvancedQuery: &managesdk.AdvancedQueryParams{
+        ConditionGroups: []managesdk.ConditionGroup{
+            managesdk.AndGroup(
+                managesdk.GreaterEqual("quantity", 10),
+                managesdk.LessEqual("quantity", 100),
+            ),
+        },
+        GroupLogic: managesdk.LogicAnd,
+    },
+    PageNo:   1,
+    PageSize: 10,
+}
+```
+
+等价于 SQL:
+```sql
+WHERE (quantity >= 10 AND quantity <= 100)
+```
+
+### 示例 8:空值判断
+
+查询未删除的资源(deleted_at 为空):
+
+```go
+params := managesdk.QueryResourcesParams{
+    TenantID: "tenant123",
+    AdvancedQuery: &managesdk.AdvancedQueryParams{
+        ConditionGroups: []managesdk.ConditionGroup{
+            managesdk.AndGroup(
+                managesdk.IsNull("deleted_at"),
+            ),
+        },
+        GroupLogic: managesdk.LogicAnd,
+    },
+    PageNo:   1,
+    PageSize: 10,
+}
+```
+
+等价于 SQL:
+```sql
+WHERE deleted_at IS NULL
+```
+
+## 与传统查询参数配合使用
+
+高级查询可以与传统查询参数配合使用:
+
+```go
+params := managesdk.QueryResourcesParams{
+    TenantID:     "tenant123",
+    Name:         "测试",           // 传统参数:名称筛选
+    BusinessType: "mbrms",         // 传统参数:业务类型
+    AdvancedQuery: managesdk.AndQuery(  // 高级查询:额外条件
+        managesdk.GreaterThan("quantity", 10),
+        managesdk.IsNotNull("code"),
+    ),
+    PageNo:   1,
+    PageSize: 10,
+}
+```
+
+传统参数会先应用,然后再应用高级查询条件。
+
+## 最佳实践
+
+### 1. 性能优化
+
+- 对于大表查询,优先使用 `Equal`、`In` 等精确匹配操作符
+- 避免在大文本字段上使用 `Like` 操作符
+- 合理使用索引字段进行查询
+
+### 2. 条件组织
+
+- 将选择性高的条件放在前面
+- 合理分组,避免过深的嵌套层级
+- 使用语义化的条件组命名(通过代码注释)
+
+### 3. 安全性
+
+- 字段名应该使用白名单验证
+- 避免直接拼接用户输入到查询条件
+
+## 注意事项
+
+1. **字段名映射**:确保使用的字段名与数据库字段名一致
+2. **类型匹配**:比较值的类型应与字段类型匹配
+3. **NULL 处理**:`IsNull` 和 `IsNotNull` 不需要 Value 参数
+4. **数组参数**:`In` 和 `NotIn` 的 Value 应该是 `[]any` 类型

+ 155 - 0
advanced_query.go

@@ -0,0 +1,155 @@
+package managesdk
+
+type QueryOperator string
+
+const (
+	OperatorEqual        QueryOperator = "="
+	OperatorNotEqual     QueryOperator = "!="
+	OperatorGreaterThan  QueryOperator = ">"
+	OperatorGreaterEqual QueryOperator = ">="
+	OperatorLessThan     QueryOperator = "<"
+	OperatorLessEqual    QueryOperator = "<="
+	OperatorLike         QueryOperator = "like"
+	OperatorNotLike      QueryOperator = "not_like"
+	OperatorStartsWith   QueryOperator = "starts_with"
+	OperatorEndsWith     QueryOperator = "ends_with"
+	OperatorIsNull       QueryOperator = "is_null"
+	OperatorIsNotNull    QueryOperator = "is_not_null"
+	OperatorIn           QueryOperator = "in"
+	OperatorNotIn        QueryOperator = "not_in"
+)
+
+type LogicOperator string
+
+const (
+	LogicAnd LogicOperator = "AND"
+	LogicOr  LogicOperator = "OR"
+)
+
+type QueryCondition struct {
+	Field    string        `json:"field"`
+	Operator QueryOperator `json:"operator"`
+	Value    any           `json:"value,omitempty"`
+}
+
+type ConditionGroup struct {
+	Conditions []ConditionItem `json:"conditions"`
+	Logic      LogicOperator   `json:"logic"`
+}
+
+type ConditionItem struct {
+	Condition       *ConditionGroup `json:"condition,omitempty"`
+	SingleCondition *QueryCondition `json:"singleCondition,omitempty"`
+}
+
+type AdvancedQueryParams struct {
+	ConditionGroups []ConditionGroup `json:"conditionGroups"`
+	GroupLogic      LogicOperator    `json:"groupLogic"`
+}
+
+type AdvancedQueryRequest struct {
+	AdvancedQuery *AdvancedQueryParams `json:"advancedQuery,omitempty"`
+	BaseQueryParams
+}
+
+func NewConditionGroup(logic LogicOperator, conditions ...ConditionItem) ConditionGroup {
+	return ConditionGroup{
+		Logic:      logic,
+		Conditions: conditions,
+	}
+}
+
+func NewSingleCondition(field string, operator QueryOperator, value any) ConditionItem {
+	return ConditionItem{
+		SingleCondition: &QueryCondition{
+			Field:    field,
+			Operator: operator,
+			Value:    value,
+		},
+	}
+}
+
+func NewNestedConditionGroup(group ConditionGroup) ConditionItem {
+	return ConditionItem{
+		Condition: &group,
+	}
+}
+
+func NewAdvancedQueryParams(groupLogic LogicOperator, groups ...ConditionGroup) *AdvancedQueryParams {
+	return &AdvancedQueryParams{
+		GroupLogic:      groupLogic,
+		ConditionGroups: groups,
+	}
+}
+
+func Equal(field string, value any) ConditionItem {
+	return NewSingleCondition(field, OperatorEqual, value)
+}
+
+func NotEqual(field string, value any) ConditionItem {
+	return NewSingleCondition(field, OperatorNotEqual, value)
+}
+
+func GreaterThan(field string, value any) ConditionItem {
+	return NewSingleCondition(field, OperatorGreaterThan, value)
+}
+
+func GreaterEqual(field string, value any) ConditionItem {
+	return NewSingleCondition(field, OperatorGreaterEqual, value)
+}
+
+func LessThan(field string, value any) ConditionItem {
+	return NewSingleCondition(field, OperatorLessThan, value)
+}
+
+func LessEqual(field string, value any) ConditionItem {
+	return NewSingleCondition(field, OperatorLessEqual, value)
+}
+
+func Like(field string, value any) ConditionItem {
+	return NewSingleCondition(field, OperatorLike, value)
+}
+
+func NotLike(field string, value any) ConditionItem {
+	return NewSingleCondition(field, OperatorNotLike, value)
+}
+
+func StartsWith(field string, value any) ConditionItem {
+	return NewSingleCondition(field, OperatorStartsWith, value)
+}
+
+func EndsWith(field string, value any) ConditionItem {
+	return NewSingleCondition(field, OperatorEndsWith, value)
+}
+
+func IsNull(field string) ConditionItem {
+	return NewSingleCondition(field, OperatorIsNull, nil)
+}
+
+func IsNotNull(field string) ConditionItem {
+	return NewSingleCondition(field, OperatorIsNotNull, nil)
+}
+
+func In(field string, value any) ConditionItem {
+	return NewSingleCondition(field, OperatorIn, value)
+}
+
+func NotIn(field string, value any) ConditionItem {
+	return NewSingleCondition(field, OperatorNotIn, value)
+}
+
+func AndGroup(conditions ...ConditionItem) ConditionGroup {
+	return NewConditionGroup(LogicAnd, conditions...)
+}
+
+func OrGroup(conditions ...ConditionItem) ConditionGroup {
+	return NewConditionGroup(LogicOr, conditions...)
+}
+
+func AndQuery(groups ...ConditionGroup) *AdvancedQueryParams {
+	return NewAdvancedQueryParams(LogicAnd, groups...)
+}
+
+func OrQuery(groups ...ConditionGroup) *AdvancedQueryParams {
+	return NewAdvancedQueryParams(LogicOr, groups...)
+}

+ 16 - 15
model.go

@@ -157,13 +157,14 @@ type DeleteResourceParams struct {
 }
 
 type QueryResourcesParams struct {
-	Name                 string         `form:"name"`
-	BusinessType         string         `form:"businessType"`
-	ExtendPropertyValues map[string]any `form:"extendPropertyValues"`
-	UserID               string         `form:"userId"`
-	QueryMode            string         `form:"queryMode"`
-	CreateUserID         string         `form:"createUserId"`
-	TenantID             string         `form:"tenantId"`
+	Name                 string               `form:"name"`
+	BusinessType         string               `form:"businessType"`
+	ExtendPropertyValues map[string]any       `form:"extendPropertyValues"`
+	UserID               string               `form:"userId"`
+	QueryMode            string               `form:"queryMode"`
+	CreateUserID         string               `form:"createUserId"`
+	TenantID             string               `form:"tenantId"`
+	AdvancedQuery        *AdvancedQueryParams `form:"advancedQuery"`
 	BaseQueryParams
 }
 
@@ -231,14 +232,14 @@ type SaveActivityParams struct {
 }
 
 type QueryActivitiesParams struct {
-	Name                 string             `json:"name,omitempty"`
-	ActorID              string             `json:"actorId,omitempty"`
-	BusinessType         []string           `json:"businessType,omitempty"`
-	ExtendPropertyValues map[string][]any   `json:"extendPropertyValues,omitempty"`
-	CreateUserID         string             `json:"createUserId,omitempty"`
-	TenantID             string             `json:"tenantId"`
-	PageNo               int                `json:"pageNo"`
-	PageSize             int                `json:"pageSize"`
+	Name                 string           `json:"name,omitempty"`
+	ActorID              string           `json:"actorId,omitempty"`
+	BusinessType         []string         `json:"businessType,omitempty"`
+	ExtendPropertyValues map[string][]any `json:"extendPropertyValues,omitempty"`
+	CreateUserID         string           `json:"createUserId,omitempty"`
+	TenantID             string           `json:"tenantId"`
+	PageNo               int              `json:"pageNo"`
+	PageSize             int              `json:"pageSize"`
 }
 
 type DeleteActivityParams struct {