mirror of
https://github.com/ent/ent.git
synced 2026-05-24 09:31:56 +03:00
entc/gen: add eager-loading support (#263)
* entc/gen: add OwnFK indicator for type edges * entc/gen: add Edges field for generated types * entc/gen: add With<T> method to query-builder template * entc/gen: scan and assign foreign-keys on eager-loading * entc/gen: load fk-relations (wip) * entc/integration: add o2m/m2o tests for eager-loading * entc/gen: add m2m support for eager-loading * entc/gen: add integration tests for m2m and subgraphs * entc/gen/integration: add tests for o2o eager-loading * all: generate all assets
This commit is contained in:
@@ -21,20 +21,36 @@ type Group struct {
|
||||
ID int `json:"id,omitempty"`
|
||||
// Name holds the value of the "name" field.
|
||||
Name string `json:"name,omitempty"`
|
||||
// Edges holds the relations/edges for other nodes in the graph.
|
||||
// The values are being populated by the GroupQuery when eager-loading is set.
|
||||
Edges struct {
|
||||
// Users holds the value of the users edge.
|
||||
Users []*User
|
||||
// Admin holds the value of the admin edge.
|
||||
Admin *User
|
||||
}
|
||||
admin_id *int
|
||||
}
|
||||
|
||||
// scanValues returns the types for scanning values from sql.Rows.
|
||||
func (*Group) scanValues() []interface{} {
|
||||
return []interface{}{
|
||||
&sql.NullInt64{},
|
||||
&sql.NullString{},
|
||||
&sql.NullInt64{}, // id
|
||||
&sql.NullString{}, // name
|
||||
}
|
||||
}
|
||||
|
||||
// fkValues returns the types for scanning foreign-keys values from sql.Rows.
|
||||
func (*Group) fkValues() []interface{} {
|
||||
return []interface{}{
|
||||
&sql.NullInt64{}, // admin_id
|
||||
}
|
||||
}
|
||||
|
||||
// assignValues assigns the values that were returned from sql.Rows (after scanning)
|
||||
// to the Group fields.
|
||||
func (gr *Group) assignValues(values ...interface{}) error {
|
||||
if m, n := len(values), len(group.Columns); m != n {
|
||||
if m, n := len(values), len(group.Columns); m < n {
|
||||
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
|
||||
}
|
||||
value, ok := values[0].(*sql.NullInt64)
|
||||
@@ -48,6 +64,15 @@ func (gr *Group) assignValues(values ...interface{}) error {
|
||||
} else if value.Valid {
|
||||
gr.Name = value.String
|
||||
}
|
||||
values = values[1:]
|
||||
if len(values) == len(group.ForeignKeys) {
|
||||
if value, ok := values[0].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for edge-field admin_id", value)
|
||||
} else if value.Valid {
|
||||
gr.admin_id = new(int)
|
||||
*gr.admin_id = int(value.Int64)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -30,12 +30,17 @@ const (
|
||||
AdminColumn = "admin_id"
|
||||
)
|
||||
|
||||
// Columns holds all SQL columns are group fields.
|
||||
// Columns holds all SQL columns for group fields.
|
||||
var Columns = []string{
|
||||
FieldID,
|
||||
FieldName,
|
||||
}
|
||||
|
||||
// ForeignKeys holds the SQL foreign-keys that are owned by the Group type.
|
||||
var ForeignKeys = []string{
|
||||
"admin_id",
|
||||
}
|
||||
|
||||
var (
|
||||
// UsersPrimaryKey and UsersColumn2 are the table columns denoting the
|
||||
// primary key for the users relation (M2M).
|
||||
|
||||
@@ -8,6 +8,7 @@ package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
@@ -28,6 +29,10 @@ type GroupQuery struct {
|
||||
order []Order
|
||||
unique []string
|
||||
predicates []predicate.Group
|
||||
// eager-loading edges.
|
||||
withUsers *UserQuery
|
||||
withAdmin *UserQuery
|
||||
withFKs bool
|
||||
// intermediate query.
|
||||
sql *sql.Selector
|
||||
}
|
||||
@@ -249,6 +254,28 @@ func (gq *GroupQuery) Clone() *GroupQuery {
|
||||
}
|
||||
}
|
||||
|
||||
// WithUsers tells the query-builder to eager-loads the nodes that are connected to
|
||||
// the "users" edge. The optional arguments used to configure the query builder of the edge.
|
||||
func (gq *GroupQuery) WithUsers(opts ...func(*UserQuery)) *GroupQuery {
|
||||
query := &UserQuery{config: gq.config}
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
gq.withUsers = query
|
||||
return gq
|
||||
}
|
||||
|
||||
// WithAdmin tells the query-builder to eager-loads the nodes that are connected to
|
||||
// the "admin" edge. The optional arguments used to configure the query builder of the edge.
|
||||
func (gq *GroupQuery) WithAdmin(opts ...func(*UserQuery)) *GroupQuery {
|
||||
query := &UserQuery{config: gq.config}
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
gq.withAdmin = query
|
||||
return gq
|
||||
}
|
||||
|
||||
// GroupBy used to group vertices by one or more fields/columns.
|
||||
// It is often used with aggregate functions, like: count, max, mean, min, sum.
|
||||
//
|
||||
@@ -292,13 +319,24 @@ func (gq *GroupQuery) Select(field string, fields ...string) *GroupSelect {
|
||||
|
||||
func (gq *GroupQuery) sqlAll(ctx context.Context) ([]*Group, error) {
|
||||
var (
|
||||
nodes []*Group
|
||||
spec = gq.querySpec()
|
||||
nodes []*Group
|
||||
withFKs = gq.withFKs
|
||||
spec = gq.querySpec()
|
||||
)
|
||||
if gq.withAdmin != nil {
|
||||
withFKs = true
|
||||
}
|
||||
if withFKs {
|
||||
spec.Node.Columns = append(spec.Node.Columns, group.ForeignKeys...)
|
||||
}
|
||||
spec.ScanValues = func() []interface{} {
|
||||
node := &Group{config: gq.config}
|
||||
nodes = append(nodes, node)
|
||||
return node.scanValues()
|
||||
values := node.scanValues()
|
||||
if withFKs {
|
||||
values = append(values, node.fkValues()...)
|
||||
}
|
||||
return values
|
||||
}
|
||||
spec.Assign = func(values ...interface{}) error {
|
||||
if len(nodes) == 0 {
|
||||
@@ -310,6 +348,95 @@ func (gq *GroupQuery) sqlAll(ctx context.Context) ([]*Group, error) {
|
||||
if err := sqlgraph.QueryNodes(ctx, gq.driver, spec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if query := gq.withUsers; query != nil {
|
||||
fks := make([]driver.Value, 0, len(nodes))
|
||||
ids := make(map[int]*Group, len(nodes))
|
||||
for _, node := range nodes {
|
||||
ids[node.ID] = node
|
||||
fks = append(fks, node.ID)
|
||||
}
|
||||
var (
|
||||
edgeids []int
|
||||
edges = make(map[int][]*Group)
|
||||
)
|
||||
spec := &sqlgraph.EdgeQuerySpec{
|
||||
Edge: &sqlgraph.EdgeSpec{
|
||||
Inverse: false,
|
||||
Table: group.UsersTable,
|
||||
Columns: group.UsersPrimaryKey,
|
||||
},
|
||||
Predicate: func(s *sql.Selector) {
|
||||
s.Where(sql.InValues(group.UsersPrimaryKey[0], fks...))
|
||||
},
|
||||
|
||||
ScanValues: func() [2]interface{} {
|
||||
return [2]interface{}{&sql.NullInt64{}, &sql.NullInt64{}}
|
||||
},
|
||||
Assign: func(out, in interface{}) error {
|
||||
eout, ok := out.(*sql.NullInt64)
|
||||
if !ok || eout == nil {
|
||||
return fmt.Errorf("unexpected id value for edge-out")
|
||||
}
|
||||
ein, ok := in.(*sql.NullInt64)
|
||||
if !ok || ein == nil {
|
||||
return fmt.Errorf("unexpected id value for edge-in")
|
||||
}
|
||||
outValue := int(eout.Int64)
|
||||
inValue := int(eout.Int64)
|
||||
node, ok := ids[outValue]
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected node id in edges: %v", outValue)
|
||||
}
|
||||
edgeids = append(edgeids, inValue)
|
||||
edges[inValue] = append(edges[inValue], node)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
if err := sqlgraph.QueryEdges(ctx, gq.driver, spec); err != nil {
|
||||
return nil, fmt.Errorf(`query edges "users": %v`, err)
|
||||
}
|
||||
query.Where(user.IDIn(edgeids...))
|
||||
neighbors, err := query.All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, n := range neighbors {
|
||||
nodes, ok := edges[n.ID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`unexpected "users" node returned %v`, n.ID)
|
||||
}
|
||||
for i := range nodes {
|
||||
nodes[i].Edges.Users = append(nodes[i].Edges.Users, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if query := gq.withAdmin; query != nil {
|
||||
ids := make([]int, 0, len(nodes))
|
||||
nodeids := make(map[int][]*Group)
|
||||
for i := range nodes {
|
||||
if fk := nodes[i].admin_id; fk != nil {
|
||||
ids = append(ids, *fk)
|
||||
nodeids[*fk] = append(nodeids[*fk], nodes[i])
|
||||
}
|
||||
}
|
||||
query.Where(user.IDIn(ids...))
|
||||
neighbors, err := query.All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, n := range neighbors {
|
||||
nodes, ok := nodeids[n.ID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`unexpected foreign-key "admin_id" returned %v`, n.ID)
|
||||
}
|
||||
for i := range nodes {
|
||||
nodes[i].Edges.Admin = n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -21,20 +21,36 @@ type Pet struct {
|
||||
ID int `json:"id,omitempty"`
|
||||
// Name holds the value of the "name" field.
|
||||
Name string `json:"name,omitempty"`
|
||||
// Edges holds the relations/edges for other nodes in the graph.
|
||||
// The values are being populated by the PetQuery when eager-loading is set.
|
||||
Edges struct {
|
||||
// Friends holds the value of the friends edge.
|
||||
Friends []*Pet
|
||||
// Owner holds the value of the owner edge.
|
||||
Owner *User
|
||||
}
|
||||
owner_id *int
|
||||
}
|
||||
|
||||
// scanValues returns the types for scanning values from sql.Rows.
|
||||
func (*Pet) scanValues() []interface{} {
|
||||
return []interface{}{
|
||||
&sql.NullInt64{},
|
||||
&sql.NullString{},
|
||||
&sql.NullInt64{}, // id
|
||||
&sql.NullString{}, // name
|
||||
}
|
||||
}
|
||||
|
||||
// fkValues returns the types for scanning foreign-keys values from sql.Rows.
|
||||
func (*Pet) fkValues() []interface{} {
|
||||
return []interface{}{
|
||||
&sql.NullInt64{}, // owner_id
|
||||
}
|
||||
}
|
||||
|
||||
// assignValues assigns the values that were returned from sql.Rows (after scanning)
|
||||
// to the Pet fields.
|
||||
func (pe *Pet) assignValues(values ...interface{}) error {
|
||||
if m, n := len(values), len(pet.Columns); m != n {
|
||||
if m, n := len(values), len(pet.Columns); m < n {
|
||||
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
|
||||
}
|
||||
value, ok := values[0].(*sql.NullInt64)
|
||||
@@ -48,6 +64,15 @@ func (pe *Pet) assignValues(values ...interface{}) error {
|
||||
} else if value.Valid {
|
||||
pe.Name = value.String
|
||||
}
|
||||
values = values[1:]
|
||||
if len(values) == len(pet.ForeignKeys) {
|
||||
if value, ok := values[0].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for edge-field owner_id", value)
|
||||
} else if value.Valid {
|
||||
pe.owner_id = new(int)
|
||||
*pe.owner_id = int(value.Int64)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -27,12 +27,17 @@ const (
|
||||
OwnerColumn = "owner_id"
|
||||
)
|
||||
|
||||
// Columns holds all SQL columns are pet fields.
|
||||
// Columns holds all SQL columns for pet fields.
|
||||
var Columns = []string{
|
||||
FieldID,
|
||||
FieldName,
|
||||
}
|
||||
|
||||
// ForeignKeys holds the SQL foreign-keys that are owned by the Pet type.
|
||||
var ForeignKeys = []string{
|
||||
"owner_id",
|
||||
}
|
||||
|
||||
var (
|
||||
// FriendsPrimaryKey and FriendsColumn2 are the table columns denoting the
|
||||
// primary key for the friends relation (M2M).
|
||||
|
||||
@@ -8,6 +8,7 @@ package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
@@ -28,6 +29,10 @@ type PetQuery struct {
|
||||
order []Order
|
||||
unique []string
|
||||
predicates []predicate.Pet
|
||||
// eager-loading edges.
|
||||
withFriends *PetQuery
|
||||
withOwner *UserQuery
|
||||
withFKs bool
|
||||
// intermediate query.
|
||||
sql *sql.Selector
|
||||
}
|
||||
@@ -249,6 +254,28 @@ func (pq *PetQuery) Clone() *PetQuery {
|
||||
}
|
||||
}
|
||||
|
||||
// WithFriends tells the query-builder to eager-loads the nodes that are connected to
|
||||
// the "friends" edge. The optional arguments used to configure the query builder of the edge.
|
||||
func (pq *PetQuery) WithFriends(opts ...func(*PetQuery)) *PetQuery {
|
||||
query := &PetQuery{config: pq.config}
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
pq.withFriends = query
|
||||
return pq
|
||||
}
|
||||
|
||||
// WithOwner tells the query-builder to eager-loads the nodes that are connected to
|
||||
// the "owner" edge. The optional arguments used to configure the query builder of the edge.
|
||||
func (pq *PetQuery) WithOwner(opts ...func(*UserQuery)) *PetQuery {
|
||||
query := &UserQuery{config: pq.config}
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
pq.withOwner = query
|
||||
return pq
|
||||
}
|
||||
|
||||
// GroupBy used to group vertices by one or more fields/columns.
|
||||
// It is often used with aggregate functions, like: count, max, mean, min, sum.
|
||||
//
|
||||
@@ -292,13 +319,24 @@ func (pq *PetQuery) Select(field string, fields ...string) *PetSelect {
|
||||
|
||||
func (pq *PetQuery) sqlAll(ctx context.Context) ([]*Pet, error) {
|
||||
var (
|
||||
nodes []*Pet
|
||||
spec = pq.querySpec()
|
||||
nodes []*Pet
|
||||
withFKs = pq.withFKs
|
||||
spec = pq.querySpec()
|
||||
)
|
||||
if pq.withOwner != nil {
|
||||
withFKs = true
|
||||
}
|
||||
if withFKs {
|
||||
spec.Node.Columns = append(spec.Node.Columns, pet.ForeignKeys...)
|
||||
}
|
||||
spec.ScanValues = func() []interface{} {
|
||||
node := &Pet{config: pq.config}
|
||||
nodes = append(nodes, node)
|
||||
return node.scanValues()
|
||||
values := node.scanValues()
|
||||
if withFKs {
|
||||
values = append(values, node.fkValues()...)
|
||||
}
|
||||
return values
|
||||
}
|
||||
spec.Assign = func(values ...interface{}) error {
|
||||
if len(nodes) == 0 {
|
||||
@@ -310,6 +348,95 @@ func (pq *PetQuery) sqlAll(ctx context.Context) ([]*Pet, error) {
|
||||
if err := sqlgraph.QueryNodes(ctx, pq.driver, spec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if query := pq.withFriends; query != nil {
|
||||
fks := make([]driver.Value, 0, len(nodes))
|
||||
ids := make(map[int]*Pet, len(nodes))
|
||||
for _, node := range nodes {
|
||||
ids[node.ID] = node
|
||||
fks = append(fks, node.ID)
|
||||
}
|
||||
var (
|
||||
edgeids []int
|
||||
edges = make(map[int][]*Pet)
|
||||
)
|
||||
spec := &sqlgraph.EdgeQuerySpec{
|
||||
Edge: &sqlgraph.EdgeSpec{
|
||||
Inverse: false,
|
||||
Table: pet.FriendsTable,
|
||||
Columns: pet.FriendsPrimaryKey,
|
||||
},
|
||||
Predicate: func(s *sql.Selector) {
|
||||
s.Where(sql.InValues(pet.FriendsPrimaryKey[0], fks...))
|
||||
},
|
||||
|
||||
ScanValues: func() [2]interface{} {
|
||||
return [2]interface{}{&sql.NullInt64{}, &sql.NullInt64{}}
|
||||
},
|
||||
Assign: func(out, in interface{}) error {
|
||||
eout, ok := out.(*sql.NullInt64)
|
||||
if !ok || eout == nil {
|
||||
return fmt.Errorf("unexpected id value for edge-out")
|
||||
}
|
||||
ein, ok := in.(*sql.NullInt64)
|
||||
if !ok || ein == nil {
|
||||
return fmt.Errorf("unexpected id value for edge-in")
|
||||
}
|
||||
outValue := int(eout.Int64)
|
||||
inValue := int(eout.Int64)
|
||||
node, ok := ids[outValue]
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected node id in edges: %v", outValue)
|
||||
}
|
||||
edgeids = append(edgeids, inValue)
|
||||
edges[inValue] = append(edges[inValue], node)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
if err := sqlgraph.QueryEdges(ctx, pq.driver, spec); err != nil {
|
||||
return nil, fmt.Errorf(`query edges "friends": %v`, err)
|
||||
}
|
||||
query.Where(pet.IDIn(edgeids...))
|
||||
neighbors, err := query.All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, n := range neighbors {
|
||||
nodes, ok := edges[n.ID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`unexpected "friends" node returned %v`, n.ID)
|
||||
}
|
||||
for i := range nodes {
|
||||
nodes[i].Edges.Friends = append(nodes[i].Edges.Friends, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if query := pq.withOwner; query != nil {
|
||||
ids := make([]int, 0, len(nodes))
|
||||
nodeids := make(map[int][]*Pet)
|
||||
for i := range nodes {
|
||||
if fk := nodes[i].owner_id; fk != nil {
|
||||
ids = append(ids, *fk)
|
||||
nodeids[*fk] = append(nodeids[*fk], nodes[i])
|
||||
}
|
||||
}
|
||||
query.Where(user.IDIn(ids...))
|
||||
neighbors, err := query.All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, n := range neighbors {
|
||||
nodes, ok := nodeids[n.ID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`unexpected foreign-key "owner_id" returned %v`, n.ID)
|
||||
}
|
||||
for i := range nodes {
|
||||
nodes[i].Edges.Owner = n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -23,21 +23,33 @@ type User struct {
|
||||
Age int `json:"age,omitempty"`
|
||||
// Name holds the value of the "name" field.
|
||||
Name string `json:"name,omitempty"`
|
||||
// Edges holds the relations/edges for other nodes in the graph.
|
||||
// The values are being populated by the UserQuery when eager-loading is set.
|
||||
Edges struct {
|
||||
// Pets holds the value of the pets edge.
|
||||
Pets []*Pet
|
||||
// Friends holds the value of the friends edge.
|
||||
Friends []*User
|
||||
// Groups holds the value of the groups edge.
|
||||
Groups []*Group
|
||||
// Manage holds the value of the manage edge.
|
||||
Manage []*Group
|
||||
}
|
||||
}
|
||||
|
||||
// scanValues returns the types for scanning values from sql.Rows.
|
||||
func (*User) scanValues() []interface{} {
|
||||
return []interface{}{
|
||||
&sql.NullInt64{},
|
||||
&sql.NullInt64{},
|
||||
&sql.NullString{},
|
||||
&sql.NullInt64{}, // id
|
||||
&sql.NullInt64{}, // age
|
||||
&sql.NullString{}, // name
|
||||
}
|
||||
}
|
||||
|
||||
// assignValues assigns the values that were returned from sql.Rows (after scanning)
|
||||
// to the User fields.
|
||||
func (u *User) assignValues(values ...interface{}) error {
|
||||
if m, n := len(values), len(user.Columns); m != n {
|
||||
if m, n := len(values), len(user.Columns); m < n {
|
||||
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
|
||||
}
|
||||
value, ok := values[0].(*sql.NullInt64)
|
||||
|
||||
@@ -41,7 +41,7 @@ const (
|
||||
ManageColumn = "admin_id"
|
||||
)
|
||||
|
||||
// Columns holds all SQL columns are user fields.
|
||||
// Columns holds all SQL columns for user fields.
|
||||
var Columns = []string{
|
||||
FieldID,
|
||||
FieldAge,
|
||||
|
||||
@@ -8,6 +8,7 @@ package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
@@ -29,6 +30,11 @@ type UserQuery struct {
|
||||
order []Order
|
||||
unique []string
|
||||
predicates []predicate.User
|
||||
// eager-loading edges.
|
||||
withPets *PetQuery
|
||||
withFriends *UserQuery
|
||||
withGroups *GroupQuery
|
||||
withManage *GroupQuery
|
||||
// intermediate query.
|
||||
sql *sql.Selector
|
||||
}
|
||||
@@ -274,6 +280,50 @@ func (uq *UserQuery) Clone() *UserQuery {
|
||||
}
|
||||
}
|
||||
|
||||
// WithPets tells the query-builder to eager-loads the nodes that are connected to
|
||||
// the "pets" edge. The optional arguments used to configure the query builder of the edge.
|
||||
func (uq *UserQuery) WithPets(opts ...func(*PetQuery)) *UserQuery {
|
||||
query := &PetQuery{config: uq.config}
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
uq.withPets = query
|
||||
return uq
|
||||
}
|
||||
|
||||
// WithFriends tells the query-builder to eager-loads the nodes that are connected to
|
||||
// the "friends" edge. The optional arguments used to configure the query builder of the edge.
|
||||
func (uq *UserQuery) WithFriends(opts ...func(*UserQuery)) *UserQuery {
|
||||
query := &UserQuery{config: uq.config}
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
uq.withFriends = query
|
||||
return uq
|
||||
}
|
||||
|
||||
// WithGroups tells the query-builder to eager-loads the nodes that are connected to
|
||||
// the "groups" edge. The optional arguments used to configure the query builder of the edge.
|
||||
func (uq *UserQuery) WithGroups(opts ...func(*GroupQuery)) *UserQuery {
|
||||
query := &GroupQuery{config: uq.config}
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
uq.withGroups = query
|
||||
return uq
|
||||
}
|
||||
|
||||
// WithManage tells the query-builder to eager-loads the nodes that are connected to
|
||||
// the "manage" edge. The optional arguments used to configure the query builder of the edge.
|
||||
func (uq *UserQuery) WithManage(opts ...func(*GroupQuery)) *UserQuery {
|
||||
query := &GroupQuery{config: uq.config}
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
uq.withManage = query
|
||||
return uq
|
||||
}
|
||||
|
||||
// GroupBy used to group vertices by one or more fields/columns.
|
||||
// It is often used with aggregate functions, like: count, max, mean, min, sum.
|
||||
//
|
||||
@@ -323,7 +373,8 @@ func (uq *UserQuery) sqlAll(ctx context.Context) ([]*User, error) {
|
||||
spec.ScanValues = func() []interface{} {
|
||||
node := &User{config: uq.config}
|
||||
nodes = append(nodes, node)
|
||||
return node.scanValues()
|
||||
values := node.scanValues()
|
||||
return values
|
||||
}
|
||||
spec.Assign = func(values ...interface{}) error {
|
||||
if len(nodes) == 0 {
|
||||
@@ -335,6 +386,189 @@ func (uq *UserQuery) sqlAll(ctx context.Context) ([]*User, error) {
|
||||
if err := sqlgraph.QueryNodes(ctx, uq.driver, spec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if query := uq.withPets; query != nil {
|
||||
fks := make([]driver.Value, 0, len(nodes))
|
||||
nodeids := make(map[int]*User)
|
||||
for i := range nodes {
|
||||
fks = append(fks, nodes[i].ID)
|
||||
nodeids[nodes[i].ID] = nodes[i]
|
||||
}
|
||||
query.withFKs = true
|
||||
query.Where(predicate.Pet(func(s *sql.Selector) {
|
||||
s.Where(sql.InValues(user.PetsColumn, fks...))
|
||||
}))
|
||||
neighbors, err := query.All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, n := range neighbors {
|
||||
fk := n.owner_id
|
||||
if fk == nil {
|
||||
return nil, fmt.Errorf(`foreign-key "owner_id" is nil for node %v`, n.ID)
|
||||
}
|
||||
node, ok := nodeids[*fk]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`unexpected foreign-key "owner_id" returned %v for node %v`, *fk, n.ID)
|
||||
}
|
||||
node.Edges.Pets = append(node.Edges.Pets, n)
|
||||
}
|
||||
}
|
||||
|
||||
if query := uq.withFriends; query != nil {
|
||||
fks := make([]driver.Value, 0, len(nodes))
|
||||
ids := make(map[int]*User, len(nodes))
|
||||
for _, node := range nodes {
|
||||
ids[node.ID] = node
|
||||
fks = append(fks, node.ID)
|
||||
}
|
||||
var (
|
||||
edgeids []int
|
||||
edges = make(map[int][]*User)
|
||||
)
|
||||
spec := &sqlgraph.EdgeQuerySpec{
|
||||
Edge: &sqlgraph.EdgeSpec{
|
||||
Inverse: false,
|
||||
Table: user.FriendsTable,
|
||||
Columns: user.FriendsPrimaryKey,
|
||||
},
|
||||
Predicate: func(s *sql.Selector) {
|
||||
s.Where(sql.InValues(user.FriendsPrimaryKey[0], fks...))
|
||||
},
|
||||
|
||||
ScanValues: func() [2]interface{} {
|
||||
return [2]interface{}{&sql.NullInt64{}, &sql.NullInt64{}}
|
||||
},
|
||||
Assign: func(out, in interface{}) error {
|
||||
eout, ok := out.(*sql.NullInt64)
|
||||
if !ok || eout == nil {
|
||||
return fmt.Errorf("unexpected id value for edge-out")
|
||||
}
|
||||
ein, ok := in.(*sql.NullInt64)
|
||||
if !ok || ein == nil {
|
||||
return fmt.Errorf("unexpected id value for edge-in")
|
||||
}
|
||||
outValue := int(eout.Int64)
|
||||
inValue := int(eout.Int64)
|
||||
node, ok := ids[outValue]
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected node id in edges: %v", outValue)
|
||||
}
|
||||
edgeids = append(edgeids, inValue)
|
||||
edges[inValue] = append(edges[inValue], node)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
if err := sqlgraph.QueryEdges(ctx, uq.driver, spec); err != nil {
|
||||
return nil, fmt.Errorf(`query edges "friends": %v`, err)
|
||||
}
|
||||
query.Where(user.IDIn(edgeids...))
|
||||
neighbors, err := query.All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, n := range neighbors {
|
||||
nodes, ok := edges[n.ID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`unexpected "friends" node returned %v`, n.ID)
|
||||
}
|
||||
for i := range nodes {
|
||||
nodes[i].Edges.Friends = append(nodes[i].Edges.Friends, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if query := uq.withGroups; query != nil {
|
||||
fks := make([]driver.Value, 0, len(nodes))
|
||||
ids := make(map[int]*User, len(nodes))
|
||||
for _, node := range nodes {
|
||||
ids[node.ID] = node
|
||||
fks = append(fks, node.ID)
|
||||
}
|
||||
var (
|
||||
edgeids []int
|
||||
edges = make(map[int][]*User)
|
||||
)
|
||||
spec := &sqlgraph.EdgeQuerySpec{
|
||||
Edge: &sqlgraph.EdgeSpec{
|
||||
Inverse: true,
|
||||
Table: user.GroupsTable,
|
||||
Columns: user.GroupsPrimaryKey,
|
||||
},
|
||||
Predicate: func(s *sql.Selector) {
|
||||
s.Where(sql.InValues(user.GroupsPrimaryKey[1], fks...))
|
||||
},
|
||||
|
||||
ScanValues: func() [2]interface{} {
|
||||
return [2]interface{}{&sql.NullInt64{}, &sql.NullInt64{}}
|
||||
},
|
||||
Assign: func(out, in interface{}) error {
|
||||
eout, ok := out.(*sql.NullInt64)
|
||||
if !ok || eout == nil {
|
||||
return fmt.Errorf("unexpected id value for edge-out")
|
||||
}
|
||||
ein, ok := in.(*sql.NullInt64)
|
||||
if !ok || ein == nil {
|
||||
return fmt.Errorf("unexpected id value for edge-in")
|
||||
}
|
||||
outValue := int(eout.Int64)
|
||||
inValue := int(eout.Int64)
|
||||
node, ok := ids[outValue]
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected node id in edges: %v", outValue)
|
||||
}
|
||||
edgeids = append(edgeids, inValue)
|
||||
edges[inValue] = append(edges[inValue], node)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
if err := sqlgraph.QueryEdges(ctx, uq.driver, spec); err != nil {
|
||||
return nil, fmt.Errorf(`query edges "groups": %v`, err)
|
||||
}
|
||||
query.Where(group.IDIn(edgeids...))
|
||||
neighbors, err := query.All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, n := range neighbors {
|
||||
nodes, ok := edges[n.ID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`unexpected "groups" node returned %v`, n.ID)
|
||||
}
|
||||
for i := range nodes {
|
||||
nodes[i].Edges.Groups = append(nodes[i].Edges.Groups, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if query := uq.withManage; query != nil {
|
||||
fks := make([]driver.Value, 0, len(nodes))
|
||||
nodeids := make(map[int]*User)
|
||||
for i := range nodes {
|
||||
fks = append(fks, nodes[i].ID)
|
||||
nodeids[nodes[i].ID] = nodes[i]
|
||||
}
|
||||
query.withFKs = true
|
||||
query.Where(predicate.Group(func(s *sql.Selector) {
|
||||
s.Where(sql.InValues(user.ManageColumn, fks...))
|
||||
}))
|
||||
neighbors, err := query.All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, n := range neighbors {
|
||||
fk := n.admin_id
|
||||
if fk == nil {
|
||||
return nil, fmt.Errorf(`foreign-key "admin_id" is nil for node %v`, n.ID)
|
||||
}
|
||||
node, ok := nodeids[*fk]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`unexpected foreign-key "admin_id" returned %v for node %v`, *fk, n.ID)
|
||||
}
|
||||
node.Edges.Manage = append(node.Edges.Manage, n)
|
||||
}
|
||||
}
|
||||
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user