ka/ent/gql_pagination.go

1127 lines
30 KiB
Go
Raw Normal View History

2024-10-04 20:22:25 +02:00
// Code generated by ent, DO NOT EDIT.
package ent
import (
"context"
"errors"
"fmt"
"io"
"strconv"
"code.icod.de/dalu/ka/ent/category"
"code.icod.de/dalu/ka/ent/post"
"code.icod.de/dalu/ka/ent/profile"
"entgo.io/contrib/entgql"
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/errcode"
"github.com/google/uuid"
"github.com/vektah/gqlparser/v2/gqlerror"
)
// Common entgql types.
type (
Cursor = entgql.Cursor[uuid.UUID]
PageInfo = entgql.PageInfo[uuid.UUID]
OrderDirection = entgql.OrderDirection
)
func orderFunc(o OrderDirection, field string) func(*sql.Selector) {
if o == entgql.OrderDirectionDesc {
return Desc(field)
}
return Asc(field)
}
const errInvalidPagination = "INVALID_PAGINATION"
func validateFirstLast(first, last *int) (err *gqlerror.Error) {
switch {
case first != nil && last != nil:
err = &gqlerror.Error{
Message: "Passing both `first` and `last` to paginate a connection is not supported.",
}
case first != nil && *first < 0:
err = &gqlerror.Error{
Message: "`first` on a connection cannot be less than zero.",
}
errcode.Set(err, errInvalidPagination)
case last != nil && *last < 0:
err = &gqlerror.Error{
Message: "`last` on a connection cannot be less than zero.",
}
errcode.Set(err, errInvalidPagination)
}
return err
}
func collectedField(ctx context.Context, path ...string) *graphql.CollectedField {
fc := graphql.GetFieldContext(ctx)
if fc == nil {
return nil
}
field := fc.Field
oc := graphql.GetOperationContext(ctx)
walk:
for _, name := range path {
for _, f := range graphql.CollectFields(oc, field.Selections, nil) {
if f.Alias == name {
field = f
continue walk
}
}
return nil
}
return &field
}
func hasCollectedField(ctx context.Context, path ...string) bool {
if graphql.GetFieldContext(ctx) == nil {
return true
}
return collectedField(ctx, path...) != nil
}
const (
edgesField = "edges"
nodeField = "node"
pageInfoField = "pageInfo"
totalCountField = "totalCount"
)
func paginateLimit(first, last *int) int {
var limit int
if first != nil {
limit = *first + 1
} else if last != nil {
limit = *last + 1
}
return limit
}
// CategoryEdge is the edge representation of Category.
type CategoryEdge struct {
Node *Category `json:"node"`
Cursor Cursor `json:"cursor"`
}
// CategoryConnection is the connection containing edges to Category.
type CategoryConnection struct {
Edges []*CategoryEdge `json:"edges"`
PageInfo PageInfo `json:"pageInfo"`
TotalCount int `json:"totalCount"`
}
func (c *CategoryConnection) build(nodes []*Category, pager *categoryPager, after *Cursor, first *int, before *Cursor, last *int) {
c.PageInfo.HasNextPage = before != nil
c.PageInfo.HasPreviousPage = after != nil
if first != nil && *first+1 == len(nodes) {
c.PageInfo.HasNextPage = true
nodes = nodes[:len(nodes)-1]
} else if last != nil && *last+1 == len(nodes) {
c.PageInfo.HasPreviousPage = true
nodes = nodes[:len(nodes)-1]
}
var nodeAt func(int) *Category
if last != nil {
n := len(nodes) - 1
nodeAt = func(i int) *Category {
return nodes[n-i]
}
} else {
nodeAt = func(i int) *Category {
return nodes[i]
}
}
c.Edges = make([]*CategoryEdge, len(nodes))
for i := range nodes {
node := nodeAt(i)
c.Edges[i] = &CategoryEdge{
Node: node,
Cursor: pager.toCursor(node),
}
}
if l := len(c.Edges); l > 0 {
c.PageInfo.StartCursor = &c.Edges[0].Cursor
c.PageInfo.EndCursor = &c.Edges[l-1].Cursor
}
if c.TotalCount == 0 {
c.TotalCount = len(nodes)
}
}
// CategoryPaginateOption enables pagination customization.
type CategoryPaginateOption func(*categoryPager) error
// WithCategoryOrder configures pagination ordering.
func WithCategoryOrder(order *CategoryOrder) CategoryPaginateOption {
if order == nil {
order = DefaultCategoryOrder
}
o := *order
return func(pager *categoryPager) error {
if err := o.Direction.Validate(); err != nil {
return err
}
if o.Field == nil {
o.Field = DefaultCategoryOrder.Field
}
pager.order = &o
return nil
}
}
// WithCategoryFilter configures pagination filter.
func WithCategoryFilter(filter func(*CategoryQuery) (*CategoryQuery, error)) CategoryPaginateOption {
return func(pager *categoryPager) error {
if filter == nil {
return errors.New("CategoryQuery filter cannot be nil")
}
pager.filter = filter
return nil
}
}
type categoryPager struct {
reverse bool
order *CategoryOrder
filter func(*CategoryQuery) (*CategoryQuery, error)
}
func newCategoryPager(opts []CategoryPaginateOption, reverse bool) (*categoryPager, error) {
pager := &categoryPager{reverse: reverse}
for _, opt := range opts {
if err := opt(pager); err != nil {
return nil, err
}
}
if pager.order == nil {
pager.order = DefaultCategoryOrder
}
return pager, nil
}
func (p *categoryPager) applyFilter(query *CategoryQuery) (*CategoryQuery, error) {
if p.filter != nil {
return p.filter(query)
}
return query, nil
}
func (p *categoryPager) toCursor(c *Category) Cursor {
return p.order.Field.toCursor(c)
}
func (p *categoryPager) applyCursors(query *CategoryQuery, after, before *Cursor) (*CategoryQuery, error) {
direction := p.order.Direction
if p.reverse {
direction = direction.Reverse()
}
for _, predicate := range entgql.CursorsPredicate(after, before, DefaultCategoryOrder.Field.column, p.order.Field.column, direction) {
query = query.Where(predicate)
}
return query, nil
}
func (p *categoryPager) applyOrder(query *CategoryQuery) *CategoryQuery {
direction := p.order.Direction
if p.reverse {
direction = direction.Reverse()
}
query = query.Order(p.order.Field.toTerm(direction.OrderTermOption()))
if p.order.Field != DefaultCategoryOrder.Field {
query = query.Order(DefaultCategoryOrder.Field.toTerm(direction.OrderTermOption()))
}
switch p.order.Field.column {
case CategoryOrderFieldPostsCount.column:
default:
if len(query.ctx.Fields) > 0 {
query.ctx.AppendFieldOnce(p.order.Field.column)
}
}
return query
}
func (p *categoryPager) orderExpr(query *CategoryQuery) sql.Querier {
direction := p.order.Direction
if p.reverse {
direction = direction.Reverse()
}
switch p.order.Field.column {
case CategoryOrderFieldPostsCount.column:
query = query.Order(p.order.Field.toTerm(direction.OrderTermOption()))
default:
if len(query.ctx.Fields) > 0 {
query.ctx.AppendFieldOnce(p.order.Field.column)
}
}
return sql.ExprFunc(func(b *sql.Builder) {
b.Ident(p.order.Field.column).Pad().WriteString(string(direction))
if p.order.Field != DefaultCategoryOrder.Field {
b.Comma().Ident(DefaultCategoryOrder.Field.column).Pad().WriteString(string(direction))
}
})
}
// Paginate executes the query and returns a relay based cursor connection to Category.
func (c *CategoryQuery) Paginate(
ctx context.Context, after *Cursor, first *int,
before *Cursor, last *int, opts ...CategoryPaginateOption,
) (*CategoryConnection, error) {
if err := validateFirstLast(first, last); err != nil {
return nil, err
}
pager, err := newCategoryPager(opts, last != nil)
if err != nil {
return nil, err
}
if c, err = pager.applyFilter(c); err != nil {
return nil, err
}
conn := &CategoryConnection{Edges: []*CategoryEdge{}}
ignoredEdges := !hasCollectedField(ctx, edgesField)
if hasCollectedField(ctx, totalCountField) || hasCollectedField(ctx, pageInfoField) {
hasPagination := after != nil || first != nil || before != nil || last != nil
if hasPagination || ignoredEdges {
c := c.Clone()
c.ctx.Fields = nil
if conn.TotalCount, err = c.Count(ctx); err != nil {
return nil, err
}
conn.PageInfo.HasNextPage = first != nil && conn.TotalCount > 0
conn.PageInfo.HasPreviousPage = last != nil && conn.TotalCount > 0
}
}
if ignoredEdges || (first != nil && *first == 0) || (last != nil && *last == 0) {
return conn, nil
}
if c, err = pager.applyCursors(c, after, before); err != nil {
return nil, err
}
limit := paginateLimit(first, last)
if limit != 0 {
c.Limit(limit)
}
if field := collectedField(ctx, edgesField, nodeField); field != nil {
if err := c.collectField(ctx, limit == 1, graphql.GetOperationContext(ctx), *field, []string{edgesField, nodeField}); err != nil {
return nil, err
}
}
c = pager.applyOrder(c)
nodes, err := c.All(ctx)
if err != nil {
return nil, err
}
conn.build(nodes, pager, after, first, before, last)
return conn, nil
}
var (
// CategoryOrderFieldCreatedAt orders Category by created_at.
CategoryOrderFieldCreatedAt = &CategoryOrderField{
Value: func(c *Category) (ent.Value, error) {
return c.CreatedAt, nil
},
column: category.FieldCreatedAt,
toTerm: category.ByCreatedAt,
toCursor: func(c *Category) Cursor {
return Cursor{
ID: c.ID,
Value: c.CreatedAt,
}
},
}
// CategoryOrderFieldUpdatedAt orders Category by updated_at.
CategoryOrderFieldUpdatedAt = &CategoryOrderField{
Value: func(c *Category) (ent.Value, error) {
return c.UpdatedAt, nil
},
column: category.FieldUpdatedAt,
toTerm: category.ByUpdatedAt,
toCursor: func(c *Category) Cursor {
return Cursor{
ID: c.ID,
Value: c.UpdatedAt,
}
},
}
// CategoryOrderFieldPostsCount orders by POSTS_COUNT.
CategoryOrderFieldPostsCount = &CategoryOrderField{
Value: func(c *Category) (ent.Value, error) {
return c.Value("posts_count")
},
column: "posts_count",
toTerm: func(opts ...sql.OrderTermOption) category.OrderOption {
return category.ByPostsCount(
append(opts, sql.OrderSelectAs("posts_count"))...,
)
},
toCursor: func(c *Category) Cursor {
cv, _ := c.Value("posts_count")
return Cursor{
ID: c.ID,
Value: cv,
}
},
}
)
// String implement fmt.Stringer interface.
func (f CategoryOrderField) String() string {
var str string
switch f.column {
case CategoryOrderFieldCreatedAt.column:
str = "CREATED_AT"
case CategoryOrderFieldUpdatedAt.column:
str = "UPDATED_AT"
case CategoryOrderFieldPostsCount.column:
str = "POSTS_COUNT"
}
return str
}
// MarshalGQL implements graphql.Marshaler interface.
func (f CategoryOrderField) MarshalGQL(w io.Writer) {
io.WriteString(w, strconv.Quote(f.String()))
}
// UnmarshalGQL implements graphql.Unmarshaler interface.
func (f *CategoryOrderField) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("CategoryOrderField %T must be a string", v)
}
switch str {
case "CREATED_AT":
*f = *CategoryOrderFieldCreatedAt
case "UPDATED_AT":
*f = *CategoryOrderFieldUpdatedAt
case "POSTS_COUNT":
*f = *CategoryOrderFieldPostsCount
default:
return fmt.Errorf("%s is not a valid CategoryOrderField", str)
}
return nil
}
// CategoryOrderField defines the ordering field of Category.
type CategoryOrderField struct {
// Value extracts the ordering value from the given Category.
Value func(*Category) (ent.Value, error)
column string // field or computed.
toTerm func(...sql.OrderTermOption) category.OrderOption
toCursor func(*Category) Cursor
}
// CategoryOrder defines the ordering of Category.
type CategoryOrder struct {
Direction OrderDirection `json:"direction"`
Field *CategoryOrderField `json:"field"`
}
// DefaultCategoryOrder is the default ordering of Category.
var DefaultCategoryOrder = &CategoryOrder{
Direction: entgql.OrderDirectionAsc,
Field: &CategoryOrderField{
Value: func(c *Category) (ent.Value, error) {
return c.ID, nil
},
column: category.FieldID,
toTerm: category.ByID,
toCursor: func(c *Category) Cursor {
return Cursor{ID: c.ID}
},
},
}
// ToEdge converts Category into CategoryEdge.
func (c *Category) ToEdge(order *CategoryOrder) *CategoryEdge {
if order == nil {
order = DefaultCategoryOrder
}
return &CategoryEdge{
Node: c,
Cursor: order.Field.toCursor(c),
}
}
// PostEdge is the edge representation of Post.
type PostEdge struct {
Node *Post `json:"node"`
Cursor Cursor `json:"cursor"`
}
// PostConnection is the connection containing edges to Post.
type PostConnection struct {
Edges []*PostEdge `json:"edges"`
PageInfo PageInfo `json:"pageInfo"`
TotalCount int `json:"totalCount"`
}
func (c *PostConnection) build(nodes []*Post, pager *postPager, after *Cursor, first *int, before *Cursor, last *int) {
c.PageInfo.HasNextPage = before != nil
c.PageInfo.HasPreviousPage = after != nil
if first != nil && *first+1 == len(nodes) {
c.PageInfo.HasNextPage = true
nodes = nodes[:len(nodes)-1]
} else if last != nil && *last+1 == len(nodes) {
c.PageInfo.HasPreviousPage = true
nodes = nodes[:len(nodes)-1]
}
var nodeAt func(int) *Post
if last != nil {
n := len(nodes) - 1
nodeAt = func(i int) *Post {
return nodes[n-i]
}
} else {
nodeAt = func(i int) *Post {
return nodes[i]
}
}
c.Edges = make([]*PostEdge, len(nodes))
for i := range nodes {
node := nodeAt(i)
c.Edges[i] = &PostEdge{
Node: node,
Cursor: pager.toCursor(node),
}
}
if l := len(c.Edges); l > 0 {
c.PageInfo.StartCursor = &c.Edges[0].Cursor
c.PageInfo.EndCursor = &c.Edges[l-1].Cursor
}
if c.TotalCount == 0 {
c.TotalCount = len(nodes)
}
}
// PostPaginateOption enables pagination customization.
type PostPaginateOption func(*postPager) error
// WithPostOrder configures pagination ordering.
func WithPostOrder(order *PostOrder) PostPaginateOption {
if order == nil {
order = DefaultPostOrder
}
o := *order
return func(pager *postPager) error {
if err := o.Direction.Validate(); err != nil {
return err
}
if o.Field == nil {
o.Field = DefaultPostOrder.Field
}
pager.order = &o
return nil
}
}
// WithPostFilter configures pagination filter.
func WithPostFilter(filter func(*PostQuery) (*PostQuery, error)) PostPaginateOption {
return func(pager *postPager) error {
if filter == nil {
return errors.New("PostQuery filter cannot be nil")
}
pager.filter = filter
return nil
}
}
type postPager struct {
reverse bool
order *PostOrder
filter func(*PostQuery) (*PostQuery, error)
}
func newPostPager(opts []PostPaginateOption, reverse bool) (*postPager, error) {
pager := &postPager{reverse: reverse}
for _, opt := range opts {
if err := opt(pager); err != nil {
return nil, err
}
}
if pager.order == nil {
pager.order = DefaultPostOrder
}
return pager, nil
}
func (p *postPager) applyFilter(query *PostQuery) (*PostQuery, error) {
if p.filter != nil {
return p.filter(query)
}
return query, nil
}
func (p *postPager) toCursor(po *Post) Cursor {
return p.order.Field.toCursor(po)
}
func (p *postPager) applyCursors(query *PostQuery, after, before *Cursor) (*PostQuery, error) {
direction := p.order.Direction
if p.reverse {
direction = direction.Reverse()
}
for _, predicate := range entgql.CursorsPredicate(after, before, DefaultPostOrder.Field.column, p.order.Field.column, direction) {
query = query.Where(predicate)
}
return query, nil
}
func (p *postPager) applyOrder(query *PostQuery) *PostQuery {
direction := p.order.Direction
if p.reverse {
direction = direction.Reverse()
}
query = query.Order(p.order.Field.toTerm(direction.OrderTermOption()))
if p.order.Field != DefaultPostOrder.Field {
query = query.Order(DefaultPostOrder.Field.toTerm(direction.OrderTermOption()))
}
if len(query.ctx.Fields) > 0 {
query.ctx.AppendFieldOnce(p.order.Field.column)
}
return query
}
func (p *postPager) orderExpr(query *PostQuery) sql.Querier {
direction := p.order.Direction
if p.reverse {
direction = direction.Reverse()
}
if len(query.ctx.Fields) > 0 {
query.ctx.AppendFieldOnce(p.order.Field.column)
}
return sql.ExprFunc(func(b *sql.Builder) {
b.Ident(p.order.Field.column).Pad().WriteString(string(direction))
if p.order.Field != DefaultPostOrder.Field {
b.Comma().Ident(DefaultPostOrder.Field.column).Pad().WriteString(string(direction))
}
})
}
// Paginate executes the query and returns a relay based cursor connection to Post.
func (po *PostQuery) Paginate(
ctx context.Context, after *Cursor, first *int,
before *Cursor, last *int, opts ...PostPaginateOption,
) (*PostConnection, error) {
if err := validateFirstLast(first, last); err != nil {
return nil, err
}
pager, err := newPostPager(opts, last != nil)
if err != nil {
return nil, err
}
if po, err = pager.applyFilter(po); err != nil {
return nil, err
}
conn := &PostConnection{Edges: []*PostEdge{}}
ignoredEdges := !hasCollectedField(ctx, edgesField)
if hasCollectedField(ctx, totalCountField) || hasCollectedField(ctx, pageInfoField) {
hasPagination := after != nil || first != nil || before != nil || last != nil
if hasPagination || ignoredEdges {
c := po.Clone()
c.ctx.Fields = nil
if conn.TotalCount, err = c.Count(ctx); err != nil {
return nil, err
}
conn.PageInfo.HasNextPage = first != nil && conn.TotalCount > 0
conn.PageInfo.HasPreviousPage = last != nil && conn.TotalCount > 0
}
}
if ignoredEdges || (first != nil && *first == 0) || (last != nil && *last == 0) {
return conn, nil
}
if po, err = pager.applyCursors(po, after, before); err != nil {
return nil, err
}
limit := paginateLimit(first, last)
if limit != 0 {
po.Limit(limit)
}
if field := collectedField(ctx, edgesField, nodeField); field != nil {
if err := po.collectField(ctx, limit == 1, graphql.GetOperationContext(ctx), *field, []string{edgesField, nodeField}); err != nil {
return nil, err
}
}
po = pager.applyOrder(po)
nodes, err := po.All(ctx)
if err != nil {
return nil, err
}
conn.build(nodes, pager, after, first, before, last)
return conn, nil
}
var (
// PostOrderFieldCreatedAt orders Post by created_at.
PostOrderFieldCreatedAt = &PostOrderField{
Value: func(po *Post) (ent.Value, error) {
return po.CreatedAt, nil
},
column: post.FieldCreatedAt,
toTerm: post.ByCreatedAt,
toCursor: func(po *Post) Cursor {
return Cursor{
ID: po.ID,
Value: po.CreatedAt,
}
},
}
// PostOrderFieldUpdatedAt orders Post by updated_at.
PostOrderFieldUpdatedAt = &PostOrderField{
Value: func(po *Post) (ent.Value, error) {
return po.UpdatedAt, nil
},
column: post.FieldUpdatedAt,
toTerm: post.ByUpdatedAt,
toCursor: func(po *Post) Cursor {
return Cursor{
ID: po.ID,
Value: po.UpdatedAt,
}
},
}
// PostOrderFieldExpireTime orders Post by expire_time.
PostOrderFieldExpireTime = &PostOrderField{
Value: func(po *Post) (ent.Value, error) {
return po.ExpireTime, nil
},
column: post.FieldExpireTime,
toTerm: post.ByExpireTime,
toCursor: func(po *Post) Cursor {
return Cursor{
ID: po.ID,
Value: po.ExpireTime,
}
},
}
)
// String implement fmt.Stringer interface.
func (f PostOrderField) String() string {
var str string
switch f.column {
case PostOrderFieldCreatedAt.column:
str = "CREATED_AT"
case PostOrderFieldUpdatedAt.column:
str = "UPDATED_AT"
case PostOrderFieldExpireTime.column:
str = "EXPIRE_TIME"
}
return str
}
// MarshalGQL implements graphql.Marshaler interface.
func (f PostOrderField) MarshalGQL(w io.Writer) {
io.WriteString(w, strconv.Quote(f.String()))
}
// UnmarshalGQL implements graphql.Unmarshaler interface.
func (f *PostOrderField) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("PostOrderField %T must be a string", v)
}
switch str {
case "CREATED_AT":
*f = *PostOrderFieldCreatedAt
case "UPDATED_AT":
*f = *PostOrderFieldUpdatedAt
case "EXPIRE_TIME":
*f = *PostOrderFieldExpireTime
default:
return fmt.Errorf("%s is not a valid PostOrderField", str)
}
return nil
}
// PostOrderField defines the ordering field of Post.
type PostOrderField struct {
// Value extracts the ordering value from the given Post.
Value func(*Post) (ent.Value, error)
column string // field or computed.
toTerm func(...sql.OrderTermOption) post.OrderOption
toCursor func(*Post) Cursor
}
// PostOrder defines the ordering of Post.
type PostOrder struct {
Direction OrderDirection `json:"direction"`
Field *PostOrderField `json:"field"`
}
// DefaultPostOrder is the default ordering of Post.
var DefaultPostOrder = &PostOrder{
Direction: entgql.OrderDirectionAsc,
Field: &PostOrderField{
Value: func(po *Post) (ent.Value, error) {
return po.ID, nil
},
column: post.FieldID,
toTerm: post.ByID,
toCursor: func(po *Post) Cursor {
return Cursor{ID: po.ID}
},
},
}
// ToEdge converts Post into PostEdge.
func (po *Post) ToEdge(order *PostOrder) *PostEdge {
if order == nil {
order = DefaultPostOrder
}
return &PostEdge{
Node: po,
Cursor: order.Field.toCursor(po),
}
}
// ProfileEdge is the edge representation of Profile.
type ProfileEdge struct {
Node *Profile `json:"node"`
Cursor Cursor `json:"cursor"`
}
// ProfileConnection is the connection containing edges to Profile.
type ProfileConnection struct {
Edges []*ProfileEdge `json:"edges"`
PageInfo PageInfo `json:"pageInfo"`
TotalCount int `json:"totalCount"`
}
func (c *ProfileConnection) build(nodes []*Profile, pager *profilePager, after *Cursor, first *int, before *Cursor, last *int) {
c.PageInfo.HasNextPage = before != nil
c.PageInfo.HasPreviousPage = after != nil
if first != nil && *first+1 == len(nodes) {
c.PageInfo.HasNextPage = true
nodes = nodes[:len(nodes)-1]
} else if last != nil && *last+1 == len(nodes) {
c.PageInfo.HasPreviousPage = true
nodes = nodes[:len(nodes)-1]
}
var nodeAt func(int) *Profile
if last != nil {
n := len(nodes) - 1
nodeAt = func(i int) *Profile {
return nodes[n-i]
}
} else {
nodeAt = func(i int) *Profile {
return nodes[i]
}
}
c.Edges = make([]*ProfileEdge, len(nodes))
for i := range nodes {
node := nodeAt(i)
c.Edges[i] = &ProfileEdge{
Node: node,
Cursor: pager.toCursor(node),
}
}
if l := len(c.Edges); l > 0 {
c.PageInfo.StartCursor = &c.Edges[0].Cursor
c.PageInfo.EndCursor = &c.Edges[l-1].Cursor
}
if c.TotalCount == 0 {
c.TotalCount = len(nodes)
}
}
// ProfilePaginateOption enables pagination customization.
type ProfilePaginateOption func(*profilePager) error
// WithProfileOrder configures pagination ordering.
func WithProfileOrder(order *ProfileOrder) ProfilePaginateOption {
if order == nil {
order = DefaultProfileOrder
}
o := *order
return func(pager *profilePager) error {
if err := o.Direction.Validate(); err != nil {
return err
}
if o.Field == nil {
o.Field = DefaultProfileOrder.Field
}
pager.order = &o
return nil
}
}
// WithProfileFilter configures pagination filter.
func WithProfileFilter(filter func(*ProfileQuery) (*ProfileQuery, error)) ProfilePaginateOption {
return func(pager *profilePager) error {
if filter == nil {
return errors.New("ProfileQuery filter cannot be nil")
}
pager.filter = filter
return nil
}
}
type profilePager struct {
reverse bool
order *ProfileOrder
filter func(*ProfileQuery) (*ProfileQuery, error)
}
func newProfilePager(opts []ProfilePaginateOption, reverse bool) (*profilePager, error) {
pager := &profilePager{reverse: reverse}
for _, opt := range opts {
if err := opt(pager); err != nil {
return nil, err
}
}
if pager.order == nil {
pager.order = DefaultProfileOrder
}
return pager, nil
}
func (p *profilePager) applyFilter(query *ProfileQuery) (*ProfileQuery, error) {
if p.filter != nil {
return p.filter(query)
}
return query, nil
}
func (p *profilePager) toCursor(pr *Profile) Cursor {
return p.order.Field.toCursor(pr)
}
func (p *profilePager) applyCursors(query *ProfileQuery, after, before *Cursor) (*ProfileQuery, error) {
direction := p.order.Direction
if p.reverse {
direction = direction.Reverse()
}
for _, predicate := range entgql.CursorsPredicate(after, before, DefaultProfileOrder.Field.column, p.order.Field.column, direction) {
query = query.Where(predicate)
}
return query, nil
}
func (p *profilePager) applyOrder(query *ProfileQuery) *ProfileQuery {
direction := p.order.Direction
if p.reverse {
direction = direction.Reverse()
}
query = query.Order(p.order.Field.toTerm(direction.OrderTermOption()))
if p.order.Field != DefaultProfileOrder.Field {
query = query.Order(DefaultProfileOrder.Field.toTerm(direction.OrderTermOption()))
}
switch p.order.Field.column {
case ProfileOrderFieldPostsCount.column:
default:
if len(query.ctx.Fields) > 0 {
query.ctx.AppendFieldOnce(p.order.Field.column)
}
}
return query
}
func (p *profilePager) orderExpr(query *ProfileQuery) sql.Querier {
direction := p.order.Direction
if p.reverse {
direction = direction.Reverse()
}
switch p.order.Field.column {
case ProfileOrderFieldPostsCount.column:
query = query.Order(p.order.Field.toTerm(direction.OrderTermOption()))
default:
if len(query.ctx.Fields) > 0 {
query.ctx.AppendFieldOnce(p.order.Field.column)
}
}
return sql.ExprFunc(func(b *sql.Builder) {
b.Ident(p.order.Field.column).Pad().WriteString(string(direction))
if p.order.Field != DefaultProfileOrder.Field {
b.Comma().Ident(DefaultProfileOrder.Field.column).Pad().WriteString(string(direction))
}
})
}
// Paginate executes the query and returns a relay based cursor connection to Profile.
func (pr *ProfileQuery) Paginate(
ctx context.Context, after *Cursor, first *int,
before *Cursor, last *int, opts ...ProfilePaginateOption,
) (*ProfileConnection, error) {
if err := validateFirstLast(first, last); err != nil {
return nil, err
}
pager, err := newProfilePager(opts, last != nil)
if err != nil {
return nil, err
}
if pr, err = pager.applyFilter(pr); err != nil {
return nil, err
}
conn := &ProfileConnection{Edges: []*ProfileEdge{}}
ignoredEdges := !hasCollectedField(ctx, edgesField)
if hasCollectedField(ctx, totalCountField) || hasCollectedField(ctx, pageInfoField) {
hasPagination := after != nil || first != nil || before != nil || last != nil
if hasPagination || ignoredEdges {
c := pr.Clone()
c.ctx.Fields = nil
if conn.TotalCount, err = c.Count(ctx); err != nil {
return nil, err
}
conn.PageInfo.HasNextPage = first != nil && conn.TotalCount > 0
conn.PageInfo.HasPreviousPage = last != nil && conn.TotalCount > 0
}
}
if ignoredEdges || (first != nil && *first == 0) || (last != nil && *last == 0) {
return conn, nil
}
if pr, err = pager.applyCursors(pr, after, before); err != nil {
return nil, err
}
limit := paginateLimit(first, last)
if limit != 0 {
pr.Limit(limit)
}
if field := collectedField(ctx, edgesField, nodeField); field != nil {
if err := pr.collectField(ctx, limit == 1, graphql.GetOperationContext(ctx), *field, []string{edgesField, nodeField}); err != nil {
return nil, err
}
}
pr = pager.applyOrder(pr)
nodes, err := pr.All(ctx)
if err != nil {
return nil, err
}
conn.build(nodes, pager, after, first, before, last)
return conn, nil
}
var (
// ProfileOrderFieldCreatedAt orders Profile by created_at.
ProfileOrderFieldCreatedAt = &ProfileOrderField{
Value: func(pr *Profile) (ent.Value, error) {
return pr.CreatedAt, nil
},
column: profile.FieldCreatedAt,
toTerm: profile.ByCreatedAt,
toCursor: func(pr *Profile) Cursor {
return Cursor{
ID: pr.ID,
Value: pr.CreatedAt,
}
},
}
// ProfileOrderFieldUpdatedAt orders Profile by updated_at.
ProfileOrderFieldUpdatedAt = &ProfileOrderField{
Value: func(pr *Profile) (ent.Value, error) {
return pr.UpdatedAt, nil
},
column: profile.FieldUpdatedAt,
toTerm: profile.ByUpdatedAt,
toCursor: func(pr *Profile) Cursor {
return Cursor{
ID: pr.ID,
Value: pr.UpdatedAt,
}
},
}
// ProfileOrderFieldPostsCount orders by POSTS_COUNT.
ProfileOrderFieldPostsCount = &ProfileOrderField{
Value: func(pr *Profile) (ent.Value, error) {
return pr.Value("posts_count")
},
column: "posts_count",
toTerm: func(opts ...sql.OrderTermOption) profile.OrderOption {
return profile.ByPostsCount(
append(opts, sql.OrderSelectAs("posts_count"))...,
)
},
toCursor: func(pr *Profile) Cursor {
cv, _ := pr.Value("posts_count")
return Cursor{
ID: pr.ID,
Value: cv,
}
},
}
)
// String implement fmt.Stringer interface.
func (f ProfileOrderField) String() string {
var str string
switch f.column {
case ProfileOrderFieldCreatedAt.column:
str = "CREATED_AT"
case ProfileOrderFieldUpdatedAt.column:
str = "UPDATED_AT"
case ProfileOrderFieldPostsCount.column:
str = "POSTS_COUNT"
}
return str
}
// MarshalGQL implements graphql.Marshaler interface.
func (f ProfileOrderField) MarshalGQL(w io.Writer) {
io.WriteString(w, strconv.Quote(f.String()))
}
// UnmarshalGQL implements graphql.Unmarshaler interface.
func (f *ProfileOrderField) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("ProfileOrderField %T must be a string", v)
}
switch str {
case "CREATED_AT":
*f = *ProfileOrderFieldCreatedAt
case "UPDATED_AT":
*f = *ProfileOrderFieldUpdatedAt
case "POSTS_COUNT":
*f = *ProfileOrderFieldPostsCount
default:
return fmt.Errorf("%s is not a valid ProfileOrderField", str)
}
return nil
}
// ProfileOrderField defines the ordering field of Profile.
type ProfileOrderField struct {
// Value extracts the ordering value from the given Profile.
Value func(*Profile) (ent.Value, error)
column string // field or computed.
toTerm func(...sql.OrderTermOption) profile.OrderOption
toCursor func(*Profile) Cursor
}
// ProfileOrder defines the ordering of Profile.
type ProfileOrder struct {
Direction OrderDirection `json:"direction"`
Field *ProfileOrderField `json:"field"`
}
// DefaultProfileOrder is the default ordering of Profile.
var DefaultProfileOrder = &ProfileOrder{
Direction: entgql.OrderDirectionAsc,
Field: &ProfileOrderField{
Value: func(pr *Profile) (ent.Value, error) {
return pr.ID, nil
},
column: profile.FieldID,
toTerm: profile.ByID,
toCursor: func(pr *Profile) Cursor {
return Cursor{ID: pr.ID}
},
},
}
// ToEdge converts Profile into ProfileEdge.
func (pr *Profile) ToEdge(order *ProfileOrder) *ProfileEdge {
if order == nil {
order = DefaultProfileOrder
}
return &ProfileEdge{
Node: pr,
Cursor: order.Field.toCursor(pr),
}
}