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),
}
}