Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
github.com/jimlambrt/gorm-cursor-paginator/v2
A paginator doing cursor-based pagination based on GORM
This doc is for v2, which uses GORM v2. If you are using GORM v1, please checkout v1 doc.
column
tag supported.cursor
module for advanced usage.go get -u github.com/pilagod/gorm-cursor-paginator/v2
import (
"github.com/pilagod/gorm-cursor-paginator/v2/paginator"
)
Given an User
model for example:
type User struct {
ID int
JoinedAt time.Time `gorm:"column:created_at"`
}
We first need to create a paginator.Paginator
for User
, here are some useful patterns:
Configure by paginator.Option
, those functions with With
prefix are factories for paginator.Option
:
func CreateUserPaginator(
cursor paginator.Cursor,
order *paginator.Order,
limit *int,
) *paginator.Paginator {
opts := []paginator.Option{
&paginator.Config{
Keys: []string{"ID", "JoinedAt"},
Limit: 10,
Order: paginator.ASC,
},
}
if limit != nil {
opts = append(opts, paginator.WithLimit(*limit))
}
if order != nil {
opts = append(opts, paginator.WithOrder(*order))
}
if cursor.After != nil {
opts = append(opts, paginator.WithAfter(*cursor.After))
}
if cursor.Before != nil {
opts = append(opts, paginator.WithBefore(*cursor.Before))
}
return paginator.New(opts...)
}
Configure by setters on paginator.Paginator
:
func CreateUserPaginator(
cursor paginator.Cursor,
order *paginator.Order,
limit *int,
) *paginator.Paginator {
p := paginator.New(
&paginator.Config{
Keys: []string{"ID", "JoinedAt"},
Limit: 10,
Order: paginator.ASC,
},
)
if order != nil {
p.SetOrder(*order)
}
if limit != nil {
p.SetLimit(*limit)
}
if cursor.After != nil {
p.SetAfterCursor(*cursor.After)
}
if cursor.Before != nil {
p.SetBeforeCursor(*cursor.Before)
}
return p
}
Configure by paginator.Rule
for fine grained setting for each key:
Please refer to Specification for details of
paginator.Rule
.
func CreateUserPaginator(/* ... */) {
p := paginator.New(
&paginator.Config{
Rules: []paginator.Rule{
{
Key: "ID",
},
{
Key: "JoinedAt",
Order: paginator.DESC,
SQLRepr: "users.created_at",
NULLReplacement: "1970-01-01",
},
},
Limit: 10,
// Order here will apply to keys without order specified.
// In this example paginator will order by "ID" ASC, "JoinedAt" DESC.
Order: paginator.ASC,
},
)
// ...
return p
}
After knowing how to setup the paginator, we can start paginating User
with GORM:
func FindUsers(db *gorm.DB, query Query) ([]User, paginator.Cursor, error) {
var users []User
// extend query before paginating
stmt := db.
Select(/* fields */).
Joins(/* joins */).
Where(/* queries */)
// create paginator for User model
p := CreateUserPaginator(/* config */)
// find users with pagination
result, cursor, err := p.Paginate(stmt, &users)
// this is paginator error, e.g., invalid cursor
if err != nil {
return nil, paginator.Cursor{}, err
}
// this is gorm error
if result.Error != nil {
return nil, paginator.Cursor{}, result.Error
}
return users, cursor, nil
}
The second value returned from paginator.Paginator.Paginate
is a paginator.Cursor
struct, which is same as cursor.Cursor
struct:
type Cursor struct {
After *string `json:"after" query:"after"`
Before *string `json:"before" query:"before"`
}
That's all! Enjoy paginating in the GORM world. :tada:
For more paginating examples, please checkout exmaple/main.go and paginator/paginator_paginate_test.go
For manually encoding/decoding cursor exmaples, please checkout cursor/encoding_test.go
Default options used by paginator when not specified:
Keys
: []string{"ID"}
Limit
: 10
Order
: paginator.DESC
Key
: Field name in target model struct.
Order
: Order for this key only.
SQLRepr
: SQL representation used in raw SQL query.
This is especially useful when you have
JOIN
or table alias in your SQL query. IfSQLRepr
is not specified, paginator will get table name from model, plus table key derived by below rules to form the SQL query:
- Find GORM tag
column
on struct field.- If tag not found, convert struct field name to snake case.
SQLType
: SQL type used for type casting in the raw SQL query.
This is especially useful when working with custom types (e.g. JSON).
NULLReplacement
(v2.2.0): Replacement for NULL value when paginating by nullable column.
If you paginate by nullable column, you will encounter NULLS { FIRST | LAST } problems. This option let you decide how to order rows with NULL value. For instance, we can set this value to
1970-01-01
for a nullabledate
column, to ensure rows with NULL date will be placed at head when order is ASC, or at tail when order is DESC.
CustomType
: Extra information needed only when paginating across custom types (e.g. JSON). To support custom type pagination, the type needs to implement the CustomType
interface:
type CustomType interface {
// GetCustomTypeValue returns the value corresponding to the meta attribute inside the custom type.
GetCustomTypeValue(meta interface{}) (interface{}, error)
}
and provide the following information:
Meta
: meta attribute inside the custom type. The paginator will pass this meta attribute to the GetCustomTypeValue
function, which should return the actual value corresponding to the meta attribute. For JSON, meta would contain the JSON key of the element inside JSON to be used for pagination.Type
: GoLang type of the meta attribute.Also, when paginating across custom types, it is expected that the SQLRepr
& SQLType
are set. SQLRepr
should contain the SQL query to get the meta attribute value, while SQLType
should be used for type casting if needed.
CustomType
to paginator.Rule
to support custom data types, credit to @nikicc.There are some adjustments to the signatures of
cursor.NewEncoder
andcursor.NewDecoder
. Be careful when upgrading if you use them directly.
NULLReplacement
to paginator.Rule
to overcome NULLS { FIRST | LAST } problems, credit to @nikicc.© Cyan Ho (pilagod), 2018-NOW
Released under the MIT License
FAQs
Unknown package
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.