Skip to content

FindApi 配置

FindApi 系列是 VEF Framework 中最常用的查询 API,提供了丰富的配置选项。

QueryPart 系统

QueryPart 是 FindApi 的核心配置机制,允许你定义查询的各个部分:

go
type QueryPart[M any] struct {
    Select    []string
    Condition func(q *orm.Query[M]) *orm.Query[M]
    OrderBy   string
    Preload   []string
}

使用 QueryPart

go
apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithQueryPart(&apis.QueryPart[models.User]{
        Select:  []string{"id", "username", "email", "created_at"},
        OrderBy: "created_at DESC",
        Preload: []string{"Department", "Roles"},
        Condition: func(q *orm.Query[models.User]) *orm.Query[models.User] {
            return q.Where("is_deleted", false)
        },
    })

动态查询配置

WithDynamicCondition

根据请求上下文动态添加条件:

go
apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithDynamicCondition(func(ctx fiber.Ctx, search payloads.UserSearch) func(q *orm.Query[models.User]) *orm.Query[models.User] {
        return func(q *orm.Query[models.User]) *orm.Query[models.User] {
            // Get current user from context
            currentUser := contextx.GetCurrentUser(ctx)
            
            // Non-admin users can only see users in their department
            if !currentUser.IsAdmin {
                q = q.Where("department_id", currentUser.DepartmentId)
            }
            
            return q
        }
    })

WithDynamicSelect

根据请求动态选择字段:

go
apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithDynamicSelect(func(ctx fiber.Ctx, search payloads.UserSearch) []string {
        // Admin users can see all fields
        if contextx.GetCurrentUser(ctx).IsAdmin {
            return []string{"*"}
        }
        // Regular users see limited fields
        return []string{"id", "username", "email"}
    })

关联数据加载

基本预加载

go
apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithPreload("Department", "Roles")

条件预加载

go
apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithPreloadCondition("Roles", func(q *gorm.DB) *gorm.DB {
        return q.Where("is_active", true)
    })

嵌套预加载

go
apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithPreload("Department.Company", "Roles.Permissions")

树形查询配置

基本树形查询

go
import "github.com/ilxqx/vef-framework-go/treebuilder"

// Tree builder function
func buildDepartmentTree(items []models.Department) []models.Department {
    return treebuilder.Build(
        items,
        treebuilder.Adapter[models.Department]{
            GetId:       func(m models.Department) string { return m.Id },
            GetParentId: func(m models.Department) string { return m.ParentId.ValueOrZero() },
            SetChildren: func(m *models.Department, children []models.Department) {
                m.Children = children
            },
        },
    )
}

// Configure FindTreeApi
apis.NewFindTreeApi[models.Department, payloads.DeptSearch](buildDepartmentTree).
    WithIdColumn("id").
    WithParentIdColumn("parent_id")

懒加载树形查询

go
apis.NewFindTreeApi[models.Department, payloads.DeptSearch](buildDepartmentTree).
    WithLazyLoad(true).
    WithRootCondition(func(q *orm.Query[models.Department]) *orm.Query[models.Department] {
        return q.WhereNull("parent_id")
    })

树形选项查询

go
apis.NewFindTreeOptionsApi[models.Department, payloads.DeptSearch](buildDepartmentTree).
    WithDefaultColumnMapping(&apis.DataOptionColumnMapping{
        LabelColumn: "name",
        ValueColumn: "id",
    }).
    WithExtraColumns("code", "level")

结果处理

WithProcessor

处理查询结果:

go
apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithProcessor(func(items []models.User) []models.User {
        for i := range items {
            // Remove sensitive data
            items[i].Password = ""
            
            // Add computed fields
            items[i].FullName = items[i].FirstName + " " + items[i].LastName
        }
        return items
    })

WithResultTransformer

转换为不同的返回类型:

go
type UserDTO struct {
    Id       string `json:"id"`
    Username string `json:"username"`
    Email    string `json:"email"`
}

apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithResultTransformer(func(items []models.User) []UserDTO {
        result := make([]UserDTO, len(items))
        for i, item := range items {
            result[i] = UserDTO{
                Id:       item.Id,
                Username: item.Username,
                Email:    item.Email,
            }
        }
        return result
    })

分页配置

默认分页设置

go
apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithDefaultPageSize(20).
    WithMaxPageSize(100)

自定义分页参数名

go
apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithPageParamName("pageNum").
    WithPageSizeParamName("pageSize")

排序配置

默认排序

go
apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithOrderBy("created_at DESC")

多字段排序

go
apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithOrderBy("is_active DESC, created_at DESC")

动态排序

go
apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithDynamicOrderBy(func(ctx fiber.Ctx, search payloads.UserSearch) string {
        if search.SortField != "" {
            direction := "ASC"
            if search.SortOrder == "desc" {
                direction = "DESC"
            }
            return fmt.Sprintf("%s %s", search.SortField, direction)
        }
        return "created_at DESC"
    })

完整配置示例

go
package resources

import (
    "my-app/internal/modules/user/models"
    "my-app/internal/modules/user/payloads"
    
    "github.com/ilxqx/vef-framework-go/api"
    "github.com/ilxqx/vef-framework-go/apis"
    "github.com/ilxqx/vef-framework-go/contextx"
    "github.com/ilxqx/vef-framework-go/orm"
)

type UserResource struct {
    api.Resource
    apis.FindPageApi[models.User, payloads.UserSearch]
}

func NewUserResource() api.Resource {
    return &UserResource{
        Resource: api.NewResource("smp/sys/user"),
        
        FindPageApi: apis.NewFindPageApi[models.User, payloads.UserSearch]().
            // Permission
            WithPermission("user:read").
            
            // Query configuration
            WithQueryPart(&apis.QueryPart[models.User]{
                Select:  []string{"id", "username", "email", "is_active", "department_id", "created_at"},
                OrderBy: "created_at DESC",
                Preload: []string{"Department"},
            }).
            
            // Dynamic condition based on user role
            WithDynamicCondition(func(ctx fiber.Ctx, search payloads.UserSearch) func(q *orm.Query[models.User]) *orm.Query[models.User] {
                return func(q *orm.Query[models.User]) *orm.Query[models.User] {
                    currentUser := contextx.GetCurrentUser(ctx)
                    if !currentUser.IsAdmin {
                        q = q.Where("department_id", currentUser.DepartmentId)
                    }
                    return q.Where("is_deleted", false)
                }
            }).
            
            // Result processing
            WithProcessor(func(items []models.User) []models.User {
                for i := range items {
                    items[i].Password = ""
                }
                return items
            }).
            
            // Pagination
            WithDefaultPageSize(20).
            WithMaxPageSize(100),
    }
}

下一步

基于 Apache License 2.0 许可发布