Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions entgql/internal/todo/ent.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1387,6 +1387,7 @@ Properties by which User connections can be ordered.
"""
enum UserOrderField {
GROUPS_COUNT
FRIENDS_COUNT
}
"""
UserWhereInput is used for filtering User objects.
Expand Down
1 change: 1 addition & 0 deletions entgql/internal/todo/ent.resolvers.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 25 additions & 2 deletions entgql/internal/todo/ent/gql_pagination.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion entgql/internal/todo/ent/schema/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ func (User) Edges() []ent.Edge {
),
edge.To("friends", User.Type).
Through("friendships", Friendship.Type).
Annotations(entgql.RelayConnection()),
Annotations(
entgql.RelayConnection(),
entgql.OrderField("FRIENDS_COUNT"),
),
}
}

Expand Down
78 changes: 78 additions & 0 deletions entgql/internal/todo/todo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1989,6 +1989,84 @@ func TestMutation_ClearChildren(t *testing.T) {
require.False(t, root.QueryChildren().ExistX(ctx))
}

func TestQuery_SortUserByFriendshipsCount(t *testing.T) {
ec := enttest.Open(t, dialect.SQLite,
fmt.Sprintf("file:%s?mode=memory&cache=shared&_fk=1", t.Name()),
enttest.WithMigrateOptions(migrate.WithGlobalUniqueID(true)),
)
srv := handler.NewDefaultServer(gen.NewSchema(ec))
srv.Use(entgql.Transactioner{TxOpener: ec})
gqlc := client.New(srv)

ctx := context.Background()
user := ec.User.Create().SetRequiredMetadata(map[string]any{}).SaveX(ctx)
friend := ec.User.Create().SetRequiredMetadata(map[string]any{}).AddFriends(user).SaveX(ctx)
secondFriend := ec.User.Create().SetRequiredMetadata(map[string]any{}).AddFriends(user, friend).SaveX(ctx)
thirdFried := ec.User.Create().SetRequiredMetadata(map[string]any{}).AddFriends(user).SaveX(ctx)

require.True(t, user.QueryFriends().ExistX(ctx))
require.True(t, friend.QueryFriends().ExistX(ctx))
require.True(t, secondFriend.QueryFriends().ExistX(ctx))
require.True(t, thirdFried.QueryFriends().ExistX(ctx))

var rsp struct {
Users struct {
Edges []struct {
Node struct {
ID string
Friends struct {
TotalCount int
}
}
}
}
}

query := `
query testThroughEdgeOrderByQuery($orderDirection: OrderDirection!) {
users (orderBy:{ field: FRIENDS_COUNT, direction: $orderDirection }) {
edges {
node {
id
friends {
totalCount
}
}
}
}
}
`

testCases := []struct {
direction string
expectedCountOrder []int
}{
{
direction: "DESC",
expectedCountOrder: []int{3, 2, 2, 1},
},
{
direction: "ASC",
expectedCountOrder: []int{1, 2, 2, 3},
},
}

for _, tc := range testCases {
t.Run(tc.direction, func(t *testing.T) {
err := gqlc.Post(
query,
&rsp,
client.Var("orderDirection", tc.direction))

require.NoError(t, err)
require.Len(t, rsp.Users.Edges, 4)
for i, edge := range rsp.Users.Edges {
require.Equal(t, edge.Node.Friends.TotalCount, tc.expectedCountOrder[i])
}
})
}
}

func TestMutation_ClearFriend(t *testing.T) {
ec := enttest.Open(t, dialect.SQLite,
fmt.Sprintf("file:%s?mode=memory&cache=shared&_fk=1", t.Name()),
Expand Down
5 changes: 3 additions & 2 deletions entgql/internal/todogotype/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions entgql/internal/todopulid/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions entgql/internal/todouuid/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion entgql/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,12 +452,16 @@ func orderFields(n *gen.Type) ([]*OrderTerm, error) {
})
}
}
edgeNamesWithThroughTables := make(map[string]interface{})
for _, e := range n.Edges {
name := strings.ToUpper(e.Name)
switch ant, err := annotation(e.Annotations); {
case err != nil:
return nil, err
case ant.Skip.Is(SkipOrderField), ant.OrderField == "":
case strings.HasSuffix(ant.OrderField, "_COUNT") &&
edgeNamesWithThroughTables[strings.TrimSuffix(ant.OrderField, "_COUNT")] != nil:
// skip the through table annotations, annotations are applied on the `edge.To` edge instead
case ant.OrderField == fmt.Sprintf("%s_COUNT", name):
// Validate that the edge has a count ordering.
if _, err := e.OrderCountName(); err != nil {
Expand All @@ -471,7 +475,7 @@ func orderFields(n *gen.Type) ([]*OrderTerm, error) {
Count: true,
})
case strings.HasPrefix(ant.OrderField, name+"_"):
// Validate that the edge has a edge field ordering.
// Validate that the edge has an edge field ordering.
if _, err := e.OrderFieldName(); err != nil {
return nil, fmt.Errorf("entgql: invalid order field %s defined on edge %s.%s: %w", ant.OrderField, n.Name, e.Name, err)
}
Expand All @@ -493,6 +497,9 @@ func orderFields(n *gen.Type) ([]*OrderTerm, error) {
default:
return nil, fmt.Errorf("entgql: invalid order field defined on edge %s.%s", n.Name, e.Name)
}
if e.Through != nil {
edgeNamesWithThroughTables[name] = true
}
}
return terms, nil
}
Expand Down
1 change: 1 addition & 0 deletions entgql/testdata/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -313,4 +313,5 @@ Properties by which User connections can be ordered.
"""
enum UserOrderField {
GROUPS_COUNT
FRIENDS_COUNT
}
1 change: 1 addition & 0 deletions entgql/testdata/schema_relay.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,7 @@ Properties by which User connections can be ordered.
"""
enum UserOrderField {
GROUPS_COUNT
FRIENDS_COUNT
}
"""
UserWhereInput is used for filtering User objects.
Expand Down
Loading