Repository navigation
Expand file tree
/
Copy pathquery.go
More file actions
123 lines (106 loc) · 2.44 KB
/
Copy pathquery.go
File metadata and controls
123 lines (106 loc) · 2.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package dbquery
import (
"encoding/json"
"fmt"
"hash/fnv"
"sort"
"sync"
)
// IQuery 组合过滤、排序、分页三个维度,表示完整的查询规格。
// 替代旧版 dbfilter.IFilter[F],明确表达"这是一个查询,不只是一个过滤器"。
type IQuery[F any] interface {
IFilter[F]
// Sort 返回排序规格,nil 表示不排序
Sort() ISortSpec
// Page 返回分页规格,nil 表示不分页
Page() IPageSpec
// String 生成组合缓存键(filter + sort + page 三维序列化)
String() string
}
// Query IQuery 的默认实现
type Query[F any] struct {
filter *F
preloads []string
sort ISortSpec
page IPageSpec
strCache string
strOnce sync.Once
}
// NewQuery 创建查询规格
func NewQuery[F any](filter F, opts ...func(*queryOption[F])) IQuery[F] {
o := &queryOption[F]{}
for _, opt := range opts {
opt(o)
}
return &Query[F]{
filter: &filter,
preloads: o.preloads,
sort: o.sort,
page: o.page,
}
}
func (q *Query[F]) Filter() *F {
if q.filter == nil {
q.filter = new(F)
}
return q.filter
}
func (q *Query[F]) Preloads() []string {
if q.preloads == nil {
return []string{}
}
return q.preloads
}
func (q *Query[F]) Sort() ISortSpec {
return q.sort
}
func (q *Query[F]) Page() IPageSpec {
return q.page
}
// queryJSON 缓存键序列化结构
type queryJSON[F any] struct {
Filter any `json:"filter"`
Sort string `json:"sort,omitempty"`
Page string `json:"page,omitempty"`
Preloads []string `json:"preloads,omitempty"`
}
func (q *Query[F]) String() string {
q.strOnce.Do(func() {
q.strCache = q.buildString()
})
return q.strCache
}
// buildString 提取序列化逻辑,由 sync.Once 保证仅执行一次
func (q *Query[F]) buildString() string {
// 排序 preloads 保证缓存 key 稳定
preloads := q.Preloads()
sortedPreloads := make([]string, len(preloads))
copy(sortedPreloads, preloads)
sort.Strings(sortedPreloads)
data := queryJSON[F]{
Filter: q.Filter(),
Sort: sortString(q.sort),
Page: pageString(q.page),
Preloads: sortedPreloads,
}
bs, _ := json.Marshal(data)
return string(bs)
}
// HashKey 使用 FNV-1a 128位哈希生成缓存键
func HashKey(s string) string {
h := fnv.New128a()
h.Write([]byte(s))
return fmt.Sprintf("%x", h.Sum(nil))
}
func sortString(s ISortSpec) string {
if s == nil {
return ""
}
return s.String()
}
func pageString(p IPageSpec) string {
if p == nil {
return ""
}
return p.String()
}