Skip to content

Commit 12c5760

Browse files
committed
refactor: constraints
1 parent da6791f commit 12c5760

8 files changed

Lines changed: 84 additions & 47 deletions

File tree

constraints/constraints.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Package constraints defines a set of useful constraints to be used
6+
// with type parameters.
7+
package constraints
8+
9+
// Signed is a constraint that permits any signed integer type.
10+
// If future releases of Go add new predeclared signed integer types,
11+
// this constraint will be modified to include them.
12+
type Signed interface {
13+
~int | ~int8 | ~int16 | ~int32 | ~int64
14+
}
15+
16+
// Unsigned is a constraint that permits any unsigned integer type.
17+
// If future releases of Go add new predeclared unsigned integer types,
18+
// this constraint will be modified to include them.
19+
type Unsigned interface {
20+
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
21+
}
22+
23+
// Integer is a constraint that permits any integer type.
24+
// If future releases of Go add new predeclared integer types,
25+
// this constraint will be modified to include them.
26+
type Integer interface {
27+
Signed | Unsigned
28+
}
29+
30+
// Float is a constraint that permits any floating-point type.
31+
// If future releases of Go add new predeclared floating-point types,
32+
// this constraint will be modified to include them.
33+
type Float interface {
34+
~float32 | ~float64
35+
}
36+
37+
// Complex is a constraint that permits any complex numeric type.
38+
// If future releases of Go add new predeclared complex numeric types,
39+
// this constraint will be modified to include them.
40+
type Complex interface {
41+
~complex64 | ~complex128
42+
}
43+
44+
// Ordered is a constraint that permits any ordered type: any type
45+
// that supports the operators < <= >= >.
46+
// If future releases of Go add new ordered types,
47+
// this constraint will be modified to include them.
48+
type Ordered interface {
49+
Integer | Float | ~string
50+
}

db/db_page.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
package db
22

33
import (
4-
"golang.org/x/exp/constraints"
4+
"github.com/voidint/box/constraints"
55
)
66

77
// WithMaxPageSize 设置分页大小上限阈值
8-
func WithMaxPageSize[INT constraints.Integer](maxPageSize INT) func(*Page[INT]) {
8+
func WithMaxPageSize[INT constraints.Unsigned](maxPageSize INT) func(*Page[INT]) {
99
return func(pg *Page[INT]) {
1010
pg.maxPageSize = maxPageSize
1111
}
1212
}
1313

1414
// Page 分页
15-
type Page[INT constraints.Integer] struct {
15+
type Page[INT constraints.Unsigned] struct {
1616
pageNo, pageSize, maxPageSize INT
1717
}
1818

1919
// NewPage 返回分页实例
20-
func NewPage[INT constraints.Integer](pageNo, pageSize INT, opts ...func(*Page[INT])) (pg *Page[INT]) {
20+
func NewPage[INT constraints.Unsigned](pageNo, pageSize INT, opts ...func(*Page[INT])) (pg *Page[INT]) {
2121
pg = &Page[INT]{
2222
pageNo: pageNo,
2323
pageSize: pageSize,

db/db_page_test.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,20 @@ import (
88

99
func TestDBPage(t *testing.T) {
1010
for _, item := range []struct {
11-
InPageNo int
12-
InPageSize int
13-
InTotalRecords int
14-
OutLimit int
15-
OutOffset int
16-
OutTotalPages int
11+
InPageNo uint64
12+
InPageSize uint64
13+
InTotalRecords uint64
14+
OutLimit uint64
15+
OutOffset uint64
16+
OutTotalPages uint64
1717
}{
1818
{InPageNo: 1, InPageSize: 10, InTotalRecords: 11, OutLimit: 10, OutOffset: 0, OutTotalPages: 2},
1919
{InPageNo: 2, InPageSize: 3, InTotalRecords: 10, OutLimit: 3, OutOffset: 3, OutTotalPages: 4},
2020
{InPageNo: 0, InPageSize: 0, InTotalRecords: 10, OutLimit: 10, OutOffset: 0, OutTotalPages: 1},
21-
{InPageNo: -1, InPageSize: -2, InTotalRecords: 0, OutLimit: 10, OutOffset: 0, OutTotalPages: 0},
2221
{InPageNo: 1, InPageSize: 30, InTotalRecords: 100, OutLimit: 20, OutOffset: 0, OutTotalPages: 5},
2322
{InPageNo: 1, InPageSize: 30, InTotalRecords: 22, OutLimit: 20, OutOffset: 0, OutTotalPages: 2},
2423
} {
25-
pg := NewPage(item.InPageNo, item.InPageSize, WithMaxPageSize(20))
24+
pg := NewPage[uint64](item.InPageNo, item.InPageSize, WithMaxPageSize(uint64(20)))
2625
assert.Equal(t, item.OutOffset, pg.Offset())
2726
assert.Equal(t, item.OutLimit, pg.Limit())
2827
assert.Equal(t, item.OutTotalPages, pg.TotalPages(item.InTotalRecords))

ecache/entity_cache.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"time"
88

99
"github.com/pkg/errors"
10+
"github.com/voidint/box/constraints"
1011
"golang.org/x/sync/singleflight"
1112
)
1213

@@ -105,16 +106,12 @@ type Cache interface {
105106
IsKeyNotFound(err error) bool
106107
}
107108

108-
type UnsignedInt interface {
109-
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
110-
}
111-
112109
// CacheableEntity defines the contract for cacheable domain entities
113110
// Used to enforce ID-based caching constraints
114111
// Implementations should:
115112
// - Use unsigned integer types for identifiers
116113
// - Maintain immutable ID properties
117-
type CacheableEntity[INT UnsignedInt] interface {
114+
type CacheableEntity[INT constraints.Unsigned] interface {
118115
ID() INT
119116
}
120117

@@ -137,7 +134,7 @@ func DelCachedEntity(ctx context.Context, cache Cache, key string) (affected int
137134
//
138135
// The cache-aside pattern prevents stale cache returns while
139136
// singleflight prevents cache stampede
140-
func GetEntityByID[T CacheableEntity[INT], INT UnsignedInt](
137+
func GetEntityByID[T CacheableEntity[INT], INT constraints.Unsigned](
141138
ctx context.Context,
142139
cache Cache,
143140
entityKeyPrefix string,
@@ -195,7 +192,7 @@ func GetEntityByID[T CacheableEntity[INT], INT UnsignedInt](
195192
// 1. Batch cache lookup with singleflight deduplication
196193
// 2. Database fallback on cache miss
197194
// 3. Cache population with serialized results
198-
func GetEntitiesByID[T CacheableEntity[INT], INT UnsignedInt](
195+
func GetEntitiesByID[T CacheableEntity[INT], INT constraints.Unsigned](
199196
ctx context.Context,
200197
cache Cache,
201198
entityKeyPrefix string,
@@ -258,7 +255,7 @@ func GetEntitiesByID[T CacheableEntity[INT], INT UnsignedInt](
258255
// - String or unsigned integer types
259256
// - Single-field uniqueness (composite keys not supported)
260257
type UniqueKey interface {
261-
~string | UnsignedInt
258+
~string | constraints.Unsigned
262259
}
263260

264261
// GetEntityByUniqueKey implements two-level cache resolution:
@@ -270,7 +267,7 @@ type UniqueKey interface {
270267
// Limitations:
271268
// - Composite unique keys not supported
272269
// - Fixed cache key format
273-
func GetEntityByUniqueKey[T CacheableEntity[INT], INT UnsignedInt, UK UniqueKey](
270+
func GetEntityByUniqueKey[T CacheableEntity[INT], INT constraints.Unsigned, UK UniqueKey](
274271
ctx context.Context,
275272
cache Cache,
276273
entityKeyPrefix string,

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ require (
1313
github.com/pkg/errors v0.9.1
1414
github.com/redis/go-redis/v9 v9.7.3
1515
github.com/stretchr/testify v1.10.0
16-
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e
1716
golang.org/x/sync v0.11.0
1817
golang.org/x/text v0.22.0
1918
)

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
3232
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
3333
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
3434
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
35-
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
36-
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
3735
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
3836
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
3937
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=

page/page.go

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
11
package page
22

33
import (
4+
"github.com/voidint/box/constraints"
45
"github.com/voidint/box/db"
5-
"golang.org/x/exp/constraints"
66
)
77

8-
// Integer 整型类型约束
9-
type Integer interface {
10-
constraints.Integer
11-
}
12-
138
// Page 分页结构定义
14-
type Page[T any, INT Integer] struct {
9+
type Page[T any, INT constraints.Unsigned] struct {
1510
PageNo INT `json:"pageNo"` // 若序列化时想要使用其他的命名风格,建议使用 github.com/json-iterator/go 库中的 extra.SetNamingStrategy() 函数注册自定义命名策略。
1611
PageSize INT `json:"pageSize"`
1712
TotalPages INT `json:"totalPages"`
@@ -20,14 +15,14 @@ type Page[T any, INT Integer] struct {
2015
}
2116

2217
// Pager 分页接口
23-
type Pager[T any, INT Integer] interface {
18+
type Pager[T any, INT constraints.Unsigned] interface {
2419
AddRecords(records ...T)
2520
BuildDBPage() *db.Page[INT]
2621
BuildPage() *Page[T, INT]
2722
}
2823

2924
// NewPager 构建一个分页对象
30-
func NewPager[T any, INT Integer](pageNo, pageSize, totalRecords INT) Pager[T, INT] {
25+
func NewPager[T any, INT constraints.Unsigned](pageNo, pageSize, totalRecords INT) Pager[T, INT] {
3126
if pageNo <= 0 {
3227
pageNo = 1
3328
}
@@ -52,7 +47,7 @@ func NewPager[T any, INT Integer](pageNo, pageSize, totalRecords INT) Pager[T, I
5247
}
5348

5449
// pagerImpl 实际的分页对象
55-
type pagerImpl[T any, INT Integer] struct {
50+
type pagerImpl[T any, INT constraints.Unsigned] struct {
5651
pageNo INT
5752
pageSize INT
5853
totalPages INT
@@ -82,7 +77,7 @@ func (p *pagerImpl[T, INT]) BuildPage() *Page[T, INT] {
8277
}
8378

8479
// EmptyPage 返回空分页
85-
func EmptyPage[T any, INT Integer](pageNo, pageSize INT) *Page[T, INT] {
80+
func EmptyPage[T any, INT constraints.Unsigned](pageNo, pageSize INT) *Page[T, INT] {
8681
return &Page[T, INT]{
8782
PageNo: pageNo,
8883
PageSize: pageSize,
@@ -93,7 +88,7 @@ func EmptyPage[T any, INT Integer](pageNo, pageSize INT) *Page[T, INT] {
9388
}
9489

9590
// mustCalculateTotalPages 计算总分页数
96-
func mustCalculateTotalPages[INT Integer](pageSize, totalRecords INT) (totalPages INT) {
91+
func mustCalculateTotalPages[INT constraints.Unsigned](pageSize, totalRecords INT) (totalPages INT) {
9792
if pageSize <= 0 {
9893
panic("page size should be positive integer")
9994
}

page/page_test.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ import (
88

99
func TestPage(t *testing.T) {
1010
for _, item := range []struct {
11-
PageNo int
12-
PageSize int
13-
TotalRecords int
14-
TotalPages int
15-
Offset int
16-
Records []int
11+
PageNo uint64
12+
PageSize uint64
13+
TotalRecords uint64
14+
TotalPages uint64
15+
Offset uint64
16+
Records []uint64
1717
}{
1818
{PageNo: 1, PageSize: 10, TotalRecords: 100, TotalPages: 10, Offset: 0},
1919
{PageNo: 2, PageSize: 3, TotalRecords: 7, TotalPages: 3, Offset: 3},
2020
} {
21-
pgr := NewPager[int](item.PageNo, item.PageSize, item.TotalRecords)
21+
pgr := NewPager[uint64](item.PageNo, item.PageSize, item.TotalRecords)
2222

2323
pg := pgr.BuildPage()
2424
assert.NotNil(t, pg)
@@ -35,17 +35,16 @@ func TestPage(t *testing.T) {
3535

3636
func TestMustCalculateTotalPages(t *testing.T) {
3737
for _, item := range []struct {
38-
PageSize int
39-
TotalRecords int
40-
TotalPages int
38+
PageSize uint64
39+
TotalRecords uint64
40+
TotalPages uint64
4141
Panic bool
4242
}{
4343
{PageSize: 10, TotalRecords: 10, TotalPages: 1},
4444
{PageSize: 10, TotalRecords: 0, TotalPages: 0},
4545
{PageSize: 3, TotalRecords: 10, TotalPages: 4},
4646
{PageSize: 3, TotalRecords: 0, TotalPages: 0},
4747
{PageSize: 0, TotalRecords: 10, TotalPages: 0, Panic: true},
48-
{PageSize: 10, TotalRecords: -1, TotalPages: 0, Panic: true},
4948
} {
5049
if item.Panic {
5150
assert.Panics(t, func() {

0 commit comments

Comments
 (0)