Use dedicated type for each order field

Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
gearnode
2025-03-19 00:20:05 +01:00
parent c73e417e5c
commit 5a1f873d58
32 changed files with 518 additions and 119 deletions

View File

@@ -19,17 +19,17 @@ import (
)
type (
Cursor struct {
Cursor[T OrderField] struct {
Size int
Position Position
Key *CursorKey
OrderBy OrderBy
OrderBy OrderBy[T]
}
Position string
OrderBy struct {
Field OrderField
OrderBy[T OrderField] struct {
Field T
Direction OrderDirection
}
)
@@ -41,27 +41,20 @@ const (
Head Position = "HEAD"
)
func NewCursor(size int, from *CursorKey, pos Position, orderBy *OrderBy) *Cursor {
func NewCursor[T OrderField](size int, from *CursorKey, pos Position, orderBy OrderBy[T]) *Cursor[T] {
if size == 0 {
size = DefaultCursorSize
}
if orderBy == nil {
orderBy = &OrderBy{
Field: OrderFieldCreatedAt,
Direction: OrderDirectionDesc,
}
}
return &Cursor{
return &Cursor[T]{
Size: size,
Key: from,
Position: pos,
OrderBy: *orderBy,
OrderBy: orderBy,
}
}
func (c *Cursor) SQLFragment() string {
func (c *Cursor[T]) SQLFragment() string {
fieldName := c.OrderBy.Field.Column()
var orderDirection string
@@ -88,7 +81,7 @@ func (c *Cursor) SQLFragment() string {
return whereClause + " ORDER BY " + orderByClause + " LIMIT @cursor_limit"
}
func (c *Cursor) SQLArguments() pgx.NamedArgs {
func (c *Cursor[T]) SQLArguments() pgx.NamedArgs {
var size = c.Size
if c.Key == nil {
size += 1

View File

@@ -21,51 +21,6 @@ import (
type (
OrderField interface {
Column() string
fmt.Stringer
}
GenericOrderField string
)
const (
OrderFieldCreatedAt GenericOrderField = "CREATED_AT"
OrderFieldUpdatedAt GenericOrderField = "UPDATED_AT"
OrderFieldName GenericOrderField = "NAME"
)
func (of GenericOrderField) String() string {
return string(of)
}
func (of GenericOrderField) Column() string {
switch of {
case OrderFieldCreatedAt:
return "created_at"
case OrderFieldUpdatedAt:
return "updated_at"
case OrderFieldName:
return "name"
default:
return ""
}
}
func (of GenericOrderField) MarshalText() ([]byte, error) {
return []byte(of.String()), nil
}
func (of *GenericOrderField) UnmarshalText(data []byte) error {
val := string(data)
switch val {
case OrderFieldCreatedAt.String():
*of = OrderFieldCreatedAt
case OrderFieldUpdatedAt.String():
*of = OrderFieldUpdatedAt
case OrderFieldName.String():
*of = OrderFieldName
default:
return fmt.Errorf("invalid GenericOrderField value: %q", val)
}
return nil
}

View File

@@ -15,8 +15,8 @@
package page
type (
Paginable interface {
CursorKey(orderBy OrderField) CursorKey
Paginable[T OrderField] interface {
CursorKey(orderBy T) CursorKey
}
PageInfo struct {
@@ -24,14 +24,14 @@ type (
HasPrev bool
}
Page[T Paginable] struct {
Page[T Paginable[U], U OrderField] struct {
Info *PageInfo
Cursor *Cursor
Cursor *Cursor[U]
Data []T
}
)
func (p *Page[T]) First() T {
func (p *Page[T, U]) First() T {
if len(p.Data) == 0 {
var zero T
return zero
@@ -40,7 +40,7 @@ func (p *Page[T]) First() T {
return p.Data[0]
}
func (p *Page[T]) Last() T {
func (p *Page[T, U]) Last() T {
if len(p.Data) == 0 {
var zero T
return zero
@@ -49,11 +49,11 @@ func (p *Page[T]) Last() T {
return p.Data[len(p.Data)-1]
}
func NewPage[T Paginable](data []T, c *Cursor) *Page[T] {
func NewPage[T Paginable[U], U OrderField](data []T, c *Cursor[U]) *Page[T, U] {
pi := &PageInfo{}
if len(data) == 0 {
return &Page[T]{
return &Page[T, U]{
Info: pi,
Data: data,
}
@@ -109,7 +109,7 @@ func NewPage[T Paginable](data []T, c *Cursor) *Page[T] {
}
}
return &Page[T]{
return &Page[T, U]{
Info: pi,
Cursor: c,
Data: edges,