From 2c1a3555cc4a1bf85fbaaa193325fc2281d073fb Mon Sep 17 00:00:00 2001 From: Ariel Mashraki <7413593+a8m@users.noreply.github.com> Date: Tue, 5 Jul 2022 15:45:28 +0300 Subject: [PATCH] entc/gen: ignore edge-fields order in edge-schema with composite identifiers (#2719) This PR allows defining edge schemas with any order of their edges but still enforce the ordering of the fields in the ID annotation --- dialect/sql/schema/schema.go | 17 +- entc/gen/graph.go | 20 +- entc/integration/edgeschema/ent/client.go | 14 +- .../edgeschema/ent/migrate/schema.go | 16 +- entc/integration/edgeschema/ent/mutation.go | 92 ++++---- .../edgeschema/ent/schema/tweetlike.go | 8 +- entc/integration/edgeschema/ent/tweetlike.go | 44 ++-- .../edgeschema/ent/tweetlike/tweetlike.go | 22 +- .../edgeschema/ent/tweetlike/where.go | 56 ++--- .../edgeschema/ent/tweetlike_create.go | 56 ++--- .../edgeschema/ent/tweetlike_query.go | 124 +++++------ .../edgeschema/ent/tweetlike_update.go | 196 +++++++++--------- 12 files changed, 344 insertions(+), 321 deletions(-) diff --git a/dialect/sql/schema/schema.go b/dialect/sql/schema/schema.go index c0de6ba8d..675ad2d6f 100644 --- a/dialect/sql/schema/schema.go +++ b/dialect/sql/schema/schema.go @@ -69,10 +69,25 @@ func (t *Table) AddColumn(c *Column) *Table { // HasColumn reports if the table contains a column with the given name. func (t *Table) HasColumn(name string) bool { - _, ok := t.columns[name] + _, ok := t.Column(name) return ok } +// Column returns the column with the given name. If exists. +func (t *Table) Column(name string) (*Column, bool) { + if c, ok := t.columns[name]; ok { + return c, true + } + // In case the column was added + // directly to the Columns field. + for _, c := range t.Columns { + if c.Name == name { + return c, true + } + } + return nil, false +} + // SetAnnotation the entsql.Annotation on the table. func (t *Table) SetAnnotation(ant *entsql.Annotation) *Table { t.Annotation = ant diff --git a/entc/gen/graph.go b/entc/gen/graph.go index f49cfb343..64bc5421a 100644 --- a/entc/gen/graph.go +++ b/entc/gen/graph.go @@ -520,7 +520,7 @@ func (g *Graph) edgeSchemas() error { Columns: ref.Rel.Columns, }, }) - // Edge schema contains a composite primary key. + // Edge schema contains a composite primary key, and it was not resolved in previous iterations. if ant := fieldAnnotate(typ.Annotations); ant != nil && len(ant.ID) > 0 && len(typ.EdgeSchema.ID) == 0 { r1, r2 := e.Rel.Columns[0], e.Rel.Columns[1] if len(ant.ID) != 2 || ant.ID[0] != r1 || ant.ID[1] != r2 { @@ -658,7 +658,9 @@ func (g *Graph) Tables() (all []*schema.Table, err error) { } } if n.HasCompositeID() { - addCompositePK(tables[n.Table()], n) + if err := addCompositePK(tables[n.Table()], n); err != nil { + return nil, err + } } } // Append indexes to tables after all columns were added (including relation columns). @@ -681,16 +683,22 @@ func mayAddColumn(t *schema.Table, c *schema.Column) { } } -func addCompositePK(t *schema.Table, n *Type) { +func addCompositePK(t *schema.Table, n *Type) error { columns := make([]*schema.Column, 0, len(n.EdgeSchema.ID)) for _, id := range n.EdgeSchema.ID { - for i, f := range n.Fields { - if f.IsEdgeField() && id == f && t.Columns[i].Name == f.StorageKey() { - columns = append(columns, t.Columns[i]) + for _, f := range n.Fields { + if !f.IsEdgeField() || id != f { + continue } + c, ok := t.Column(f.StorageKey()) + if !ok { + return fmt.Errorf("missing column %q for edge field %q.%q", f.StorageKey(), n.Name, f.Name) + } + columns = append(columns, c) } } t.PrimaryKey = columns + return nil } // fkSymbol returns the symbol of the foreign-key constraint for edges of type O2M, M2O and O2O. diff --git a/entc/integration/edgeschema/ent/client.go b/entc/integration/edgeschema/ent/client.go index f74a4494a..82a85352f 100644 --- a/entc/integration/edgeschema/ent/client.go +++ b/entc/integration/edgeschema/ent/client.go @@ -868,13 +868,6 @@ func (c *TweetLikeClient) Query() *TweetLikeQuery { } } -// QueryUser queries the user edge of a TweetLike. -func (c *TweetLikeClient) QueryUser(tl *TweetLike) *UserQuery { - return c.Query(). - Where(tweetlike.UserID(tl.UserID), tweetlike.TweetID(tl.TweetID)). - QueryUser() -} - // QueryTweet queries the tweet edge of a TweetLike. func (c *TweetLikeClient) QueryTweet(tl *TweetLike) *TweetQuery { return c.Query(). @@ -882,6 +875,13 @@ func (c *TweetLikeClient) QueryTweet(tl *TweetLike) *TweetQuery { QueryTweet() } +// QueryUser queries the user edge of a TweetLike. +func (c *TweetLikeClient) QueryUser(tl *TweetLike) *UserQuery { + return c.Query(). + Where(tweetlike.UserID(tl.UserID), tweetlike.TweetID(tl.TweetID)). + QueryUser() +} + // Hooks returns the client hooks. func (c *TweetLikeClient) Hooks() []Hook { return c.hooks.TweetLike diff --git a/entc/integration/edgeschema/ent/migrate/schema.go b/entc/integration/edgeschema/ent/migrate/schema.go index 2462320a0..778c06a12 100644 --- a/entc/integration/edgeschema/ent/migrate/schema.go +++ b/entc/integration/edgeschema/ent/migrate/schema.go @@ -121,25 +121,25 @@ var ( // TweetLikesColumns holds the columns for the "tweet_likes" table. TweetLikesColumns = []*schema.Column{ {Name: "liked_at", Type: field.TypeTime}, - {Name: "user_id", Type: field.TypeInt}, {Name: "tweet_id", Type: field.TypeInt}, + {Name: "user_id", Type: field.TypeInt}, } // TweetLikesTable holds the schema information for the "tweet_likes" table. TweetLikesTable = &schema.Table{ Name: "tweet_likes", Columns: TweetLikesColumns, - PrimaryKey: []*schema.Column{TweetLikesColumns[1], TweetLikesColumns[2]}, + PrimaryKey: []*schema.Column{TweetLikesColumns[2], TweetLikesColumns[1]}, ForeignKeys: []*schema.ForeignKey{ { - Symbol: "tweet_likes_users_user", + Symbol: "tweet_likes_tweets_tweet", Columns: []*schema.Column{TweetLikesColumns[1]}, - RefColumns: []*schema.Column{UsersColumns[0]}, + RefColumns: []*schema.Column{TweetsColumns[0]}, OnDelete: schema.NoAction, }, { - Symbol: "tweet_likes_tweets_tweet", + Symbol: "tweet_likes_users_user", Columns: []*schema.Column{TweetLikesColumns[2]}, - RefColumns: []*schema.Column{TweetsColumns[0]}, + RefColumns: []*schema.Column{UsersColumns[0]}, OnDelete: schema.NoAction, }, }, @@ -282,8 +282,8 @@ func init() { FriendshipsTable.ForeignKeys[1].RefTable = UsersTable RelationshipsTable.ForeignKeys[0].RefTable = UsersTable RelationshipsTable.ForeignKeys[1].RefTable = UsersTable - TweetLikesTable.ForeignKeys[0].RefTable = UsersTable - TweetLikesTable.ForeignKeys[1].RefTable = TweetsTable + TweetLikesTable.ForeignKeys[0].RefTable = TweetsTable + TweetLikesTable.ForeignKeys[1].RefTable = UsersTable TweetTagsTable.ForeignKeys[0].RefTable = TagsTable TweetTagsTable.ForeignKeys[1].RefTable = TweetsTable UserGroupsTable.ForeignKeys[0].RefTable = UsersTable diff --git a/entc/integration/edgeschema/ent/mutation.go b/entc/integration/edgeschema/ent/mutation.go index 297184bb6..ff6c601dd 100644 --- a/entc/integration/edgeschema/ent/mutation.go +++ b/entc/integration/edgeschema/ent/mutation.go @@ -2811,10 +2811,10 @@ type TweetLikeMutation struct { typ string liked_at *time.Time clearedFields map[string]struct{} - user *int - cleareduser bool tweet *int clearedtweet bool + user *int + cleareduser bool done bool oldValue func(context.Context) (*TweetLike, error) predicates []predicate.TweetLike @@ -2915,32 +2915,6 @@ func (m *TweetLikeMutation) ResetTweetID() { m.tweet = nil } -// ClearUser clears the "user" edge to the User entity. -func (m *TweetLikeMutation) ClearUser() { - m.cleareduser = true -} - -// UserCleared reports if the "user" edge to the User entity was cleared. -func (m *TweetLikeMutation) UserCleared() bool { - return m.cleareduser -} - -// UserIDs returns the "user" edge IDs in the mutation. -// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use -// UserID instead. It exists only for internal usage by the builders. -func (m *TweetLikeMutation) UserIDs() (ids []int) { - if id := m.user; id != nil { - ids = append(ids, *id) - } - return -} - -// ResetUser resets all changes to the "user" edge. -func (m *TweetLikeMutation) ResetUser() { - m.user = nil - m.cleareduser = false -} - // ClearTweet clears the "tweet" edge to the Tweet entity. func (m *TweetLikeMutation) ClearTweet() { m.clearedtweet = true @@ -2967,6 +2941,32 @@ func (m *TweetLikeMutation) ResetTweet() { m.clearedtweet = false } +// ClearUser clears the "user" edge to the User entity. +func (m *TweetLikeMutation) ClearUser() { + m.cleareduser = true +} + +// UserCleared reports if the "user" edge to the User entity was cleared. +func (m *TweetLikeMutation) UserCleared() bool { + return m.cleareduser +} + +// UserIDs returns the "user" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// UserID instead. It exists only for internal usage by the builders. +func (m *TweetLikeMutation) UserIDs() (ids []int) { + if id := m.user; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetUser resets all changes to the "user" edge. +func (m *TweetLikeMutation) ResetUser() { + m.user = nil + m.cleareduser = false +} + // Where appends a list predicates to the TweetLikeMutation builder. func (m *TweetLikeMutation) Where(ps ...predicate.TweetLike) { m.predicates = append(m.predicates, ps...) @@ -3115,12 +3115,12 @@ func (m *TweetLikeMutation) ResetField(name string) error { // AddedEdges returns all edge names that were set/added in this mutation. func (m *TweetLikeMutation) AddedEdges() []string { edges := make([]string, 0, 2) - if m.user != nil { - edges = append(edges, tweetlike.EdgeUser) - } if m.tweet != nil { edges = append(edges, tweetlike.EdgeTweet) } + if m.user != nil { + edges = append(edges, tweetlike.EdgeUser) + } return edges } @@ -3128,14 +3128,14 @@ func (m *TweetLikeMutation) AddedEdges() []string { // name in this mutation. func (m *TweetLikeMutation) AddedIDs(name string) []ent.Value { switch name { - case tweetlike.EdgeUser: - if id := m.user; id != nil { - return []ent.Value{*id} - } case tweetlike.EdgeTweet: if id := m.tweet; id != nil { return []ent.Value{*id} } + case tweetlike.EdgeUser: + if id := m.user; id != nil { + return []ent.Value{*id} + } } return nil } @@ -3157,12 +3157,12 @@ func (m *TweetLikeMutation) RemovedIDs(name string) []ent.Value { // ClearedEdges returns all edge names that were cleared in this mutation. func (m *TweetLikeMutation) ClearedEdges() []string { edges := make([]string, 0, 2) - if m.cleareduser { - edges = append(edges, tweetlike.EdgeUser) - } if m.clearedtweet { edges = append(edges, tweetlike.EdgeTweet) } + if m.cleareduser { + edges = append(edges, tweetlike.EdgeUser) + } return edges } @@ -3170,10 +3170,10 @@ func (m *TweetLikeMutation) ClearedEdges() []string { // was cleared in this mutation. func (m *TweetLikeMutation) EdgeCleared(name string) bool { switch name { - case tweetlike.EdgeUser: - return m.cleareduser case tweetlike.EdgeTweet: return m.clearedtweet + case tweetlike.EdgeUser: + return m.cleareduser } return false } @@ -3182,12 +3182,12 @@ func (m *TweetLikeMutation) EdgeCleared(name string) bool { // if that edge is not defined in the schema. func (m *TweetLikeMutation) ClearEdge(name string) error { switch name { - case tweetlike.EdgeUser: - m.ClearUser() - return nil case tweetlike.EdgeTweet: m.ClearTweet() return nil + case tweetlike.EdgeUser: + m.ClearUser() + return nil } return fmt.Errorf("unknown TweetLike unique edge %s", name) } @@ -3196,12 +3196,12 @@ func (m *TweetLikeMutation) ClearEdge(name string) error { // It returns an error if the edge is not defined in the schema. func (m *TweetLikeMutation) ResetEdge(name string) error { switch name { - case tweetlike.EdgeUser: - m.ResetUser() - return nil case tweetlike.EdgeTweet: m.ResetTweet() return nil + case tweetlike.EdgeUser: + m.ResetUser() + return nil } return fmt.Errorf("unknown TweetLike edge %s", name) } diff --git a/entc/integration/edgeschema/ent/schema/tweetlike.go b/entc/integration/edgeschema/ent/schema/tweetlike.go index 8e122dae7..49c56ecdd 100644 --- a/entc/integration/edgeschema/ent/schema/tweetlike.go +++ b/entc/integration/edgeschema/ent/schema/tweetlike.go @@ -37,13 +37,13 @@ func (TweetLike) Fields() []ent.Field { // Edges of the TweetLike. func (TweetLike) Edges() []ent.Edge { return []ent.Edge{ - edge.To("user", User.Type). - Unique(). - Required(). - Field("user_id"), edge.To("tweet", Tweet.Type). Unique(). Required(). Field("tweet_id"), + edge.To("user", User.Type). + Unique(). + Required(). + Field("user_id"), } } diff --git a/entc/integration/edgeschema/ent/tweetlike.go b/entc/integration/edgeschema/ent/tweetlike.go index 106250e4b..14d91a386 100644 --- a/entc/integration/edgeschema/ent/tweetlike.go +++ b/entc/integration/edgeschema/ent/tweetlike.go @@ -33,33 +33,19 @@ type TweetLike struct { // TweetLikeEdges holds the relations/edges for other nodes in the graph. type TweetLikeEdges struct { - // User holds the value of the user edge. - User *User `json:"user,omitempty"` // Tweet holds the value of the tweet edge. Tweet *Tweet `json:"tweet,omitempty"` + // User holds the value of the user edge. + User *User `json:"user,omitempty"` // loadedTypes holds the information for reporting if a // type was loaded (or requested) in eager-loading or not. loadedTypes [2]bool } -// UserOrErr returns the User value or an error if the edge -// was not loaded in eager-loading, or loaded but was not found. -func (e TweetLikeEdges) UserOrErr() (*User, error) { - if e.loadedTypes[0] { - if e.User == nil { - // The edge user was loaded in eager-loading, - // but was not found. - return nil, &NotFoundError{label: user.Label} - } - return e.User, nil - } - return nil, &NotLoadedError{edge: "user"} -} - // TweetOrErr returns the Tweet value or an error if the edge // was not loaded in eager-loading, or loaded but was not found. func (e TweetLikeEdges) TweetOrErr() (*Tweet, error) { - if e.loadedTypes[1] { + if e.loadedTypes[0] { if e.Tweet == nil { // The edge tweet was loaded in eager-loading, // but was not found. @@ -70,6 +56,20 @@ func (e TweetLikeEdges) TweetOrErr() (*Tweet, error) { return nil, &NotLoadedError{edge: "tweet"} } +// UserOrErr returns the User value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e TweetLikeEdges) UserOrErr() (*User, error) { + if e.loadedTypes[1] { + if e.User == nil { + // The edge user was loaded in eager-loading, + // but was not found. + return nil, &NotFoundError{label: user.Label} + } + return e.User, nil + } + return nil, &NotLoadedError{edge: "user"} +} + // scanValues returns the types for scanning values from sql.Rows. func (*TweetLike) scanValues(columns []string) ([]interface{}, error) { values := make([]interface{}, len(columns)) @@ -117,16 +117,16 @@ func (tl *TweetLike) assignValues(columns []string, values []interface{}) error return nil } -// QueryUser queries the "user" edge of the TweetLike entity. -func (tl *TweetLike) QueryUser() *UserQuery { - return (&TweetLikeClient{config: tl.config}).QueryUser(tl) -} - // QueryTweet queries the "tweet" edge of the TweetLike entity. func (tl *TweetLike) QueryTweet() *TweetQuery { return (&TweetLikeClient{config: tl.config}).QueryTweet(tl) } +// QueryUser queries the "user" edge of the TweetLike entity. +func (tl *TweetLike) QueryUser() *UserQuery { + return (&TweetLikeClient{config: tl.config}).QueryUser(tl) +} + // Update returns a builder for updating this TweetLike. // Note that you need to call TweetLike.Unwrap() before calling this method if this TweetLike // was returned from a transaction, and the transaction was committed or rolled back. diff --git a/entc/integration/edgeschema/ent/tweetlike/tweetlike.go b/entc/integration/edgeschema/ent/tweetlike/tweetlike.go index 045b9ce51..9b1f849a8 100644 --- a/entc/integration/edgeschema/ent/tweetlike/tweetlike.go +++ b/entc/integration/edgeschema/ent/tweetlike/tweetlike.go @@ -19,23 +19,16 @@ const ( FieldUserID = "user_id" // FieldTweetID holds the string denoting the tweet_id field in the database. FieldTweetID = "tweet_id" - // EdgeUser holds the string denoting the user edge name in mutations. - EdgeUser = "user" // EdgeTweet holds the string denoting the tweet edge name in mutations. EdgeTweet = "tweet" - // UserFieldID holds the string denoting the ID field of the User. - UserFieldID = "id" + // EdgeUser holds the string denoting the user edge name in mutations. + EdgeUser = "user" // TweetFieldID holds the string denoting the ID field of the Tweet. TweetFieldID = "id" + // UserFieldID holds the string denoting the ID field of the User. + UserFieldID = "id" // Table holds the table name of the tweetlike in the database. Table = "tweet_likes" - // UserTable is the table that holds the user relation/edge. - UserTable = "tweet_likes" - // UserInverseTable is the table name for the User entity. - // It exists in this package in order to avoid circular dependency with the "user" package. - UserInverseTable = "users" - // UserColumn is the table column denoting the user relation/edge. - UserColumn = "user_id" // TweetTable is the table that holds the tweet relation/edge. TweetTable = "tweet_likes" // TweetInverseTable is the table name for the Tweet entity. @@ -43,6 +36,13 @@ const ( TweetInverseTable = "tweets" // TweetColumn is the table column denoting the tweet relation/edge. TweetColumn = "tweet_id" + // UserTable is the table that holds the user relation/edge. + UserTable = "tweet_likes" + // UserInverseTable is the table name for the User entity. + // It exists in this package in order to avoid circular dependency with the "user" package. + UserInverseTable = "users" + // UserColumn is the table column denoting the user relation/edge. + UserColumn = "user_id" ) // Columns holds all SQL columns for tweetlike fields. diff --git a/entc/integration/edgeschema/ent/tweetlike/where.go b/entc/integration/edgeschema/ent/tweetlike/where.go index 763adeb1e..887992f28 100644 --- a/entc/integration/edgeschema/ent/tweetlike/where.go +++ b/entc/integration/edgeschema/ent/tweetlike/where.go @@ -207,34 +207,6 @@ func TweetIDNotIn(vs ...int) predicate.TweetLike { }) } -// HasUser applies the HasEdge predicate on the "user" edge. -func HasUser() predicate.TweetLike { - return predicate.TweetLike(func(s *sql.Selector) { - step := sqlgraph.NewStep( - sqlgraph.From(Table, UserColumn), - sqlgraph.To(UserInverseTable, UserFieldID), - sqlgraph.Edge(sqlgraph.M2O, false, UserTable, UserColumn), - ) - sqlgraph.HasNeighbors(s, step) - }) -} - -// HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates). -func HasUserWith(preds ...predicate.User) predicate.TweetLike { - return predicate.TweetLike(func(s *sql.Selector) { - step := sqlgraph.NewStep( - sqlgraph.From(Table, UserColumn), - sqlgraph.To(UserInverseTable, UserFieldID), - sqlgraph.Edge(sqlgraph.M2O, false, UserTable, UserColumn), - ) - sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { - for _, p := range preds { - p(s) - } - }) - }) -} - // HasTweet applies the HasEdge predicate on the "tweet" edge. func HasTweet() predicate.TweetLike { return predicate.TweetLike(func(s *sql.Selector) { @@ -263,6 +235,34 @@ func HasTweetWith(preds ...predicate.Tweet) predicate.TweetLike { }) } +// HasUser applies the HasEdge predicate on the "user" edge. +func HasUser() predicate.TweetLike { + return predicate.TweetLike(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, UserColumn), + sqlgraph.To(UserInverseTable, UserFieldID), + sqlgraph.Edge(sqlgraph.M2O, false, UserTable, UserColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates). +func HasUserWith(preds ...predicate.User) predicate.TweetLike { + return predicate.TweetLike(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, UserColumn), + sqlgraph.To(UserInverseTable, UserFieldID), + sqlgraph.Edge(sqlgraph.M2O, false, UserTable, UserColumn), + ) + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + // And groups predicates with the AND operator between them. func And(predicates ...predicate.TweetLike) predicate.TweetLike { return predicate.TweetLike(func(s *sql.Selector) { diff --git a/entc/integration/edgeschema/ent/tweetlike_create.go b/entc/integration/edgeschema/ent/tweetlike_create.go index bc1b02f1f..a8134e466 100644 --- a/entc/integration/edgeschema/ent/tweetlike_create.go +++ b/entc/integration/edgeschema/ent/tweetlike_create.go @@ -54,16 +54,16 @@ func (tlc *TweetLikeCreate) SetTweetID(i int) *TweetLikeCreate { return tlc } -// SetUser sets the "user" edge to the User entity. -func (tlc *TweetLikeCreate) SetUser(u *User) *TweetLikeCreate { - return tlc.SetUserID(u.ID) -} - // SetTweet sets the "tweet" edge to the Tweet entity. func (tlc *TweetLikeCreate) SetTweet(t *Tweet) *TweetLikeCreate { return tlc.SetTweetID(t.ID) } +// SetUser sets the "user" edge to the User entity. +func (tlc *TweetLikeCreate) SetUser(u *User) *TweetLikeCreate { + return tlc.SetUserID(u.ID) +} + // Mutation returns the TweetLikeMutation object of the builder. func (tlc *TweetLikeCreate) Mutation() *TweetLikeMutation { return tlc.mutation @@ -156,12 +156,12 @@ func (tlc *TweetLikeCreate) check() error { if _, ok := tlc.mutation.TweetID(); !ok { return &ValidationError{Name: "tweet_id", err: errors.New(`ent: missing required field "TweetLike.tweet_id"`)} } - if _, ok := tlc.mutation.UserID(); !ok { - return &ValidationError{Name: "user", err: errors.New(`ent: missing required edge "TweetLike.user"`)} - } if _, ok := tlc.mutation.TweetID(); !ok { return &ValidationError{Name: "tweet", err: errors.New(`ent: missing required edge "TweetLike.tweet"`)} } + if _, ok := tlc.mutation.UserID(); !ok { + return &ValidationError{Name: "user", err: errors.New(`ent: missing required edge "TweetLike.user"`)} + } return nil } @@ -192,26 +192,6 @@ func (tlc *TweetLikeCreate) createSpec() (*TweetLike, *sqlgraph.CreateSpec) { }) _node.LikedAt = value } - if nodes := tlc.mutation.UserIDs(); len(nodes) > 0 { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: false, - Table: tweetlike.UserTable, - Columns: []string{tweetlike.UserColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: &sqlgraph.FieldSpec{ - Type: field.TypeInt, - Column: user.FieldID, - }, - }, - } - for _, k := range nodes { - edge.Target.Nodes = append(edge.Target.Nodes, k) - } - _node.UserID = nodes[0] - _spec.Edges = append(_spec.Edges, edge) - } if nodes := tlc.mutation.TweetIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, @@ -232,6 +212,26 @@ func (tlc *TweetLikeCreate) createSpec() (*TweetLike, *sqlgraph.CreateSpec) { _node.TweetID = nodes[0] _spec.Edges = append(_spec.Edges, edge) } + if nodes := tlc.mutation.UserIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: tweetlike.UserTable, + Columns: []string{tweetlike.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: user.FieldID, + }, + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.UserID = nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } return _node, _spec } diff --git a/entc/integration/edgeschema/ent/tweetlike_query.go b/entc/integration/edgeschema/ent/tweetlike_query.go index 1c387b934..b495dbf05 100644 --- a/entc/integration/edgeschema/ent/tweetlike_query.go +++ b/entc/integration/edgeschema/ent/tweetlike_query.go @@ -29,8 +29,8 @@ type TweetLikeQuery struct { fields []string predicates []predicate.TweetLike // eager-loading edges. - withUser *UserQuery withTweet *TweetQuery + withUser *UserQuery // intermediate query (i.e. traversal path). sql *sql.Selector path func(context.Context) (*sql.Selector, error) @@ -67,28 +67,6 @@ func (tlq *TweetLikeQuery) Order(o ...OrderFunc) *TweetLikeQuery { return tlq } -// QueryUser chains the current query on the "user" edge. -func (tlq *TweetLikeQuery) QueryUser() *UserQuery { - query := &UserQuery{config: tlq.config} - query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { - if err := tlq.prepareQuery(ctx); err != nil { - return nil, err - } - selector := tlq.sqlQuery(ctx) - if err := selector.Err(); err != nil { - return nil, err - } - step := sqlgraph.NewStep( - sqlgraph.From(tweetlike.Table, tweetlike.UserColumn, selector), - sqlgraph.To(user.Table, user.FieldID), - sqlgraph.Edge(sqlgraph.M2O, false, tweetlike.UserTable, tweetlike.UserColumn), - ) - fromU = sqlgraph.SetNeighbors(tlq.driver.Dialect(), step) - return fromU, nil - } - return query -} - // QueryTweet chains the current query on the "tweet" edge. func (tlq *TweetLikeQuery) QueryTweet() *TweetQuery { query := &TweetQuery{config: tlq.config} @@ -111,6 +89,28 @@ func (tlq *TweetLikeQuery) QueryTweet() *TweetQuery { return query } +// QueryUser chains the current query on the "user" edge. +func (tlq *TweetLikeQuery) QueryUser() *UserQuery { + query := &UserQuery{config: tlq.config} + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := tlq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := tlq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(tweetlike.Table, tweetlike.UserColumn, selector), + sqlgraph.To(user.Table, user.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, tweetlike.UserTable, tweetlike.UserColumn), + ) + fromU = sqlgraph.SetNeighbors(tlq.driver.Dialect(), step) + return fromU, nil + } + return query +} + // First returns the first TweetLike entity from the query. // Returns a *NotFoundError when no TweetLike was found. func (tlq *TweetLikeQuery) First(ctx context.Context) (*TweetLike, error) { @@ -223,8 +223,8 @@ func (tlq *TweetLikeQuery) Clone() *TweetLikeQuery { offset: tlq.offset, order: append([]OrderFunc{}, tlq.order...), predicates: append([]predicate.TweetLike{}, tlq.predicates...), - withUser: tlq.withUser.Clone(), withTweet: tlq.withTweet.Clone(), + withUser: tlq.withUser.Clone(), // clone intermediate query. sql: tlq.sql.Clone(), path: tlq.path, @@ -232,17 +232,6 @@ func (tlq *TweetLikeQuery) Clone() *TweetLikeQuery { } } -// WithUser tells the query-builder to eager-load the nodes that are connected to -// the "user" edge. The optional arguments are used to configure the query builder of the edge. -func (tlq *TweetLikeQuery) WithUser(opts ...func(*UserQuery)) *TweetLikeQuery { - query := &UserQuery{config: tlq.config} - for _, opt := range opts { - opt(query) - } - tlq.withUser = query - return tlq -} - // WithTweet tells the query-builder to eager-load the nodes that are connected to // the "tweet" edge. The optional arguments are used to configure the query builder of the edge. func (tlq *TweetLikeQuery) WithTweet(opts ...func(*TweetQuery)) *TweetLikeQuery { @@ -254,6 +243,17 @@ func (tlq *TweetLikeQuery) WithTweet(opts ...func(*TweetQuery)) *TweetLikeQuery return tlq } +// WithUser tells the query-builder to eager-load the nodes that are connected to +// the "user" edge. The optional arguments are used to configure the query builder of the edge. +func (tlq *TweetLikeQuery) WithUser(opts ...func(*UserQuery)) *TweetLikeQuery { + query := &UserQuery{config: tlq.config} + for _, opt := range opts { + opt(query) + } + tlq.withUser = query + return tlq +} + // GroupBy is used to group vertices by one or more fields/columns. // It is often used with aggregate functions, like: count, max, mean, min, sum. // @@ -325,8 +325,8 @@ func (tlq *TweetLikeQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*T nodes = []*TweetLike{} _spec = tlq.querySpec() loadedTypes = [2]bool{ - tlq.withUser != nil, tlq.withTweet != nil, + tlq.withUser != nil, } ) _spec.ScanValues = func(columns []string) ([]interface{}, error) { @@ -348,32 +348,6 @@ func (tlq *TweetLikeQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*T return nodes, nil } - if query := tlq.withUser; query != nil { - ids := make([]int, 0, len(nodes)) - nodeids := make(map[int][]*TweetLike) - for i := range nodes { - fk := nodes[i].UserID - if _, ok := nodeids[fk]; !ok { - 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 "user_id" returned %v`, n.ID) - } - for i := range nodes { - nodes[i].Edges.User = n - } - } - } - if query := tlq.withTweet; query != nil { ids := make([]int, 0, len(nodes)) nodeids := make(map[int][]*TweetLike) @@ -400,6 +374,32 @@ func (tlq *TweetLikeQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*T } } + if query := tlq.withUser; query != nil { + ids := make([]int, 0, len(nodes)) + nodeids := make(map[int][]*TweetLike) + for i := range nodes { + fk := nodes[i].UserID + if _, ok := nodeids[fk]; !ok { + 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 "user_id" returned %v`, n.ID) + } + for i := range nodes { + nodes[i].Edges.User = n + } + } + } + return nodes, nil } diff --git a/entc/integration/edgeschema/ent/tweetlike_update.go b/entc/integration/edgeschema/ent/tweetlike_update.go index caf10b885..3cf0995b8 100644 --- a/entc/integration/edgeschema/ent/tweetlike_update.go +++ b/entc/integration/edgeschema/ent/tweetlike_update.go @@ -60,33 +60,33 @@ func (tlu *TweetLikeUpdate) SetTweetID(i int) *TweetLikeUpdate { return tlu } -// SetUser sets the "user" edge to the User entity. -func (tlu *TweetLikeUpdate) SetUser(u *User) *TweetLikeUpdate { - return tlu.SetUserID(u.ID) -} - // SetTweet sets the "tweet" edge to the Tweet entity. func (tlu *TweetLikeUpdate) SetTweet(t *Tweet) *TweetLikeUpdate { return tlu.SetTweetID(t.ID) } +// SetUser sets the "user" edge to the User entity. +func (tlu *TweetLikeUpdate) SetUser(u *User) *TweetLikeUpdate { + return tlu.SetUserID(u.ID) +} + // Mutation returns the TweetLikeMutation object of the builder. func (tlu *TweetLikeUpdate) Mutation() *TweetLikeMutation { return tlu.mutation } -// ClearUser clears the "user" edge to the User entity. -func (tlu *TweetLikeUpdate) ClearUser() *TweetLikeUpdate { - tlu.mutation.ClearUser() - return tlu -} - // ClearTweet clears the "tweet" edge to the Tweet entity. func (tlu *TweetLikeUpdate) ClearTweet() *TweetLikeUpdate { tlu.mutation.ClearTweet() return tlu } +// ClearUser clears the "user" edge to the User entity. +func (tlu *TweetLikeUpdate) ClearUser() *TweetLikeUpdate { + tlu.mutation.ClearUser() + return tlu +} + // Save executes the query and returns the number of nodes affected by the update operation. func (tlu *TweetLikeUpdate) Save(ctx context.Context) (int, error) { var ( @@ -149,12 +149,12 @@ func (tlu *TweetLikeUpdate) ExecX(ctx context.Context) { // check runs all checks and user-defined validators on the builder. func (tlu *TweetLikeUpdate) check() error { - if _, ok := tlu.mutation.UserID(); tlu.mutation.UserCleared() && !ok { - return errors.New(`ent: clearing a required unique edge "TweetLike.user"`) - } if _, ok := tlu.mutation.TweetID(); tlu.mutation.TweetCleared() && !ok { return errors.New(`ent: clearing a required unique edge "TweetLike.tweet"`) } + if _, ok := tlu.mutation.UserID(); tlu.mutation.UserCleared() && !ok { + return errors.New(`ent: clearing a required unique edge "TweetLike.user"`) + } return nil } @@ -179,41 +179,6 @@ func (tlu *TweetLikeUpdate) sqlSave(ctx context.Context) (n int, err error) { Column: tweetlike.FieldLikedAt, }) } - if tlu.mutation.UserCleared() { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: false, - Table: tweetlike.UserTable, - Columns: []string{tweetlike.UserColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: &sqlgraph.FieldSpec{ - Type: field.TypeInt, - Column: user.FieldID, - }, - }, - } - _spec.Edges.Clear = append(_spec.Edges.Clear, edge) - } - if nodes := tlu.mutation.UserIDs(); len(nodes) > 0 { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: false, - Table: tweetlike.UserTable, - Columns: []string{tweetlike.UserColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: &sqlgraph.FieldSpec{ - Type: field.TypeInt, - Column: user.FieldID, - }, - }, - } - for _, k := range nodes { - edge.Target.Nodes = append(edge.Target.Nodes, k) - } - _spec.Edges.Add = append(_spec.Edges.Add, edge) - } if tlu.mutation.TweetCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, @@ -249,6 +214,41 @@ func (tlu *TweetLikeUpdate) sqlSave(ctx context.Context) (n int, err error) { } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if tlu.mutation.UserCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: tweetlike.UserTable, + Columns: []string{tweetlike.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: user.FieldID, + }, + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := tlu.mutation.UserIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: tweetlike.UserTable, + Columns: []string{tweetlike.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: user.FieldID, + }, + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } if n, err = sqlgraph.UpdateNodes(ctx, tlu.driver, _spec); err != nil { if _, ok := err.(*sqlgraph.NotFoundError); ok { err = &NotFoundError{tweetlike.Label} @@ -294,33 +294,33 @@ func (tluo *TweetLikeUpdateOne) SetTweetID(i int) *TweetLikeUpdateOne { return tluo } -// SetUser sets the "user" edge to the User entity. -func (tluo *TweetLikeUpdateOne) SetUser(u *User) *TweetLikeUpdateOne { - return tluo.SetUserID(u.ID) -} - // SetTweet sets the "tweet" edge to the Tweet entity. func (tluo *TweetLikeUpdateOne) SetTweet(t *Tweet) *TweetLikeUpdateOne { return tluo.SetTweetID(t.ID) } +// SetUser sets the "user" edge to the User entity. +func (tluo *TweetLikeUpdateOne) SetUser(u *User) *TweetLikeUpdateOne { + return tluo.SetUserID(u.ID) +} + // Mutation returns the TweetLikeMutation object of the builder. func (tluo *TweetLikeUpdateOne) Mutation() *TweetLikeMutation { return tluo.mutation } -// ClearUser clears the "user" edge to the User entity. -func (tluo *TweetLikeUpdateOne) ClearUser() *TweetLikeUpdateOne { - tluo.mutation.ClearUser() - return tluo -} - // ClearTweet clears the "tweet" edge to the Tweet entity. func (tluo *TweetLikeUpdateOne) ClearTweet() *TweetLikeUpdateOne { tluo.mutation.ClearTweet() return tluo } +// ClearUser clears the "user" edge to the User entity. +func (tluo *TweetLikeUpdateOne) ClearUser() *TweetLikeUpdateOne { + tluo.mutation.ClearUser() + return tluo +} + // Select allows selecting one or more fields (columns) of the returned entity. // The default is selecting all fields defined in the entity schema. func (tluo *TweetLikeUpdateOne) Select(field string, fields ...string) *TweetLikeUpdateOne { @@ -396,12 +396,12 @@ func (tluo *TweetLikeUpdateOne) ExecX(ctx context.Context) { // check runs all checks and user-defined validators on the builder. func (tluo *TweetLikeUpdateOne) check() error { - if _, ok := tluo.mutation.UserID(); tluo.mutation.UserCleared() && !ok { - return errors.New(`ent: clearing a required unique edge "TweetLike.user"`) - } if _, ok := tluo.mutation.TweetID(); tluo.mutation.TweetCleared() && !ok { return errors.New(`ent: clearing a required unique edge "TweetLike.tweet"`) } + if _, ok := tluo.mutation.UserID(); tluo.mutation.UserCleared() && !ok { + return errors.New(`ent: clearing a required unique edge "TweetLike.user"`) + } return nil } @@ -435,41 +435,6 @@ func (tluo *TweetLikeUpdateOne) sqlSave(ctx context.Context) (_node *TweetLike, Column: tweetlike.FieldLikedAt, }) } - if tluo.mutation.UserCleared() { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: false, - Table: tweetlike.UserTable, - Columns: []string{tweetlike.UserColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: &sqlgraph.FieldSpec{ - Type: field.TypeInt, - Column: user.FieldID, - }, - }, - } - _spec.Edges.Clear = append(_spec.Edges.Clear, edge) - } - if nodes := tluo.mutation.UserIDs(); len(nodes) > 0 { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: false, - Table: tweetlike.UserTable, - Columns: []string{tweetlike.UserColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: &sqlgraph.FieldSpec{ - Type: field.TypeInt, - Column: user.FieldID, - }, - }, - } - for _, k := range nodes { - edge.Target.Nodes = append(edge.Target.Nodes, k) - } - _spec.Edges.Add = append(_spec.Edges.Add, edge) - } if tluo.mutation.TweetCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, @@ -505,6 +470,41 @@ func (tluo *TweetLikeUpdateOne) sqlSave(ctx context.Context) (_node *TweetLike, } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if tluo.mutation.UserCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: tweetlike.UserTable, + Columns: []string{tweetlike.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: user.FieldID, + }, + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := tluo.mutation.UserIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: tweetlike.UserTable, + Columns: []string{tweetlike.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: user.FieldID, + }, + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } _node = &TweetLike{config: tluo.config} _spec.Assign = _node.assignValues _spec.ScanValues = _node.scanValues