diff --git a/schema/ent/example/ent/pagination_query.go b/schema/ent/example/ent/pagination_query.go new file mode 100644 index 0000000..56787e2 --- /dev/null +++ b/schema/ent/example/ent/pagination_query.go @@ -0,0 +1,49 @@ +// Code generated by entc template, DO NOT EDIT. + +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" +) + +// PaginateAfterID paginates User by monotonically increasing "id". +// It preserves any existing filters/joins applied to the query, fetches up to "limit" items, +// and returns the next cursor (last ID of this page) and whether a next page exists. +func (q *UserQuery) PaginateAfterID(ctx context.Context, afterID, limit int) ([]*User, int, bool, error) { + if limit <= 0 { + limit = 20 + } + + qq := q.Clone(). + Order(func(s *sql.Selector) { + s.OrderBy(s.C("id")) + }). + Limit(limit + 1) // fetch one extra to detect "has next" + + if afterID > 0 { + qq = qq.Where(func(s *sql.Selector) { + s.Where(sql.GT(s.C("id"), afterID)) + }) + } + + rows, err := qq.All(ctx) + if err != nil { + return nil, 0, false, err + } + + hasNext := len(rows) > limit + if hasNext { + rows = rows[:limit] + } + + next := 0 + if len(rows) > 0 { + next = rows[len(rows)-1].ID + } + + return rows, next, hasNext, nil +} diff --git a/schema/ent/example/generate_schema.go b/schema/ent/example/generate_schema.go index 6df9d5b..006bb1a 100644 --- a/schema/ent/example/generate_schema.go +++ b/schema/ent/example/generate_schema.go @@ -9,7 +9,16 @@ import ( func main() { log.Println("ersteller start") - must(entc.Generate("./schema/ent/example/ent/schema", &gen.Config{})) + // Parse our custom pagination template (per-entity Query methods). + paginationPath := "schema/ent/pagination_query.tmpl" + //paginationTmpl := gen.MustParse(gen.NewTemplate("pagination_query"). + // ParseFiles(paginationPath)) + + must(entc.Generate( + "./schema/ent/example/ent/schema", + &gen.Config{}, + entc.TemplateFiles(paginationPath), + )) } func must(err error) { diff --git a/schema/ent/example/start.go b/schema/ent/example/start.go index b83c764..f3ce74e 100644 --- a/schema/ent/example/start.go +++ b/schema/ent/example/start.go @@ -3,11 +3,9 @@ package main import ( "context" "ersteller-lib/schema/ent/example/ent" - "ersteller-lib/schema/ent/example/ent/user" "log" "time" - "entgo.io/ent/dialect/sql" _ "github.com/mattn/go-sqlite3" ) @@ -40,7 +38,8 @@ func main() { // log.Fatalf("failed updating user: %w", err) //}j //log.Println("user was updated", u) - users, nextId, hasNext, err := ListUsersAfterID(ctx, client, 0, 2) + query := client.User.Query() + users, nextId, hasNext, err := query.PaginateAfterID(ctx, 0, 2) if err != nil { log.Fatalf("failed listing users: %w", err) } @@ -50,7 +49,7 @@ func main() { log.Println("user", u.ID, u.Email, u.Password) } } - users, nextId, hasNext, err = ListUsersAfterID(ctx, client, nextId, 2) + users, nextId, hasNext, err = query.PaginateAfterID(ctx, nextId, 2) if err != nil { log.Fatalf("failed listing users: %w", err) } @@ -62,31 +61,3 @@ func main() { } } - -// afterID is the last ID from the previous page. Use 0 for the first page. -func ListUsersAfterID(ctx context.Context, client *ent.Client, afterID, limit int) ([]*ent.User, int, bool, error) { - q := client.User.Query(). - Order(user.ByID(sql.OrderAsc())). - Limit(limit + 1) // fetch one extra to detect "has next" - - if afterID > 0 { - q = q.Where(user.IDGT(afterID)) - } - - rows, err := q.All(ctx) - if err != nil { - return nil, -1, false, err - } - - hasNext := len(rows) > limit - if hasNext { - rows = rows[:limit] - } - - var next int - if len(rows) > 0 { - last := rows[len(rows)-1].ID - next = last - } - return rows, next, hasNext, nil -} diff --git a/schema/ent/pagination_query.tmpl b/schema/ent/pagination_query.tmpl new file mode 100644 index 0000000..aba8daf --- /dev/null +++ b/schema/ent/pagination_query.tmpl @@ -0,0 +1,52 @@ +{{ define "pagination_query" }} +// Code generated by entc template, DO NOT EDIT. + +{{/* A template that adds the functionality for running each client in debug mode */}} + +{{/* Add the base header for the generated file */}} +{{ $pkg := base $.Config.Package }} +{{ template "header" $ }} + +{{ range $n := $.Nodes }} + +// PaginateAfterID paginates {{ $n.Name }} by monotonically increasing "id". +// It preserves any existing filters/joins applied to the query, fetches up to "limit" items, +// and returns the next cursor (last ID of this page) and whether a next page exists. +func (q *{{ $n.Name }}Query) PaginateAfterID(ctx context.Context, afterID, limit int) ([]*{{ $n.Name }}, int, bool, error) { + if limit <= 0 { + limit = 20 + } + + qq := q.Clone(). + Order(func(s *sql.Selector) { + s.OrderBy(s.C("id")) + }). + Limit(limit + 1) // fetch one extra to detect "has next" + + if afterID > 0 { + qq = qq.Where(func(s *sql.Selector) { + s.Where(sql.GT(s.C("id"), afterID)) + }) + } + + rows, err := qq.All(ctx) + if err != nil { + return nil, 0, false, err + } + + hasNext := len(rows) > limit + if hasNext { + rows = rows[:limit] + } + + next := 0 + if len(rows) > 0 { + next = rows[len(rows)-1].ID + } + + return rows, next, hasNext, nil +} + +{{ end }} + +{{ end }} \ No newline at end of file