1127 lines
30 KiB
Go
1127 lines
30 KiB
Go
// 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),
|
|
}
|
|
}
|