From 53bdc325c027ba1787953156a97e4da5c8ee89b7 Mon Sep 17 00:00:00 2001 From: Ariel Mashraki <7413593+a8m@users.noreply.github.com> Date: Sat, 12 Nov 2022 21:42:57 +0200 Subject: [PATCH] entc/gen/schemaconfig: set alternate edge-schema names from config (#3087) Fixed https://github.com/ent/ent/issues/3082 --- entc/gen/template.go | 1 + .../dialect/sql/feature/schemaconfig.tmpl | 23 +- entc/gen/template/dialect/sql/query.tmpl | 9 +- entc/integration/multischema/ent/client.go | 195 ++++- entc/integration/multischema/ent/config.go | 7 +- entc/integration/multischema/ent/ent.go | 8 +- .../integration/multischema/ent/friendship.go | 188 ++++ .../multischema/ent/friendship/friendship.go | 72 ++ .../multischema/ent/friendship/where.go | 415 +++++++++ .../multischema/ent/friendship_create.go | 348 ++++++++ .../multischema/ent/friendship_delete.go | 122 +++ .../multischema/ent/friendship_query.go | 729 ++++++++++++++++ .../multischema/ent/friendship_update.go | 393 +++++++++ .../multischema/ent/group_query.go | 1 + entc/integration/multischema/ent/hook/hook.go | 13 + .../multischema/ent/internal/schemaconfig.go | 1 + .../multischema/ent/migrate/schema.go | 43 + entc/integration/multischema/ent/mutation.go | 816 +++++++++++++++++- .../multischema/ent/predicate/predicate.go | 3 + entc/integration/multischema/ent/runtime.go | 13 + .../multischema/ent/schema/friendship.go | 56 ++ .../multischema/ent/schema/user.go | 2 + entc/integration/multischema/ent/tx.go | 5 +- entc/integration/multischema/ent/user.go | 34 +- entc/integration/multischema/ent/user/user.go | 16 + .../integration/multischema/ent/user/where.go | 68 ++ .../multischema/ent/user_create.go | 75 ++ .../integration/multischema/ent/user_query.go | 214 ++++- .../multischema/ent/user_update.go | 397 +++++++++ .../multischema/multischema_test.go | 27 +- 30 files changed, 4225 insertions(+), 69 deletions(-) create mode 100644 entc/integration/multischema/ent/friendship.go create mode 100644 entc/integration/multischema/ent/friendship/friendship.go create mode 100644 entc/integration/multischema/ent/friendship/where.go create mode 100644 entc/integration/multischema/ent/friendship_create.go create mode 100644 entc/integration/multischema/ent/friendship_delete.go create mode 100644 entc/integration/multischema/ent/friendship_query.go create mode 100644 entc/integration/multischema/ent/friendship_update.go create mode 100644 entc/integration/multischema/ent/schema/friendship.go diff --git a/entc/gen/template.go b/entc/gen/template.go index b1a1d4a12..917980a10 100644 --- a/entc/gen/template.go +++ b/entc/gen/template.go @@ -191,6 +191,7 @@ var ( "dialect/sql/query/all/nodes/*", "dialect/sql/query/from/*", "dialect/sql/query/path/*", + "dialect/sql/query/*/*/*", "import/additional/*", "model/additional/*", "model/comment/additional/*", diff --git a/entc/gen/template/dialect/sql/feature/schemaconfig.tmpl b/entc/gen/template/dialect/sql/feature/schemaconfig.tmpl index 696f54c43..34ee356f5 100644 --- a/entc/gen/template/dialect/sql/feature/schemaconfig.tmpl +++ b/entc/gen/template/dialect/sql/feature/schemaconfig.tmpl @@ -4,6 +4,8 @@ This source code is licensed under the Apache 2.0 license found in the LICENSE file in the root directory of this source tree. */}} +{{/* gotype: entgo.io/ent/entc/gen.Graph */}} + {{- define "dialect/sql/internal/schemaconfig" -}} {{ with extend $ "Package" "internal" -}} {{ template "header" . }} @@ -16,7 +18,8 @@ type SchemaConfig struct { {{- range $n := $.Nodes }} {{ $n.Name }} string // {{ $n.Name }} table. {{- range $e := $n.Edges }} - {{- if and $e.M2M (not $e.Inverse) }} + {{- /* Skip adding join-table in case the edge is inverse or already defined as an edge-schema. */}} + {{- if and $e.M2M (not $e.Inverse) (not $e.Through) }} {{ $n.Name }}{{ $e.StructField }} string // {{ $n.Name }}-{{ $e.Name }}->{{ $e.Type.Name }} table. {{- end }} {{- end }} @@ -88,8 +91,8 @@ func NewSchemaConfigContext(parent context.Context, config SchemaConfig) context {{- template "dialect/sql/spec/ctxschemaconfig" . }} {{- end }} -{{- define "dialect/sql/query/eagerloading/spec/schemaconfig" }} - {{- with extend $ "Ident" "_spec.Edge" }} +{{- define "dialect/sql/query/eagerloading/join/schemaconfig" }} + {{- with extend $ "Ident" "joinT" "CallSet" true }} {{- template "dialect/sql/defedge/spec/schemaconfig" . }} {{- end }} {{- end }} @@ -104,13 +107,19 @@ func NewSchemaConfigContext(parent context.Context, config SchemaConfig) context {{- if $e.OwnFK }} {{- $schema = $.Name }} {{- else if $e.M2M }} - {{- if $e.Inverse }} + {{- if $e.Through }} + {{- $schema = $e.Through.Name }} + {{- else if $e.Inverse }} {{- $schema = print $e.Type.Name (pascal $e.Inverse) }} {{- else }} {{- $schema = print $.Name $e.StructField }} {{- end }} {{- end }} - {{ $ident }}.Schema = {{ $receiver }}.schemaConfig.{{ $schema }} + {{- if $.Scope.CallSet }} + {{ $ident }}.Schema({{ $receiver }}.schemaConfig.{{ $schema }}) + {{- else }} + {{ $ident }}.Schema = {{ $receiver }}.schemaConfig.{{ $schema }} + {{- end }} {{- end }} {{- end }} @@ -173,7 +182,9 @@ func NewSchemaConfigContext(parent context.Context, config SchemaConfig) context {{- if $e.OwnFK }} {{- $schema = $.Name }} {{- else if $e.M2M }} - {{- if $e.Inverse }} + {{- if $e.Through }} + {{- $schema = $e.Through.Name }} + {{- else if $e.Inverse }} {{- $schema = print $e.Type.Name (pascal $e.Inverse) }} {{- else }} {{- $schema = print $.Name $e.StructField }} diff --git a/entc/gen/template/dialect/sql/query.tmpl b/entc/gen/template/dialect/sql/query.tmpl index 43d1e21e9..aac52031b 100644 --- a/entc/gen/template/dialect/sql/query.tmpl +++ b/entc/gen/template/dialect/sql/query.tmpl @@ -108,6 +108,13 @@ func ({{ $receiver }} *{{ $builder }}) sqlAll(ctx context.Context, hooks ...quer } query.Where(func(s *sql.Selector) { joinT := sql.Table({{ $.Package }}.{{ $e.TableConstant }}) + {{- with $tmpls := matchTemplate "dialect/sql/query/eagerloading/join/*" }} + {{- range $tmpl := $tmpls }} + {{- with extend $ "Edge" $e }} + {{- xtemplate $tmpl . }} + {{- end }} + {{- end }} + {{- end }} {{- $edgeid := print $e.Type.Package "." $e.Type.ID.Constant }} {{- $fk1idx := 1 }}{{- $fk2idx := 0 }}{{ if $e.IsInverse }}{{ $fk1idx = 0 }}{{ $fk2idx = 1 }}{{ end }} s.Join(joinT).On(s.C({{ $edgeid }}), joinT.C({{ $.Package }}.{{ $e.PKConstant }}[{{ $fk1idx }}])) @@ -193,7 +200,7 @@ func ({{ $receiver }} *{{ $builder }}) sqlAll(ctx context.Context, hooks ...quer nodeids[nodes[i].ID] = nodes[i] {{- if $e.O2M }} if init != nil { - init(nodes[i]) + init(nodes[i]) } {{- end }} } diff --git a/entc/integration/multischema/ent/client.go b/entc/integration/multischema/ent/client.go index 848b488fb..1e7c49534 100644 --- a/entc/integration/multischema/ent/client.go +++ b/entc/integration/multischema/ent/client.go @@ -14,6 +14,7 @@ import ( "entgo.io/ent/entc/integration/multischema/ent/migrate" + "entgo.io/ent/entc/integration/multischema/ent/friendship" "entgo.io/ent/entc/integration/multischema/ent/group" "entgo.io/ent/entc/integration/multischema/ent/pet" "entgo.io/ent/entc/integration/multischema/ent/user" @@ -28,6 +29,8 @@ type Client struct { config // Schema is the client for creating, migrating and dropping schema. Schema *migrate.Schema + // Friendship is the client for interacting with the Friendship builders. + Friendship *FriendshipClient // Group is the client for interacting with the Group builders. Group *GroupClient // Pet is the client for interacting with the Pet builders. @@ -47,6 +50,7 @@ func NewClient(opts ...Option) *Client { func (c *Client) init() { c.Schema = migrate.NewSchema(c.driver) + c.Friendship = NewFriendshipClient(c.config) c.Group = NewGroupClient(c.config) c.Pet = NewPetClient(c.config) c.User = NewUserClient(c.config) @@ -81,11 +85,12 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) { cfg := c.config cfg.driver = tx return &Tx{ - ctx: ctx, - config: cfg, - Group: NewGroupClient(cfg), - Pet: NewPetClient(cfg), - User: NewUserClient(cfg), + ctx: ctx, + config: cfg, + Friendship: NewFriendshipClient(cfg), + Group: NewGroupClient(cfg), + Pet: NewPetClient(cfg), + User: NewUserClient(cfg), }, nil } @@ -103,18 +108,19 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) cfg := c.config cfg.driver = &txDriver{tx: tx, drv: c.driver} return &Tx{ - ctx: ctx, - config: cfg, - Group: NewGroupClient(cfg), - Pet: NewPetClient(cfg), - User: NewUserClient(cfg), + ctx: ctx, + config: cfg, + Friendship: NewFriendshipClient(cfg), + Group: NewGroupClient(cfg), + Pet: NewPetClient(cfg), + User: NewUserClient(cfg), }, nil } // Debug returns a new debug-client. It's used to get verbose logging on specific operations. // // client.Debug(). -// Group. +// Friendship. // Query(). // Count(ctx) func (c *Client) Debug() *Client { @@ -136,11 +142,140 @@ func (c *Client) Close() error { // Use adds the mutation hooks to all the entity clients. // In order to add hooks to a specific client, call: `client.Node.Use(...)`. func (c *Client) Use(hooks ...Hook) { + c.Friendship.Use(hooks...) c.Group.Use(hooks...) c.Pet.Use(hooks...) c.User.Use(hooks...) } +// FriendshipClient is a client for the Friendship schema. +type FriendshipClient struct { + config +} + +// NewFriendshipClient returns a client for the Friendship from the given config. +func NewFriendshipClient(c config) *FriendshipClient { + return &FriendshipClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `friendship.Hooks(f(g(h())))`. +func (c *FriendshipClient) Use(hooks ...Hook) { + c.hooks.Friendship = append(c.hooks.Friendship, hooks...) +} + +// Create returns a builder for creating a Friendship entity. +func (c *FriendshipClient) Create() *FriendshipCreate { + mutation := newFriendshipMutation(c.config, OpCreate) + return &FriendshipCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of Friendship entities. +func (c *FriendshipClient) CreateBulk(builders ...*FriendshipCreate) *FriendshipCreateBulk { + return &FriendshipCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for Friendship. +func (c *FriendshipClient) Update() *FriendshipUpdate { + mutation := newFriendshipMutation(c.config, OpUpdate) + return &FriendshipUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *FriendshipClient) UpdateOne(f *Friendship) *FriendshipUpdateOne { + mutation := newFriendshipMutation(c.config, OpUpdateOne, withFriendship(f)) + return &FriendshipUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *FriendshipClient) UpdateOneID(id int) *FriendshipUpdateOne { + mutation := newFriendshipMutation(c.config, OpUpdateOne, withFriendshipID(id)) + return &FriendshipUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for Friendship. +func (c *FriendshipClient) Delete() *FriendshipDelete { + mutation := newFriendshipMutation(c.config, OpDelete) + return &FriendshipDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *FriendshipClient) DeleteOne(f *Friendship) *FriendshipDeleteOne { + return c.DeleteOneID(f.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *FriendshipClient) DeleteOneID(id int) *FriendshipDeleteOne { + builder := c.Delete().Where(friendship.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &FriendshipDeleteOne{builder} +} + +// Query returns a query builder for Friendship. +func (c *FriendshipClient) Query() *FriendshipQuery { + return &FriendshipQuery{ + config: c.config, + } +} + +// Get returns a Friendship entity by its id. +func (c *FriendshipClient) Get(ctx context.Context, id int) (*Friendship, error) { + return c.Query().Where(friendship.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *FriendshipClient) GetX(ctx context.Context, id int) *Friendship { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryUser queries the user edge of a Friendship. +func (c *FriendshipClient) QueryUser(f *Friendship) *UserQuery { + query := &UserQuery{config: c.config} + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := f.ID + step := sqlgraph.NewStep( + sqlgraph.From(friendship.Table, friendship.FieldID, id), + sqlgraph.To(user.Table, user.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, friendship.UserTable, friendship.UserColumn), + ) + schemaConfig := f.schemaConfig + step.To.Schema = schemaConfig.User + step.Edge.Schema = schemaConfig.Friendship + fromV = sqlgraph.Neighbors(f.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// QueryFriend queries the friend edge of a Friendship. +func (c *FriendshipClient) QueryFriend(f *Friendship) *UserQuery { + query := &UserQuery{config: c.config} + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := f.ID + step := sqlgraph.NewStep( + sqlgraph.From(friendship.Table, friendship.FieldID, id), + sqlgraph.To(user.Table, user.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, friendship.FriendTable, friendship.FriendColumn), + ) + schemaConfig := f.schemaConfig + step.To.Schema = schemaConfig.User + step.Edge.Schema = schemaConfig.Friendship + fromV = sqlgraph.Neighbors(f.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *FriendshipClient) Hooks() []Hook { + return c.hooks.Friendship +} + // GroupClient is a client for the Group schema. type GroupClient struct { config @@ -482,6 +617,44 @@ func (c *UserClient) QueryGroups(u *User) *GroupQuery { return query } +// QueryFriends queries the friends edge of a User. +func (c *UserClient) QueryFriends(u *User) *UserQuery { + query := &UserQuery{config: c.config} + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := u.ID + step := sqlgraph.NewStep( + sqlgraph.From(user.Table, user.FieldID, id), + sqlgraph.To(user.Table, user.FieldID), + sqlgraph.Edge(sqlgraph.M2M, false, user.FriendsTable, user.FriendsPrimaryKey...), + ) + schemaConfig := u.schemaConfig + step.To.Schema = schemaConfig.User + step.Edge.Schema = schemaConfig.Friendship + fromV = sqlgraph.Neighbors(u.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// QueryFriendships queries the friendships edge of a User. +func (c *UserClient) QueryFriendships(u *User) *FriendshipQuery { + query := &FriendshipQuery{config: c.config} + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := u.ID + step := sqlgraph.NewStep( + sqlgraph.From(user.Table, user.FieldID, id), + sqlgraph.To(friendship.Table, friendship.FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, user.FriendshipsTable, user.FriendshipsColumn), + ) + schemaConfig := u.schemaConfig + step.To.Schema = schemaConfig.Friendship + step.Edge.Schema = schemaConfig.Friendship + fromV = sqlgraph.Neighbors(u.driver.Dialect(), step) + return fromV, nil + } + return query +} + // Hooks returns the client hooks. func (c *UserClient) Hooks() []Hook { return c.hooks.User diff --git a/entc/integration/multischema/ent/config.go b/entc/integration/multischema/ent/config.go index 50a60dd08..b1366818c 100644 --- a/entc/integration/multischema/ent/config.go +++ b/entc/integration/multischema/ent/config.go @@ -33,9 +33,10 @@ type config struct { // hooks per client, for fast access. type hooks struct { - Group []ent.Hook - Pet []ent.Hook - User []ent.Hook + Friendship []ent.Hook + Group []ent.Hook + Pet []ent.Hook + User []ent.Hook } // Options applies the options on the config object. diff --git a/entc/integration/multischema/ent/ent.go b/entc/integration/multischema/ent/ent.go index b150c53be..e7ef7b99d 100644 --- a/entc/integration/multischema/ent/ent.go +++ b/entc/integration/multischema/ent/ent.go @@ -14,6 +14,7 @@ import ( "entgo.io/ent" "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/entc/integration/multischema/ent/friendship" "entgo.io/ent/entc/integration/multischema/ent/group" "entgo.io/ent/entc/integration/multischema/ent/pet" "entgo.io/ent/entc/integration/multischema/ent/user" @@ -37,9 +38,10 @@ type OrderFunc func(*sql.Selector) // columnChecker returns a function indicates if the column exists in the given column. func columnChecker(table string) func(string) error { checks := map[string]func(string) bool{ - group.Table: group.ValidColumn, - pet.Table: pet.ValidColumn, - user.Table: user.ValidColumn, + friendship.Table: friendship.ValidColumn, + group.Table: group.ValidColumn, + pet.Table: pet.ValidColumn, + user.Table: user.ValidColumn, } check, ok := checks[table] if !ok { diff --git a/entc/integration/multischema/ent/friendship.go b/entc/integration/multischema/ent/friendship.go new file mode 100644 index 000000000..64bf9e1da --- /dev/null +++ b/entc/integration/multischema/ent/friendship.go @@ -0,0 +1,188 @@ +// Copyright 2019-present Facebook Inc. All rights reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "fmt" + "strings" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/entc/integration/multischema/ent/friendship" + "entgo.io/ent/entc/integration/multischema/ent/user" +) + +// Friendship is the model entity for the Friendship schema. +type Friendship struct { + config `json:"-"` + // ID of the ent. + ID int `json:"id,omitempty"` + // Weight holds the value of the "weight" field. + Weight int `json:"weight,omitempty"` + // CreatedAt holds the value of the "created_at" field. + CreatedAt time.Time `json:"created_at,omitempty"` + // UserID holds the value of the "user_id" field. + UserID int `json:"user_id,omitempty"` + // FriendID holds the value of the "friend_id" field. + FriendID int `json:"friend_id,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the FriendshipQuery when eager-loading is set. + Edges FriendshipEdges `json:"edges"` +} + +// FriendshipEdges holds the relations/edges for other nodes in the graph. +type FriendshipEdges struct { + // User holds the value of the user edge. + User *User `json:"user,omitempty"` + // Friend holds the value of the friend edge. + Friend *User `json:"friend,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 FriendshipEdges) UserOrErr() (*User, error) { + if e.loadedTypes[0] { + if e.User == nil { + // Edge was loaded but was not found. + return nil, &NotFoundError{label: user.Label} + } + return e.User, nil + } + return nil, &NotLoadedError{edge: "user"} +} + +// FriendOrErr returns the Friend value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e FriendshipEdges) FriendOrErr() (*User, error) { + if e.loadedTypes[1] { + if e.Friend == nil { + // Edge was loaded but was not found. + return nil, &NotFoundError{label: user.Label} + } + return e.Friend, nil + } + return nil, &NotLoadedError{edge: "friend"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*Friendship) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case friendship.FieldID, friendship.FieldWeight, friendship.FieldUserID, friendship.FieldFriendID: + values[i] = new(sql.NullInt64) + case friendship.FieldCreatedAt: + values[i] = new(sql.NullTime) + default: + return nil, fmt.Errorf("unexpected column %q for type Friendship", columns[i]) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the Friendship fields. +func (f *Friendship) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case friendship.FieldID: + value, ok := values[i].(*sql.NullInt64) + if !ok { + return fmt.Errorf("unexpected type %T for field id", value) + } + f.ID = int(value.Int64) + case friendship.FieldWeight: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field weight", values[i]) + } else if value.Valid { + f.Weight = int(value.Int64) + } + case friendship.FieldCreatedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field created_at", values[i]) + } else if value.Valid { + f.CreatedAt = value.Time + } + case friendship.FieldUserID: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field user_id", values[i]) + } else if value.Valid { + f.UserID = int(value.Int64) + } + case friendship.FieldFriendID: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field friend_id", values[i]) + } else if value.Valid { + f.FriendID = int(value.Int64) + } + } + } + return nil +} + +// QueryUser queries the "user" edge of the Friendship entity. +func (f *Friendship) QueryUser() *UserQuery { + return (&FriendshipClient{config: f.config}).QueryUser(f) +} + +// QueryFriend queries the "friend" edge of the Friendship entity. +func (f *Friendship) QueryFriend() *UserQuery { + return (&FriendshipClient{config: f.config}).QueryFriend(f) +} + +// Update returns a builder for updating this Friendship. +// Note that you need to call Friendship.Unwrap() before calling this method if this Friendship +// was returned from a transaction, and the transaction was committed or rolled back. +func (f *Friendship) Update() *FriendshipUpdateOne { + return (&FriendshipClient{config: f.config}).UpdateOne(f) +} + +// Unwrap unwraps the Friendship entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (f *Friendship) Unwrap() *Friendship { + _tx, ok := f.config.driver.(*txDriver) + if !ok { + panic("ent: Friendship is not a transactional entity") + } + f.config.driver = _tx.drv + return f +} + +// String implements the fmt.Stringer. +func (f *Friendship) String() string { + var builder strings.Builder + builder.WriteString("Friendship(") + builder.WriteString(fmt.Sprintf("id=%v, ", f.ID)) + builder.WriteString("weight=") + builder.WriteString(fmt.Sprintf("%v", f.Weight)) + builder.WriteString(", ") + builder.WriteString("created_at=") + builder.WriteString(f.CreatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("user_id=") + builder.WriteString(fmt.Sprintf("%v", f.UserID)) + builder.WriteString(", ") + builder.WriteString("friend_id=") + builder.WriteString(fmt.Sprintf("%v", f.FriendID)) + builder.WriteByte(')') + return builder.String() +} + +// Friendships is a parsable slice of Friendship. +type Friendships []*Friendship + +func (f Friendships) config(cfg config) { + for _i := range f { + f[_i].config = cfg + } +} diff --git a/entc/integration/multischema/ent/friendship/friendship.go b/entc/integration/multischema/ent/friendship/friendship.go new file mode 100644 index 000000000..2c704e783 --- /dev/null +++ b/entc/integration/multischema/ent/friendship/friendship.go @@ -0,0 +1,72 @@ +// Copyright 2019-present Facebook Inc. All rights reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated by ent, DO NOT EDIT. + +package friendship + +import ( + "time" +) + +const ( + // Label holds the string label denoting the friendship type in the database. + Label = "friendship" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldWeight holds the string denoting the weight field in the database. + FieldWeight = "weight" + // FieldCreatedAt holds the string denoting the created_at field in the database. + FieldCreatedAt = "created_at" + // FieldUserID holds the string denoting the user_id field in the database. + FieldUserID = "user_id" + // FieldFriendID holds the string denoting the friend_id field in the database. + FieldFriendID = "friend_id" + // EdgeUser holds the string denoting the user edge name in mutations. + EdgeUser = "user" + // EdgeFriend holds the string denoting the friend edge name in mutations. + EdgeFriend = "friend" + // Table holds the table name of the friendship in the database. + Table = "friendships" + // UserTable is the table that holds the user relation/edge. + UserTable = "friendships" + // 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" + // FriendTable is the table that holds the friend relation/edge. + FriendTable = "friendships" + // FriendInverseTable is the table name for the User entity. + // It exists in this package in order to avoid circular dependency with the "user" package. + FriendInverseTable = "users" + // FriendColumn is the table column denoting the friend relation/edge. + FriendColumn = "friend_id" +) + +// Columns holds all SQL columns for friendship fields. +var Columns = []string{ + FieldID, + FieldWeight, + FieldCreatedAt, + FieldUserID, + FieldFriendID, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +var ( + // DefaultWeight holds the default value on creation for the "weight" field. + DefaultWeight int + // DefaultCreatedAt holds the default value on creation for the "created_at" field. + DefaultCreatedAt func() time.Time +) diff --git a/entc/integration/multischema/ent/friendship/where.go b/entc/integration/multischema/ent/friendship/where.go new file mode 100644 index 000000000..bdf1c5851 --- /dev/null +++ b/entc/integration/multischema/ent/friendship/where.go @@ -0,0 +1,415 @@ +// Copyright 2019-present Facebook Inc. All rights reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated by ent, DO NOT EDIT. + +package friendship + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/entc/integration/multischema/ent/internal" + "entgo.io/ent/entc/integration/multischema/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldID), id)) + }) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldID), id)) + }) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldID), id)) + }) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + v := make([]any, len(ids)) + for i := range v { + v[i] = ids[i] + } + s.Where(sql.In(s.C(FieldID), v...)) + }) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + v := make([]any, len(ids)) + for i := range v { + v[i] = ids[i] + } + s.Where(sql.NotIn(s.C(FieldID), v...)) + }) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldID), id)) + }) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldID), id)) + }) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldID), id)) + }) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldID), id)) + }) +} + +// Weight applies equality check predicate on the "weight" field. It's identical to WeightEQ. +func Weight(v int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldWeight), v)) + }) +} + +// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ. +func CreatedAt(v time.Time) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldCreatedAt), v)) + }) +} + +// UserID applies equality check predicate on the "user_id" field. It's identical to UserIDEQ. +func UserID(v int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldUserID), v)) + }) +} + +// FriendID applies equality check predicate on the "friend_id" field. It's identical to FriendIDEQ. +func FriendID(v int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldFriendID), v)) + }) +} + +// WeightEQ applies the EQ predicate on the "weight" field. +func WeightEQ(v int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldWeight), v)) + }) +} + +// WeightNEQ applies the NEQ predicate on the "weight" field. +func WeightNEQ(v int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldWeight), v)) + }) +} + +// WeightIn applies the In predicate on the "weight" field. +func WeightIn(vs ...int) predicate.Friendship { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.In(s.C(FieldWeight), v...)) + }) +} + +// WeightNotIn applies the NotIn predicate on the "weight" field. +func WeightNotIn(vs ...int) predicate.Friendship { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.NotIn(s.C(FieldWeight), v...)) + }) +} + +// WeightGT applies the GT predicate on the "weight" field. +func WeightGT(v int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldWeight), v)) + }) +} + +// WeightGTE applies the GTE predicate on the "weight" field. +func WeightGTE(v int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldWeight), v)) + }) +} + +// WeightLT applies the LT predicate on the "weight" field. +func WeightLT(v int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldWeight), v)) + }) +} + +// WeightLTE applies the LTE predicate on the "weight" field. +func WeightLTE(v int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldWeight), v)) + }) +} + +// CreatedAtEQ applies the EQ predicate on the "created_at" field. +func CreatedAtEQ(v time.Time) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldCreatedAt), v)) + }) +} + +// CreatedAtNEQ applies the NEQ predicate on the "created_at" field. +func CreatedAtNEQ(v time.Time) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldCreatedAt), v)) + }) +} + +// CreatedAtIn applies the In predicate on the "created_at" field. +func CreatedAtIn(vs ...time.Time) predicate.Friendship { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.In(s.C(FieldCreatedAt), v...)) + }) +} + +// CreatedAtNotIn applies the NotIn predicate on the "created_at" field. +func CreatedAtNotIn(vs ...time.Time) predicate.Friendship { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.NotIn(s.C(FieldCreatedAt), v...)) + }) +} + +// CreatedAtGT applies the GT predicate on the "created_at" field. +func CreatedAtGT(v time.Time) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldCreatedAt), v)) + }) +} + +// CreatedAtGTE applies the GTE predicate on the "created_at" field. +func CreatedAtGTE(v time.Time) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldCreatedAt), v)) + }) +} + +// CreatedAtLT applies the LT predicate on the "created_at" field. +func CreatedAtLT(v time.Time) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldCreatedAt), v)) + }) +} + +// CreatedAtLTE applies the LTE predicate on the "created_at" field. +func CreatedAtLTE(v time.Time) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldCreatedAt), v)) + }) +} + +// UserIDEQ applies the EQ predicate on the "user_id" field. +func UserIDEQ(v int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldUserID), v)) + }) +} + +// UserIDNEQ applies the NEQ predicate on the "user_id" field. +func UserIDNEQ(v int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldUserID), v)) + }) +} + +// UserIDIn applies the In predicate on the "user_id" field. +func UserIDIn(vs ...int) predicate.Friendship { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.In(s.C(FieldUserID), v...)) + }) +} + +// UserIDNotIn applies the NotIn predicate on the "user_id" field. +func UserIDNotIn(vs ...int) predicate.Friendship { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.NotIn(s.C(FieldUserID), v...)) + }) +} + +// FriendIDEQ applies the EQ predicate on the "friend_id" field. +func FriendIDEQ(v int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldFriendID), v)) + }) +} + +// FriendIDNEQ applies the NEQ predicate on the "friend_id" field. +func FriendIDNEQ(v int) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldFriendID), v)) + }) +} + +// FriendIDIn applies the In predicate on the "friend_id" field. +func FriendIDIn(vs ...int) predicate.Friendship { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.In(s.C(FieldFriendID), v...)) + }) +} + +// FriendIDNotIn applies the NotIn predicate on the "friend_id" field. +func FriendIDNotIn(vs ...int) predicate.Friendship { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.NotIn(s.C(FieldFriendID), v...)) + }) +} + +// HasUser applies the HasEdge predicate on the "user" edge. +func HasUser() predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(UserTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, UserTable, UserColumn), + ) + schemaConfig := internal.SchemaConfigFromContext(s.Context()) + step.To.Schema = schemaConfig.User + step.Edge.Schema = schemaConfig.Friendship + 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.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(UserInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, UserTable, UserColumn), + ) + schemaConfig := internal.SchemaConfigFromContext(s.Context()) + step.To.Schema = schemaConfig.User + step.Edge.Schema = schemaConfig.Friendship + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// HasFriend applies the HasEdge predicate on the "friend" edge. +func HasFriend() predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(FriendTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, FriendTable, FriendColumn), + ) + schemaConfig := internal.SchemaConfigFromContext(s.Context()) + step.To.Schema = schemaConfig.User + step.Edge.Schema = schemaConfig.Friendship + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasFriendWith applies the HasEdge predicate on the "friend" edge with a given conditions (other predicates). +func HasFriendWith(preds ...predicate.User) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(FriendInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, FriendTable, FriendColumn), + ) + schemaConfig := internal.SchemaConfigFromContext(s.Context()) + step.To.Schema = schemaConfig.User + step.Edge.Schema = schemaConfig.Friendship + 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.Friendship) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.Friendship) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.Friendship) predicate.Friendship { + return predicate.Friendship(func(s *sql.Selector) { + p(s.Not()) + }) +} diff --git a/entc/integration/multischema/ent/friendship_create.go b/entc/integration/multischema/ent/friendship_create.go new file mode 100644 index 000000000..b151bfd72 --- /dev/null +++ b/entc/integration/multischema/ent/friendship_create.go @@ -0,0 +1,348 @@ +// Copyright 2019-present Facebook Inc. All rights reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/entc/integration/multischema/ent/friendship" + "entgo.io/ent/entc/integration/multischema/ent/user" + "entgo.io/ent/schema/field" +) + +// FriendshipCreate is the builder for creating a Friendship entity. +type FriendshipCreate struct { + config + mutation *FriendshipMutation + hooks []Hook +} + +// SetWeight sets the "weight" field. +func (fc *FriendshipCreate) SetWeight(i int) *FriendshipCreate { + fc.mutation.SetWeight(i) + return fc +} + +// SetNillableWeight sets the "weight" field if the given value is not nil. +func (fc *FriendshipCreate) SetNillableWeight(i *int) *FriendshipCreate { + if i != nil { + fc.SetWeight(*i) + } + return fc +} + +// SetCreatedAt sets the "created_at" field. +func (fc *FriendshipCreate) SetCreatedAt(t time.Time) *FriendshipCreate { + fc.mutation.SetCreatedAt(t) + return fc +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (fc *FriendshipCreate) SetNillableCreatedAt(t *time.Time) *FriendshipCreate { + if t != nil { + fc.SetCreatedAt(*t) + } + return fc +} + +// SetUserID sets the "user_id" field. +func (fc *FriendshipCreate) SetUserID(i int) *FriendshipCreate { + fc.mutation.SetUserID(i) + return fc +} + +// SetFriendID sets the "friend_id" field. +func (fc *FriendshipCreate) SetFriendID(i int) *FriendshipCreate { + fc.mutation.SetFriendID(i) + return fc +} + +// SetUser sets the "user" edge to the User entity. +func (fc *FriendshipCreate) SetUser(u *User) *FriendshipCreate { + return fc.SetUserID(u.ID) +} + +// SetFriend sets the "friend" edge to the User entity. +func (fc *FriendshipCreate) SetFriend(u *User) *FriendshipCreate { + return fc.SetFriendID(u.ID) +} + +// Mutation returns the FriendshipMutation object of the builder. +func (fc *FriendshipCreate) Mutation() *FriendshipMutation { + return fc.mutation +} + +// Save creates the Friendship in the database. +func (fc *FriendshipCreate) Save(ctx context.Context) (*Friendship, error) { + var ( + err error + node *Friendship + ) + fc.defaults() + if len(fc.hooks) == 0 { + if err = fc.check(); err != nil { + return nil, err + } + node, err = fc.sqlSave(ctx) + } else { + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*FriendshipMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err = fc.check(); err != nil { + return nil, err + } + fc.mutation = mutation + if node, err = fc.sqlSave(ctx); err != nil { + return nil, err + } + mutation.id = &node.ID + mutation.done = true + return node, err + }) + for i := len(fc.hooks) - 1; i >= 0; i-- { + if fc.hooks[i] == nil { + return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)") + } + mut = fc.hooks[i](mut) + } + v, err := mut.Mutate(ctx, fc.mutation) + if err != nil { + return nil, err + } + nv, ok := v.(*Friendship) + if !ok { + return nil, fmt.Errorf("unexpected node type %T returned from FriendshipMutation", v) + } + node = nv + } + return node, err +} + +// SaveX calls Save and panics if Save returns an error. +func (fc *FriendshipCreate) SaveX(ctx context.Context) *Friendship { + v, err := fc.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (fc *FriendshipCreate) Exec(ctx context.Context) error { + _, err := fc.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (fc *FriendshipCreate) ExecX(ctx context.Context) { + if err := fc.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (fc *FriendshipCreate) defaults() { + if _, ok := fc.mutation.Weight(); !ok { + v := friendship.DefaultWeight + fc.mutation.SetWeight(v) + } + if _, ok := fc.mutation.CreatedAt(); !ok { + v := friendship.DefaultCreatedAt() + fc.mutation.SetCreatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (fc *FriendshipCreate) check() error { + if _, ok := fc.mutation.Weight(); !ok { + return &ValidationError{Name: "weight", err: errors.New(`ent: missing required field "Friendship.weight"`)} + } + if _, ok := fc.mutation.CreatedAt(); !ok { + return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "Friendship.created_at"`)} + } + if _, ok := fc.mutation.UserID(); !ok { + return &ValidationError{Name: "user_id", err: errors.New(`ent: missing required field "Friendship.user_id"`)} + } + if _, ok := fc.mutation.FriendID(); !ok { + return &ValidationError{Name: "friend_id", err: errors.New(`ent: missing required field "Friendship.friend_id"`)} + } + if _, ok := fc.mutation.UserID(); !ok { + return &ValidationError{Name: "user", err: errors.New(`ent: missing required edge "Friendship.user"`)} + } + if _, ok := fc.mutation.FriendID(); !ok { + return &ValidationError{Name: "friend", err: errors.New(`ent: missing required edge "Friendship.friend"`)} + } + return nil +} + +func (fc *FriendshipCreate) sqlSave(ctx context.Context) (*Friendship, error) { + _node, _spec := fc.createSpec() + if err := sqlgraph.CreateNode(ctx, fc.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + id := _spec.ID.Value.(int64) + _node.ID = int(id) + return _node, nil +} + +func (fc *FriendshipCreate) createSpec() (*Friendship, *sqlgraph.CreateSpec) { + var ( + _node = &Friendship{config: fc.config} + _spec = &sqlgraph.CreateSpec{ + Table: friendship.Table, + ID: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: friendship.FieldID, + }, + } + ) + _spec.Schema = fc.schemaConfig.Friendship + if value, ok := fc.mutation.Weight(); ok { + _spec.SetField(friendship.FieldWeight, field.TypeInt, value) + _node.Weight = value + } + if value, ok := fc.mutation.CreatedAt(); ok { + _spec.SetField(friendship.FieldCreatedAt, field.TypeTime, value) + _node.CreatedAt = value + } + if nodes := fc.mutation.UserIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: friendship.UserTable, + Columns: []string{friendship.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: user.FieldID, + }, + }, + } + edge.Schema = fc.schemaConfig.Friendship + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.UserID = nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + if nodes := fc.mutation.FriendIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: friendship.FriendTable, + Columns: []string{friendship.FriendColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: user.FieldID, + }, + }, + } + edge.Schema = fc.schemaConfig.Friendship + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.FriendID = nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// FriendshipCreateBulk is the builder for creating many Friendship entities in bulk. +type FriendshipCreateBulk struct { + config + builders []*FriendshipCreate +} + +// Save creates the Friendship entities in the database. +func (fcb *FriendshipCreateBulk) Save(ctx context.Context) ([]*Friendship, error) { + specs := make([]*sqlgraph.CreateSpec, len(fcb.builders)) + nodes := make([]*Friendship, len(fcb.builders)) + mutators := make([]Mutator, len(fcb.builders)) + for i := range fcb.builders { + func(i int, root context.Context) { + builder := fcb.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*FriendshipMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + nodes[i], specs[i] = builder.createSpec() + var err error + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, fcb.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, fcb.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + if specs[i].ID.Value != nil { + id := specs[i].ID.Value.(int64) + nodes[i].ID = int(id) + } + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, fcb.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (fcb *FriendshipCreateBulk) SaveX(ctx context.Context) []*Friendship { + v, err := fcb.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (fcb *FriendshipCreateBulk) Exec(ctx context.Context) error { + _, err := fcb.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (fcb *FriendshipCreateBulk) ExecX(ctx context.Context) { + if err := fcb.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/entc/integration/multischema/ent/friendship_delete.go b/entc/integration/multischema/ent/friendship_delete.go new file mode 100644 index 000000000..8f9194a52 --- /dev/null +++ b/entc/integration/multischema/ent/friendship_delete.go @@ -0,0 +1,122 @@ +// Copyright 2019-present Facebook Inc. All rights reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/entc/integration/multischema/ent/friendship" + "entgo.io/ent/entc/integration/multischema/ent/internal" + "entgo.io/ent/entc/integration/multischema/ent/predicate" + "entgo.io/ent/schema/field" +) + +// FriendshipDelete is the builder for deleting a Friendship entity. +type FriendshipDelete struct { + config + hooks []Hook + mutation *FriendshipMutation +} + +// Where appends a list predicates to the FriendshipDelete builder. +func (fd *FriendshipDelete) Where(ps ...predicate.Friendship) *FriendshipDelete { + fd.mutation.Where(ps...) + return fd +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (fd *FriendshipDelete) Exec(ctx context.Context) (int, error) { + var ( + err error + affected int + ) + if len(fd.hooks) == 0 { + affected, err = fd.sqlExec(ctx) + } else { + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*FriendshipMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + fd.mutation = mutation + affected, err = fd.sqlExec(ctx) + mutation.done = true + return affected, err + }) + for i := len(fd.hooks) - 1; i >= 0; i-- { + if fd.hooks[i] == nil { + return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)") + } + mut = fd.hooks[i](mut) + } + if _, err := mut.Mutate(ctx, fd.mutation); err != nil { + return 0, err + } + } + return affected, err +} + +// ExecX is like Exec, but panics if an error occurs. +func (fd *FriendshipDelete) ExecX(ctx context.Context) int { + n, err := fd.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (fd *FriendshipDelete) sqlExec(ctx context.Context) (int, error) { + _spec := &sqlgraph.DeleteSpec{ + Node: &sqlgraph.NodeSpec{ + Table: friendship.Table, + ID: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: friendship.FieldID, + }, + }, + } + _spec.Node.Schema = fd.schemaConfig.Friendship + ctx = internal.NewSchemaConfigContext(ctx, fd.schemaConfig) + if ps := fd.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, fd.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return affected, err +} + +// FriendshipDeleteOne is the builder for deleting a single Friendship entity. +type FriendshipDeleteOne struct { + fd *FriendshipDelete +} + +// Exec executes the deletion query. +func (fdo *FriendshipDeleteOne) Exec(ctx context.Context) error { + n, err := fdo.fd.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{friendship.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (fdo *FriendshipDeleteOne) ExecX(ctx context.Context) { + fdo.fd.ExecX(ctx) +} diff --git a/entc/integration/multischema/ent/friendship_query.go b/entc/integration/multischema/ent/friendship_query.go new file mode 100644 index 000000000..ed74382dd --- /dev/null +++ b/entc/integration/multischema/ent/friendship_query.go @@ -0,0 +1,729 @@ +// Copyright 2019-present Facebook Inc. All rights reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "math" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/entc/integration/multischema/ent/friendship" + "entgo.io/ent/entc/integration/multischema/ent/internal" + "entgo.io/ent/entc/integration/multischema/ent/predicate" + "entgo.io/ent/entc/integration/multischema/ent/user" + "entgo.io/ent/schema/field" +) + +// FriendshipQuery is the builder for querying Friendship entities. +type FriendshipQuery struct { + config + limit *int + offset *int + unique *bool + order []OrderFunc + fields []string + predicates []predicate.Friendship + withUser *UserQuery + withFriend *UserQuery + modifiers []func(*sql.Selector) + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the FriendshipQuery builder. +func (fq *FriendshipQuery) Where(ps ...predicate.Friendship) *FriendshipQuery { + fq.predicates = append(fq.predicates, ps...) + return fq +} + +// Limit adds a limit step to the query. +func (fq *FriendshipQuery) Limit(limit int) *FriendshipQuery { + fq.limit = &limit + return fq +} + +// Offset adds an offset step to the query. +func (fq *FriendshipQuery) Offset(offset int) *FriendshipQuery { + fq.offset = &offset + return fq +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (fq *FriendshipQuery) Unique(unique bool) *FriendshipQuery { + fq.unique = &unique + return fq +} + +// Order adds an order step to the query. +func (fq *FriendshipQuery) Order(o ...OrderFunc) *FriendshipQuery { + fq.order = append(fq.order, o...) + return fq +} + +// QueryUser chains the current query on the "user" edge. +func (fq *FriendshipQuery) QueryUser() *UserQuery { + query := &UserQuery{config: fq.config} + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := fq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := fq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(friendship.Table, friendship.FieldID, selector), + sqlgraph.To(user.Table, user.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, friendship.UserTable, friendship.UserColumn), + ) + schemaConfig := fq.schemaConfig + step.To.Schema = schemaConfig.User + step.Edge.Schema = schemaConfig.Friendship + fromU = sqlgraph.SetNeighbors(fq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// QueryFriend chains the current query on the "friend" edge. +func (fq *FriendshipQuery) QueryFriend() *UserQuery { + query := &UserQuery{config: fq.config} + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := fq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := fq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(friendship.Table, friendship.FieldID, selector), + sqlgraph.To(user.Table, user.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, friendship.FriendTable, friendship.FriendColumn), + ) + schemaConfig := fq.schemaConfig + step.To.Schema = schemaConfig.User + step.Edge.Schema = schemaConfig.Friendship + fromU = sqlgraph.SetNeighbors(fq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first Friendship entity from the query. +// Returns a *NotFoundError when no Friendship was found. +func (fq *FriendshipQuery) First(ctx context.Context) (*Friendship, error) { + nodes, err := fq.Limit(1).All(ctx) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{friendship.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (fq *FriendshipQuery) FirstX(ctx context.Context) *Friendship { + node, err := fq.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first Friendship ID from the query. +// Returns a *NotFoundError when no Friendship ID was found. +func (fq *FriendshipQuery) FirstID(ctx context.Context) (id int, err error) { + var ids []int + if ids, err = fq.Limit(1).IDs(ctx); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{friendship.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (fq *FriendshipQuery) FirstIDX(ctx context.Context) int { + id, err := fq.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single Friendship entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one Friendship entity is found. +// Returns a *NotFoundError when no Friendship entities are found. +func (fq *FriendshipQuery) Only(ctx context.Context) (*Friendship, error) { + nodes, err := fq.Limit(2).All(ctx) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{friendship.Label} + default: + return nil, &NotSingularError{friendship.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (fq *FriendshipQuery) OnlyX(ctx context.Context) *Friendship { + node, err := fq.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only Friendship ID in the query. +// Returns a *NotSingularError when more than one Friendship ID is found. +// Returns a *NotFoundError when no entities are found. +func (fq *FriendshipQuery) OnlyID(ctx context.Context) (id int, err error) { + var ids []int + if ids, err = fq.Limit(2).IDs(ctx); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{friendship.Label} + default: + err = &NotSingularError{friendship.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (fq *FriendshipQuery) OnlyIDX(ctx context.Context) int { + id, err := fq.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of Friendships. +func (fq *FriendshipQuery) All(ctx context.Context) ([]*Friendship, error) { + if err := fq.prepareQuery(ctx); err != nil { + return nil, err + } + return fq.sqlAll(ctx) +} + +// AllX is like All, but panics if an error occurs. +func (fq *FriendshipQuery) AllX(ctx context.Context) []*Friendship { + nodes, err := fq.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of Friendship IDs. +func (fq *FriendshipQuery) IDs(ctx context.Context) ([]int, error) { + var ids []int + if err := fq.Select(friendship.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (fq *FriendshipQuery) IDsX(ctx context.Context) []int { + ids, err := fq.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (fq *FriendshipQuery) Count(ctx context.Context) (int, error) { + if err := fq.prepareQuery(ctx); err != nil { + return 0, err + } + return fq.sqlCount(ctx) +} + +// CountX is like Count, but panics if an error occurs. +func (fq *FriendshipQuery) CountX(ctx context.Context) int { + count, err := fq.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (fq *FriendshipQuery) Exist(ctx context.Context) (bool, error) { + if err := fq.prepareQuery(ctx); err != nil { + return false, err + } + return fq.sqlExist(ctx) +} + +// ExistX is like Exist, but panics if an error occurs. +func (fq *FriendshipQuery) ExistX(ctx context.Context) bool { + exist, err := fq.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the FriendshipQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (fq *FriendshipQuery) Clone() *FriendshipQuery { + if fq == nil { + return nil + } + return &FriendshipQuery{ + config: fq.config, + limit: fq.limit, + offset: fq.offset, + order: append([]OrderFunc{}, fq.order...), + predicates: append([]predicate.Friendship{}, fq.predicates...), + withUser: fq.withUser.Clone(), + withFriend: fq.withFriend.Clone(), + // clone intermediate query. + sql: fq.sql.Clone(), + path: fq.path, + unique: fq.unique, + } +} + +// 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 (fq *FriendshipQuery) WithUser(opts ...func(*UserQuery)) *FriendshipQuery { + query := &UserQuery{config: fq.config} + for _, opt := range opts { + opt(query) + } + fq.withUser = query + return fq +} + +// WithFriend tells the query-builder to eager-load the nodes that are connected to +// the "friend" edge. The optional arguments are used to configure the query builder of the edge. +func (fq *FriendshipQuery) WithFriend(opts ...func(*UserQuery)) *FriendshipQuery { + query := &UserQuery{config: fq.config} + for _, opt := range opts { + opt(query) + } + fq.withFriend = query + return fq +} + +// 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. +// +// Example: +// +// var v []struct { +// Weight int `json:"weight,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.Friendship.Query(). +// GroupBy(friendship.FieldWeight). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (fq *FriendshipQuery) GroupBy(field string, fields ...string) *FriendshipGroupBy { + grbuild := &FriendshipGroupBy{config: fq.config} + grbuild.fields = append([]string{field}, fields...) + grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) { + if err := fq.prepareQuery(ctx); err != nil { + return nil, err + } + return fq.sqlQuery(ctx), nil + } + grbuild.label = friendship.Label + grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// Weight int `json:"weight,omitempty"` +// } +// +// client.Friendship.Query(). +// Select(friendship.FieldWeight). +// Scan(ctx, &v) +func (fq *FriendshipQuery) Select(fields ...string) *FriendshipSelect { + fq.fields = append(fq.fields, fields...) + selbuild := &FriendshipSelect{FriendshipQuery: fq} + selbuild.label = friendship.Label + selbuild.flds, selbuild.scan = &fq.fields, selbuild.Scan + return selbuild +} + +// Aggregate returns a FriendshipSelect configured with the given aggregations. +func (fq *FriendshipQuery) Aggregate(fns ...AggregateFunc) *FriendshipSelect { + return fq.Select().Aggregate(fns...) +} + +func (fq *FriendshipQuery) prepareQuery(ctx context.Context) error { + for _, f := range fq.fields { + if !friendship.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if fq.path != nil { + prev, err := fq.path(ctx) + if err != nil { + return err + } + fq.sql = prev + } + return nil +} + +func (fq *FriendshipQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Friendship, error) { + var ( + nodes = []*Friendship{} + _spec = fq.querySpec() + loadedTypes = [2]bool{ + fq.withUser != nil, + fq.withFriend != nil, + } + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*Friendship).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &Friendship{config: fq.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + return node.assignValues(columns, values) + } + _spec.Node.Schema = fq.schemaConfig.Friendship + ctx = internal.NewSchemaConfigContext(ctx, fq.schemaConfig) + if len(fq.modifiers) > 0 { + _spec.Modifiers = fq.modifiers + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, fq.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + if query := fq.withUser; query != nil { + if err := fq.loadUser(ctx, query, nodes, nil, + func(n *Friendship, e *User) { n.Edges.User = e }); err != nil { + return nil, err + } + } + if query := fq.withFriend; query != nil { + if err := fq.loadFriend(ctx, query, nodes, nil, + func(n *Friendship, e *User) { n.Edges.Friend = e }); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (fq *FriendshipQuery) loadUser(ctx context.Context, query *UserQuery, nodes []*Friendship, init func(*Friendship), assign func(*Friendship, *User)) error { + ids := make([]int, 0, len(nodes)) + nodeids := make(map[int][]*Friendship) + 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 err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "user_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} +func (fq *FriendshipQuery) loadFriend(ctx context.Context, query *UserQuery, nodes []*Friendship, init func(*Friendship), assign func(*Friendship, *User)) error { + ids := make([]int, 0, len(nodes)) + nodeids := make(map[int][]*Friendship) + for i := range nodes { + fk := nodes[i].FriendID + 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 err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "friend_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} + +func (fq *FriendshipQuery) sqlCount(ctx context.Context) (int, error) { + _spec := fq.querySpec() + _spec.Node.Schema = fq.schemaConfig.Friendship + ctx = internal.NewSchemaConfigContext(ctx, fq.schemaConfig) + if len(fq.modifiers) > 0 { + _spec.Modifiers = fq.modifiers + } + _spec.Node.Columns = fq.fields + if len(fq.fields) > 0 { + _spec.Unique = fq.unique != nil && *fq.unique + } + return sqlgraph.CountNodes(ctx, fq.driver, _spec) +} + +func (fq *FriendshipQuery) sqlExist(ctx context.Context) (bool, error) { + switch _, err := fq.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +func (fq *FriendshipQuery) querySpec() *sqlgraph.QuerySpec { + _spec := &sqlgraph.QuerySpec{ + Node: &sqlgraph.NodeSpec{ + Table: friendship.Table, + Columns: friendship.Columns, + ID: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: friendship.FieldID, + }, + }, + From: fq.sql, + Unique: true, + } + if unique := fq.unique; unique != nil { + _spec.Unique = *unique + } + if fields := fq.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, friendship.FieldID) + for i := range fields { + if fields[i] != friendship.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + } + if ps := fq.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := fq.limit; limit != nil { + _spec.Limit = *limit + } + if offset := fq.offset; offset != nil { + _spec.Offset = *offset + } + if ps := fq.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (fq *FriendshipQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(fq.driver.Dialect()) + t1 := builder.Table(friendship.Table) + columns := fq.fields + if len(columns) == 0 { + columns = friendship.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if fq.sql != nil { + selector = fq.sql + selector.Select(selector.Columns(columns...)...) + } + if fq.unique != nil && *fq.unique { + selector.Distinct() + } + t1.Schema(fq.schemaConfig.Friendship) + ctx = internal.NewSchemaConfigContext(ctx, fq.schemaConfig) + selector.WithContext(ctx) + for _, m := range fq.modifiers { + m(selector) + } + for _, p := range fq.predicates { + p(selector) + } + for _, p := range fq.order { + p(selector) + } + if offset := fq.offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := fq.limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// Modify adds a query modifier for attaching custom logic to queries. +func (fq *FriendshipQuery) Modify(modifiers ...func(s *sql.Selector)) *FriendshipSelect { + fq.modifiers = append(fq.modifiers, modifiers...) + return fq.Select() +} + +// FriendshipGroupBy is the group-by builder for Friendship entities. +type FriendshipGroupBy struct { + config + selector + fields []string + fns []AggregateFunc + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (fgb *FriendshipGroupBy) Aggregate(fns ...AggregateFunc) *FriendshipGroupBy { + fgb.fns = append(fgb.fns, fns...) + return fgb +} + +// Scan applies the group-by query and scans the result into the given value. +func (fgb *FriendshipGroupBy) Scan(ctx context.Context, v any) error { + query, err := fgb.path(ctx) + if err != nil { + return err + } + fgb.sql = query + return fgb.sqlScan(ctx, v) +} + +func (fgb *FriendshipGroupBy) sqlScan(ctx context.Context, v any) error { + for _, f := range fgb.fields { + if !friendship.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("invalid field %q for group-by", f)} + } + } + selector := fgb.sqlQuery() + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := fgb.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +func (fgb *FriendshipGroupBy) sqlQuery() *sql.Selector { + selector := fgb.sql.Select() + aggregation := make([]string, 0, len(fgb.fns)) + for _, fn := range fgb.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(fgb.fields)+len(fgb.fns)) + for _, f := range fgb.fields { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + return selector.GroupBy(selector.Columns(fgb.fields...)...) +} + +// FriendshipSelect is the builder for selecting fields of Friendship entities. +type FriendshipSelect struct { + *FriendshipQuery + selector + // intermediate query (i.e. traversal path). + sql *sql.Selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (fs *FriendshipSelect) Aggregate(fns ...AggregateFunc) *FriendshipSelect { + fs.fns = append(fs.fns, fns...) + return fs +} + +// Scan applies the selector query and scans the result into the given value. +func (fs *FriendshipSelect) Scan(ctx context.Context, v any) error { + if err := fs.prepareQuery(ctx); err != nil { + return err + } + fs.sql = fs.FriendshipQuery.sqlQuery(ctx) + return fs.sqlScan(ctx, v) +} + +func (fs *FriendshipSelect) sqlScan(ctx context.Context, v any) error { + aggregation := make([]string, 0, len(fs.fns)) + for _, fn := range fs.fns { + aggregation = append(aggregation, fn(fs.sql)) + } + switch n := len(*fs.selector.flds); { + case n == 0 && len(aggregation) > 0: + fs.sql.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + fs.sql.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := fs.sql.Query() + if err := fs.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// Modify adds a query modifier for attaching custom logic to queries. +func (fs *FriendshipSelect) Modify(modifiers ...func(s *sql.Selector)) *FriendshipSelect { + fs.modifiers = append(fs.modifiers, modifiers...) + return fs +} diff --git a/entc/integration/multischema/ent/friendship_update.go b/entc/integration/multischema/ent/friendship_update.go new file mode 100644 index 000000000..6fea4b241 --- /dev/null +++ b/entc/integration/multischema/ent/friendship_update.go @@ -0,0 +1,393 @@ +// Copyright 2019-present Facebook Inc. All rights reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/entc/integration/multischema/ent/friendship" + "entgo.io/ent/entc/integration/multischema/ent/internal" + "entgo.io/ent/entc/integration/multischema/ent/predicate" + "entgo.io/ent/schema/field" +) + +// FriendshipUpdate is the builder for updating Friendship entities. +type FriendshipUpdate struct { + config + hooks []Hook + mutation *FriendshipMutation + modifiers []func(*sql.UpdateBuilder) +} + +// Where appends a list predicates to the FriendshipUpdate builder. +func (fu *FriendshipUpdate) Where(ps ...predicate.Friendship) *FriendshipUpdate { + fu.mutation.Where(ps...) + return fu +} + +// SetWeight sets the "weight" field. +func (fu *FriendshipUpdate) SetWeight(i int) *FriendshipUpdate { + fu.mutation.ResetWeight() + fu.mutation.SetWeight(i) + return fu +} + +// SetNillableWeight sets the "weight" field if the given value is not nil. +func (fu *FriendshipUpdate) SetNillableWeight(i *int) *FriendshipUpdate { + if i != nil { + fu.SetWeight(*i) + } + return fu +} + +// AddWeight adds i to the "weight" field. +func (fu *FriendshipUpdate) AddWeight(i int) *FriendshipUpdate { + fu.mutation.AddWeight(i) + return fu +} + +// SetCreatedAt sets the "created_at" field. +func (fu *FriendshipUpdate) SetCreatedAt(t time.Time) *FriendshipUpdate { + fu.mutation.SetCreatedAt(t) + return fu +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (fu *FriendshipUpdate) SetNillableCreatedAt(t *time.Time) *FriendshipUpdate { + if t != nil { + fu.SetCreatedAt(*t) + } + return fu +} + +// Mutation returns the FriendshipMutation object of the builder. +func (fu *FriendshipUpdate) Mutation() *FriendshipMutation { + return fu.mutation +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (fu *FriendshipUpdate) Save(ctx context.Context) (int, error) { + var ( + err error + affected int + ) + if len(fu.hooks) == 0 { + if err = fu.check(); err != nil { + return 0, err + } + affected, err = fu.sqlSave(ctx) + } else { + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*FriendshipMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err = fu.check(); err != nil { + return 0, err + } + fu.mutation = mutation + affected, err = fu.sqlSave(ctx) + mutation.done = true + return affected, err + }) + for i := len(fu.hooks) - 1; i >= 0; i-- { + if fu.hooks[i] == nil { + return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)") + } + mut = fu.hooks[i](mut) + } + if _, err := mut.Mutate(ctx, fu.mutation); err != nil { + return 0, err + } + } + return affected, err +} + +// SaveX is like Save, but panics if an error occurs. +func (fu *FriendshipUpdate) SaveX(ctx context.Context) int { + affected, err := fu.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (fu *FriendshipUpdate) Exec(ctx context.Context) error { + _, err := fu.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (fu *FriendshipUpdate) ExecX(ctx context.Context) { + if err := fu.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (fu *FriendshipUpdate) check() error { + if _, ok := fu.mutation.UserID(); fu.mutation.UserCleared() && !ok { + return errors.New(`ent: clearing a required unique edge "Friendship.user"`) + } + if _, ok := fu.mutation.FriendID(); fu.mutation.FriendCleared() && !ok { + return errors.New(`ent: clearing a required unique edge "Friendship.friend"`) + } + return nil +} + +// Modify adds a statement modifier for attaching custom logic to the UPDATE statement. +func (fu *FriendshipUpdate) Modify(modifiers ...func(u *sql.UpdateBuilder)) *FriendshipUpdate { + fu.modifiers = append(fu.modifiers, modifiers...) + return fu +} + +func (fu *FriendshipUpdate) sqlSave(ctx context.Context) (n int, err error) { + _spec := &sqlgraph.UpdateSpec{ + Node: &sqlgraph.NodeSpec{ + Table: friendship.Table, + Columns: friendship.Columns, + ID: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: friendship.FieldID, + }, + }, + } + if ps := fu.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := fu.mutation.Weight(); ok { + _spec.SetField(friendship.FieldWeight, field.TypeInt, value) + } + if value, ok := fu.mutation.AddedWeight(); ok { + _spec.AddField(friendship.FieldWeight, field.TypeInt, value) + } + if value, ok := fu.mutation.CreatedAt(); ok { + _spec.SetField(friendship.FieldCreatedAt, field.TypeTime, value) + } + _spec.Node.Schema = fu.schemaConfig.Friendship + ctx = internal.NewSchemaConfigContext(ctx, fu.schemaConfig) + _spec.AddModifiers(fu.modifiers...) + if n, err = sqlgraph.UpdateNodes(ctx, fu.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{friendship.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + return n, nil +} + +// FriendshipUpdateOne is the builder for updating a single Friendship entity. +type FriendshipUpdateOne struct { + config + fields []string + hooks []Hook + mutation *FriendshipMutation + modifiers []func(*sql.UpdateBuilder) +} + +// SetWeight sets the "weight" field. +func (fuo *FriendshipUpdateOne) SetWeight(i int) *FriendshipUpdateOne { + fuo.mutation.ResetWeight() + fuo.mutation.SetWeight(i) + return fuo +} + +// SetNillableWeight sets the "weight" field if the given value is not nil. +func (fuo *FriendshipUpdateOne) SetNillableWeight(i *int) *FriendshipUpdateOne { + if i != nil { + fuo.SetWeight(*i) + } + return fuo +} + +// AddWeight adds i to the "weight" field. +func (fuo *FriendshipUpdateOne) AddWeight(i int) *FriendshipUpdateOne { + fuo.mutation.AddWeight(i) + return fuo +} + +// SetCreatedAt sets the "created_at" field. +func (fuo *FriendshipUpdateOne) SetCreatedAt(t time.Time) *FriendshipUpdateOne { + fuo.mutation.SetCreatedAt(t) + return fuo +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (fuo *FriendshipUpdateOne) SetNillableCreatedAt(t *time.Time) *FriendshipUpdateOne { + if t != nil { + fuo.SetCreatedAt(*t) + } + return fuo +} + +// Mutation returns the FriendshipMutation object of the builder. +func (fuo *FriendshipUpdateOne) Mutation() *FriendshipMutation { + return fuo.mutation +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (fuo *FriendshipUpdateOne) Select(field string, fields ...string) *FriendshipUpdateOne { + fuo.fields = append([]string{field}, fields...) + return fuo +} + +// Save executes the query and returns the updated Friendship entity. +func (fuo *FriendshipUpdateOne) Save(ctx context.Context) (*Friendship, error) { + var ( + err error + node *Friendship + ) + if len(fuo.hooks) == 0 { + if err = fuo.check(); err != nil { + return nil, err + } + node, err = fuo.sqlSave(ctx) + } else { + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*FriendshipMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err = fuo.check(); err != nil { + return nil, err + } + fuo.mutation = mutation + node, err = fuo.sqlSave(ctx) + mutation.done = true + return node, err + }) + for i := len(fuo.hooks) - 1; i >= 0; i-- { + if fuo.hooks[i] == nil { + return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)") + } + mut = fuo.hooks[i](mut) + } + v, err := mut.Mutate(ctx, fuo.mutation) + if err != nil { + return nil, err + } + nv, ok := v.(*Friendship) + if !ok { + return nil, fmt.Errorf("unexpected node type %T returned from FriendshipMutation", v) + } + node = nv + } + return node, err +} + +// SaveX is like Save, but panics if an error occurs. +func (fuo *FriendshipUpdateOne) SaveX(ctx context.Context) *Friendship { + node, err := fuo.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (fuo *FriendshipUpdateOne) Exec(ctx context.Context) error { + _, err := fuo.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (fuo *FriendshipUpdateOne) ExecX(ctx context.Context) { + if err := fuo.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (fuo *FriendshipUpdateOne) check() error { + if _, ok := fuo.mutation.UserID(); fuo.mutation.UserCleared() && !ok { + return errors.New(`ent: clearing a required unique edge "Friendship.user"`) + } + if _, ok := fuo.mutation.FriendID(); fuo.mutation.FriendCleared() && !ok { + return errors.New(`ent: clearing a required unique edge "Friendship.friend"`) + } + return nil +} + +// Modify adds a statement modifier for attaching custom logic to the UPDATE statement. +func (fuo *FriendshipUpdateOne) Modify(modifiers ...func(u *sql.UpdateBuilder)) *FriendshipUpdateOne { + fuo.modifiers = append(fuo.modifiers, modifiers...) + return fuo +} + +func (fuo *FriendshipUpdateOne) sqlSave(ctx context.Context) (_node *Friendship, err error) { + _spec := &sqlgraph.UpdateSpec{ + Node: &sqlgraph.NodeSpec{ + Table: friendship.Table, + Columns: friendship.Columns, + ID: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: friendship.FieldID, + }, + }, + } + id, ok := fuo.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Friendship.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := fuo.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, friendship.FieldID) + for _, f := range fields { + if !friendship.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != friendship.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := fuo.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := fuo.mutation.Weight(); ok { + _spec.SetField(friendship.FieldWeight, field.TypeInt, value) + } + if value, ok := fuo.mutation.AddedWeight(); ok { + _spec.AddField(friendship.FieldWeight, field.TypeInt, value) + } + if value, ok := fuo.mutation.CreatedAt(); ok { + _spec.SetField(friendship.FieldCreatedAt, field.TypeTime, value) + } + _spec.Node.Schema = fuo.schemaConfig.Friendship + ctx = internal.NewSchemaConfigContext(ctx, fuo.schemaConfig) + _spec.AddModifiers(fuo.modifiers...) + _node = &Friendship{config: fuo.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, fuo.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{friendship.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + return _node, nil +} diff --git a/entc/integration/multischema/ent/group_query.go b/entc/integration/multischema/ent/group_query.go index 102c7c617..fe6ca4d07 100644 --- a/entc/integration/multischema/ent/group_query.go +++ b/entc/integration/multischema/ent/group_query.go @@ -416,6 +416,7 @@ func (gq *GroupQuery) loadUsers(ctx context.Context, query *UserQuery, nodes []* } query.Where(func(s *sql.Selector) { joinT := sql.Table(group.UsersTable) + joinT.Schema(gq.schemaConfig.GroupUsers) s.Join(joinT).On(s.C(user.FieldID), joinT.C(group.UsersPrimaryKey[1])) s.Where(sql.InValues(joinT.C(group.UsersPrimaryKey[0]), edgeIDs...)) columns := s.SelectedColumns() diff --git a/entc/integration/multischema/ent/hook/hook.go b/entc/integration/multischema/ent/hook/hook.go index 800d70158..f7dccd53b 100644 --- a/entc/integration/multischema/ent/hook/hook.go +++ b/entc/integration/multischema/ent/hook/hook.go @@ -13,6 +13,19 @@ import ( "entgo.io/ent/entc/integration/multischema/ent" ) +// The FriendshipFunc type is an adapter to allow the use of ordinary +// function as Friendship mutator. +type FriendshipFunc func(context.Context, *ent.FriendshipMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f FriendshipFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + mv, ok := m.(*ent.FriendshipMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.FriendshipMutation", m) + } + return f(ctx, mv) +} + // The GroupFunc type is an adapter to allow the use of ordinary // function as Group mutator. type GroupFunc func(context.Context, *ent.GroupMutation) (ent.Value, error) diff --git a/entc/integration/multischema/ent/internal/schemaconfig.go b/entc/integration/multischema/ent/internal/schemaconfig.go index 381356777..711db9535 100644 --- a/entc/integration/multischema/ent/internal/schemaconfig.go +++ b/entc/integration/multischema/ent/internal/schemaconfig.go @@ -11,6 +11,7 @@ import "context" // SchemaConfig represents alternative schema names for all tables // that can be passed at runtime. type SchemaConfig struct { + Friendship string // Friendship table. Group string // Group table. GroupUsers string // Group-users->User table. Pet string // Pet table. diff --git a/entc/integration/multischema/ent/migrate/schema.go b/entc/integration/multischema/ent/migrate/schema.go index 7f3579f30..ab543f4ec 100644 --- a/entc/integration/multischema/ent/migrate/schema.go +++ b/entc/integration/multischema/ent/migrate/schema.go @@ -12,6 +12,46 @@ import ( ) var ( + // FriendshipsColumns holds the columns for the "friendships" table. + FriendshipsColumns = []*schema.Column{ + {Name: "id", Type: field.TypeInt, Increment: true}, + {Name: "weight", Type: field.TypeInt, Default: 1}, + {Name: "created_at", Type: field.TypeTime}, + {Name: "user_id", Type: field.TypeInt}, + {Name: "friend_id", Type: field.TypeInt}, + } + // FriendshipsTable holds the schema information for the "friendships" table. + FriendshipsTable = &schema.Table{ + Name: "friendships", + Columns: FriendshipsColumns, + PrimaryKey: []*schema.Column{FriendshipsColumns[0]}, + ForeignKeys: []*schema.ForeignKey{ + { + Symbol: "friendships_users_user", + Columns: []*schema.Column{FriendshipsColumns[3]}, + RefColumns: []*schema.Column{UsersColumns[0]}, + OnDelete: schema.NoAction, + }, + { + Symbol: "friendships_users_friend", + Columns: []*schema.Column{FriendshipsColumns[4]}, + RefColumns: []*schema.Column{UsersColumns[0]}, + OnDelete: schema.NoAction, + }, + }, + Indexes: []*schema.Index{ + { + Name: "friendship_user_id_friend_id", + Unique: true, + Columns: []*schema.Column{FriendshipsColumns[3], FriendshipsColumns[4]}, + }, + { + Name: "friendship_created_at", + Unique: false, + Columns: []*schema.Column{FriendshipsColumns[2]}, + }, + }, + } // GroupsColumns holds the columns for the "groups" table. GroupsColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt, Increment: true}, @@ -81,6 +121,7 @@ var ( } // Tables holds all the tables in the schema. Tables = []*schema.Table{ + FriendshipsTable, GroupsTable, PetsTable, UsersTable, @@ -89,6 +130,8 @@ var ( ) func init() { + FriendshipsTable.ForeignKeys[0].RefTable = UsersTable + FriendshipsTable.ForeignKeys[1].RefTable = UsersTable PetsTable.ForeignKeys[0].RefTable = UsersTable GroupUsersTable.ForeignKeys[0].RefTable = GroupsTable GroupUsersTable.ForeignKeys[1].RefTable = UsersTable diff --git a/entc/integration/multischema/ent/mutation.go b/entc/integration/multischema/ent/mutation.go index 8bf56e6a3..b3cd438c6 100644 --- a/entc/integration/multischema/ent/mutation.go +++ b/entc/integration/multischema/ent/mutation.go @@ -11,7 +11,9 @@ import ( "errors" "fmt" "sync" + "time" + "entgo.io/ent/entc/integration/multischema/ent/friendship" "entgo.io/ent/entc/integration/multischema/ent/group" "entgo.io/ent/entc/integration/multischema/ent/pet" "entgo.io/ent/entc/integration/multischema/ent/predicate" @@ -29,11 +31,619 @@ const ( OpUpdateOne = ent.OpUpdateOne // Node types. - TypeGroup = "Group" - TypePet = "Pet" - TypeUser = "User" + TypeFriendship = "Friendship" + TypeGroup = "Group" + TypePet = "Pet" + TypeUser = "User" ) +// FriendshipMutation represents an operation that mutates the Friendship nodes in the graph. +type FriendshipMutation struct { + config + op Op + typ string + id *int + weight *int + addweight *int + created_at *time.Time + clearedFields map[string]struct{} + user *int + cleareduser bool + friend *int + clearedfriend bool + done bool + oldValue func(context.Context) (*Friendship, error) + predicates []predicate.Friendship +} + +var _ ent.Mutation = (*FriendshipMutation)(nil) + +// friendshipOption allows management of the mutation configuration using functional options. +type friendshipOption func(*FriendshipMutation) + +// newFriendshipMutation creates new mutation for the Friendship entity. +func newFriendshipMutation(c config, op Op, opts ...friendshipOption) *FriendshipMutation { + m := &FriendshipMutation{ + config: c, + op: op, + typ: TypeFriendship, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withFriendshipID sets the ID field of the mutation. +func withFriendshipID(id int) friendshipOption { + return func(m *FriendshipMutation) { + var ( + err error + once sync.Once + value *Friendship + ) + m.oldValue = func(ctx context.Context) (*Friendship, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().Friendship.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withFriendship sets the old Friendship of the mutation. +func withFriendship(node *Friendship) friendshipOption { + return func(m *FriendshipMutation) { + m.oldValue = func(context.Context) (*Friendship, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m FriendshipMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m FriendshipMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *FriendshipMutation) ID() (id int, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *FriendshipMutation) IDs(ctx context.Context) ([]int, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().Friendship.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetWeight sets the "weight" field. +func (m *FriendshipMutation) SetWeight(i int) { + m.weight = &i + m.addweight = nil +} + +// Weight returns the value of the "weight" field in the mutation. +func (m *FriendshipMutation) Weight() (r int, exists bool) { + v := m.weight + if v == nil { + return + } + return *v, true +} + +// OldWeight returns the old "weight" field's value of the Friendship entity. +// If the Friendship object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *FriendshipMutation) OldWeight(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldWeight is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldWeight requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldWeight: %w", err) + } + return oldValue.Weight, nil +} + +// AddWeight adds i to the "weight" field. +func (m *FriendshipMutation) AddWeight(i int) { + if m.addweight != nil { + *m.addweight += i + } else { + m.addweight = &i + } +} + +// AddedWeight returns the value that was added to the "weight" field in this mutation. +func (m *FriendshipMutation) AddedWeight() (r int, exists bool) { + v := m.addweight + if v == nil { + return + } + return *v, true +} + +// ResetWeight resets all changes to the "weight" field. +func (m *FriendshipMutation) ResetWeight() { + m.weight = nil + m.addweight = nil +} + +// SetCreatedAt sets the "created_at" field. +func (m *FriendshipMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *FriendshipMutation) CreatedAt() (r time.Time, exists bool) { + v := m.created_at + if v == nil { + return + } + return *v, true +} + +// OldCreatedAt returns the old "created_at" field's value of the Friendship entity. +// If the Friendship object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *FriendshipMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreatedAt: %w", err) + } + return oldValue.CreatedAt, nil +} + +// ResetCreatedAt resets all changes to the "created_at" field. +func (m *FriendshipMutation) ResetCreatedAt() { + m.created_at = nil +} + +// SetUserID sets the "user_id" field. +func (m *FriendshipMutation) SetUserID(i int) { + m.user = &i +} + +// UserID returns the value of the "user_id" field in the mutation. +func (m *FriendshipMutation) UserID() (r int, exists bool) { + v := m.user + if v == nil { + return + } + return *v, true +} + +// OldUserID returns the old "user_id" field's value of the Friendship entity. +// If the Friendship object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *FriendshipMutation) OldUserID(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUserID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUserID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUserID: %w", err) + } + return oldValue.UserID, nil +} + +// ResetUserID resets all changes to the "user_id" field. +func (m *FriendshipMutation) ResetUserID() { + m.user = nil +} + +// SetFriendID sets the "friend_id" field. +func (m *FriendshipMutation) SetFriendID(i int) { + m.friend = &i +} + +// FriendID returns the value of the "friend_id" field in the mutation. +func (m *FriendshipMutation) FriendID() (r int, exists bool) { + v := m.friend + if v == nil { + return + } + return *v, true +} + +// OldFriendID returns the old "friend_id" field's value of the Friendship entity. +// If the Friendship object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *FriendshipMutation) OldFriendID(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldFriendID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldFriendID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldFriendID: %w", err) + } + return oldValue.FriendID, nil +} + +// ResetFriendID resets all changes to the "friend_id" field. +func (m *FriendshipMutation) ResetFriendID() { + m.friend = nil +} + +// ClearUser clears the "user" edge to the User entity. +func (m *FriendshipMutation) ClearUser() { + m.cleareduser = true +} + +// UserCleared reports if the "user" edge to the User entity was cleared. +func (m *FriendshipMutation) 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 *FriendshipMutation) UserIDs() (ids []int) { + if id := m.user; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetUser resets all changes to the "user" edge. +func (m *FriendshipMutation) ResetUser() { + m.user = nil + m.cleareduser = false +} + +// ClearFriend clears the "friend" edge to the User entity. +func (m *FriendshipMutation) ClearFriend() { + m.clearedfriend = true +} + +// FriendCleared reports if the "friend" edge to the User entity was cleared. +func (m *FriendshipMutation) FriendCleared() bool { + return m.clearedfriend +} + +// FriendIDs returns the "friend" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// FriendID instead. It exists only for internal usage by the builders. +func (m *FriendshipMutation) FriendIDs() (ids []int) { + if id := m.friend; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetFriend resets all changes to the "friend" edge. +func (m *FriendshipMutation) ResetFriend() { + m.friend = nil + m.clearedfriend = false +} + +// Where appends a list predicates to the FriendshipMutation builder. +func (m *FriendshipMutation) Where(ps ...predicate.Friendship) { + m.predicates = append(m.predicates, ps...) +} + +// Op returns the operation name. +func (m *FriendshipMutation) Op() Op { + return m.op +} + +// Type returns the node type of this mutation (Friendship). +func (m *FriendshipMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *FriendshipMutation) Fields() []string { + fields := make([]string, 0, 4) + if m.weight != nil { + fields = append(fields, friendship.FieldWeight) + } + if m.created_at != nil { + fields = append(fields, friendship.FieldCreatedAt) + } + if m.user != nil { + fields = append(fields, friendship.FieldUserID) + } + if m.friend != nil { + fields = append(fields, friendship.FieldFriendID) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *FriendshipMutation) Field(name string) (ent.Value, bool) { + switch name { + case friendship.FieldWeight: + return m.Weight() + case friendship.FieldCreatedAt: + return m.CreatedAt() + case friendship.FieldUserID: + return m.UserID() + case friendship.FieldFriendID: + return m.FriendID() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *FriendshipMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case friendship.FieldWeight: + return m.OldWeight(ctx) + case friendship.FieldCreatedAt: + return m.OldCreatedAt(ctx) + case friendship.FieldUserID: + return m.OldUserID(ctx) + case friendship.FieldFriendID: + return m.OldFriendID(ctx) + } + return nil, fmt.Errorf("unknown Friendship field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *FriendshipMutation) SetField(name string, value ent.Value) error { + switch name { + case friendship.FieldWeight: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetWeight(v) + return nil + case friendship.FieldCreatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreatedAt(v) + return nil + case friendship.FieldUserID: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUserID(v) + return nil + case friendship.FieldFriendID: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetFriendID(v) + return nil + } + return fmt.Errorf("unknown Friendship field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *FriendshipMutation) AddedFields() []string { + var fields []string + if m.addweight != nil { + fields = append(fields, friendship.FieldWeight) + } + return fields +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *FriendshipMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case friendship.FieldWeight: + return m.AddedWeight() + } + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *FriendshipMutation) AddField(name string, value ent.Value) error { + switch name { + case friendship.FieldWeight: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddWeight(v) + return nil + } + return fmt.Errorf("unknown Friendship numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *FriendshipMutation) ClearedFields() []string { + return nil +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *FriendshipMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *FriendshipMutation) ClearField(name string) error { + return fmt.Errorf("unknown Friendship nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *FriendshipMutation) ResetField(name string) error { + switch name { + case friendship.FieldWeight: + m.ResetWeight() + return nil + case friendship.FieldCreatedAt: + m.ResetCreatedAt() + return nil + case friendship.FieldUserID: + m.ResetUserID() + return nil + case friendship.FieldFriendID: + m.ResetFriendID() + return nil + } + return fmt.Errorf("unknown Friendship field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *FriendshipMutation) AddedEdges() []string { + edges := make([]string, 0, 2) + if m.user != nil { + edges = append(edges, friendship.EdgeUser) + } + if m.friend != nil { + edges = append(edges, friendship.EdgeFriend) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *FriendshipMutation) AddedIDs(name string) []ent.Value { + switch name { + case friendship.EdgeUser: + if id := m.user; id != nil { + return []ent.Value{*id} + } + case friendship.EdgeFriend: + if id := m.friend; id != nil { + return []ent.Value{*id} + } + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *FriendshipMutation) RemovedEdges() []string { + edges := make([]string, 0, 2) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *FriendshipMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *FriendshipMutation) ClearedEdges() []string { + edges := make([]string, 0, 2) + if m.cleareduser { + edges = append(edges, friendship.EdgeUser) + } + if m.clearedfriend { + edges = append(edges, friendship.EdgeFriend) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *FriendshipMutation) EdgeCleared(name string) bool { + switch name { + case friendship.EdgeUser: + return m.cleareduser + case friendship.EdgeFriend: + return m.clearedfriend + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *FriendshipMutation) ClearEdge(name string) error { + switch name { + case friendship.EdgeUser: + m.ClearUser() + return nil + case friendship.EdgeFriend: + m.ClearFriend() + return nil + } + return fmt.Errorf("unknown Friendship unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *FriendshipMutation) ResetEdge(name string) error { + switch name { + case friendship.EdgeUser: + m.ResetUser() + return nil + case friendship.EdgeFriend: + m.ResetFriend() + return nil + } + return fmt.Errorf("unknown Friendship edge %s", name) +} + // GroupMutation represents an operation that mutates the Group nodes in the graph. type GroupMutation struct { config @@ -884,20 +1494,26 @@ func (m *PetMutation) ResetEdge(name string) error { // UserMutation represents an operation that mutates the User nodes in the graph. type UserMutation struct { config - op Op - typ string - id *int - name *string - clearedFields map[string]struct{} - pets map[int]struct{} - removedpets map[int]struct{} - clearedpets bool - groups map[int]struct{} - removedgroups map[int]struct{} - clearedgroups bool - done bool - oldValue func(context.Context) (*User, error) - predicates []predicate.User + op Op + typ string + id *int + name *string + clearedFields map[string]struct{} + pets map[int]struct{} + removedpets map[int]struct{} + clearedpets bool + groups map[int]struct{} + removedgroups map[int]struct{} + clearedgroups bool + friends map[int]struct{} + removedfriends map[int]struct{} + clearedfriends bool + friendships map[int]struct{} + removedfriendships map[int]struct{} + clearedfriendships bool + done bool + oldValue func(context.Context) (*User, error) + predicates []predicate.User } var _ ent.Mutation = (*UserMutation)(nil) @@ -1142,6 +1758,114 @@ func (m *UserMutation) ResetGroups() { m.removedgroups = nil } +// AddFriendIDs adds the "friends" edge to the User entity by ids. +func (m *UserMutation) AddFriendIDs(ids ...int) { + if m.friends == nil { + m.friends = make(map[int]struct{}) + } + for i := range ids { + m.friends[ids[i]] = struct{}{} + } +} + +// ClearFriends clears the "friends" edge to the User entity. +func (m *UserMutation) ClearFriends() { + m.clearedfriends = true +} + +// FriendsCleared reports if the "friends" edge to the User entity was cleared. +func (m *UserMutation) FriendsCleared() bool { + return m.clearedfriends +} + +// RemoveFriendIDs removes the "friends" edge to the User entity by IDs. +func (m *UserMutation) RemoveFriendIDs(ids ...int) { + if m.removedfriends == nil { + m.removedfriends = make(map[int]struct{}) + } + for i := range ids { + delete(m.friends, ids[i]) + m.removedfriends[ids[i]] = struct{}{} + } +} + +// RemovedFriends returns the removed IDs of the "friends" edge to the User entity. +func (m *UserMutation) RemovedFriendsIDs() (ids []int) { + for id := range m.removedfriends { + ids = append(ids, id) + } + return +} + +// FriendsIDs returns the "friends" edge IDs in the mutation. +func (m *UserMutation) FriendsIDs() (ids []int) { + for id := range m.friends { + ids = append(ids, id) + } + return +} + +// ResetFriends resets all changes to the "friends" edge. +func (m *UserMutation) ResetFriends() { + m.friends = nil + m.clearedfriends = false + m.removedfriends = nil +} + +// AddFriendshipIDs adds the "friendships" edge to the Friendship entity by ids. +func (m *UserMutation) AddFriendshipIDs(ids ...int) { + if m.friendships == nil { + m.friendships = make(map[int]struct{}) + } + for i := range ids { + m.friendships[ids[i]] = struct{}{} + } +} + +// ClearFriendships clears the "friendships" edge to the Friendship entity. +func (m *UserMutation) ClearFriendships() { + m.clearedfriendships = true +} + +// FriendshipsCleared reports if the "friendships" edge to the Friendship entity was cleared. +func (m *UserMutation) FriendshipsCleared() bool { + return m.clearedfriendships +} + +// RemoveFriendshipIDs removes the "friendships" edge to the Friendship entity by IDs. +func (m *UserMutation) RemoveFriendshipIDs(ids ...int) { + if m.removedfriendships == nil { + m.removedfriendships = make(map[int]struct{}) + } + for i := range ids { + delete(m.friendships, ids[i]) + m.removedfriendships[ids[i]] = struct{}{} + } +} + +// RemovedFriendships returns the removed IDs of the "friendships" edge to the Friendship entity. +func (m *UserMutation) RemovedFriendshipsIDs() (ids []int) { + for id := range m.removedfriendships { + ids = append(ids, id) + } + return +} + +// FriendshipsIDs returns the "friendships" edge IDs in the mutation. +func (m *UserMutation) FriendshipsIDs() (ids []int) { + for id := range m.friendships { + ids = append(ids, id) + } + return +} + +// ResetFriendships resets all changes to the "friendships" edge. +func (m *UserMutation) ResetFriendships() { + m.friendships = nil + m.clearedfriendships = false + m.removedfriendships = nil +} + // Where appends a list predicates to the UserMutation builder. func (m *UserMutation) Where(ps ...predicate.User) { m.predicates = append(m.predicates, ps...) @@ -1260,13 +1984,19 @@ func (m *UserMutation) ResetField(name string) error { // AddedEdges returns all edge names that were set/added in this mutation. func (m *UserMutation) AddedEdges() []string { - edges := make([]string, 0, 2) + edges := make([]string, 0, 4) if m.pets != nil { edges = append(edges, user.EdgePets) } if m.groups != nil { edges = append(edges, user.EdgeGroups) } + if m.friends != nil { + edges = append(edges, user.EdgeFriends) + } + if m.friendships != nil { + edges = append(edges, user.EdgeFriendships) + } return edges } @@ -1286,19 +2016,37 @@ func (m *UserMutation) AddedIDs(name string) []ent.Value { ids = append(ids, id) } return ids + case user.EdgeFriends: + ids := make([]ent.Value, 0, len(m.friends)) + for id := range m.friends { + ids = append(ids, id) + } + return ids + case user.EdgeFriendships: + ids := make([]ent.Value, 0, len(m.friendships)) + for id := range m.friendships { + ids = append(ids, id) + } + return ids } return nil } // RemovedEdges returns all edge names that were removed in this mutation. func (m *UserMutation) RemovedEdges() []string { - edges := make([]string, 0, 2) + edges := make([]string, 0, 4) if m.removedpets != nil { edges = append(edges, user.EdgePets) } if m.removedgroups != nil { edges = append(edges, user.EdgeGroups) } + if m.removedfriends != nil { + edges = append(edges, user.EdgeFriends) + } + if m.removedfriendships != nil { + edges = append(edges, user.EdgeFriendships) + } return edges } @@ -1318,19 +2066,37 @@ func (m *UserMutation) RemovedIDs(name string) []ent.Value { ids = append(ids, id) } return ids + case user.EdgeFriends: + ids := make([]ent.Value, 0, len(m.removedfriends)) + for id := range m.removedfriends { + ids = append(ids, id) + } + return ids + case user.EdgeFriendships: + ids := make([]ent.Value, 0, len(m.removedfriendships)) + for id := range m.removedfriendships { + ids = append(ids, id) + } + return ids } return nil } // ClearedEdges returns all edge names that were cleared in this mutation. func (m *UserMutation) ClearedEdges() []string { - edges := make([]string, 0, 2) + edges := make([]string, 0, 4) if m.clearedpets { edges = append(edges, user.EdgePets) } if m.clearedgroups { edges = append(edges, user.EdgeGroups) } + if m.clearedfriends { + edges = append(edges, user.EdgeFriends) + } + if m.clearedfriendships { + edges = append(edges, user.EdgeFriendships) + } return edges } @@ -1342,6 +2108,10 @@ func (m *UserMutation) EdgeCleared(name string) bool { return m.clearedpets case user.EdgeGroups: return m.clearedgroups + case user.EdgeFriends: + return m.clearedfriends + case user.EdgeFriendships: + return m.clearedfriendships } return false } @@ -1364,6 +2134,12 @@ func (m *UserMutation) ResetEdge(name string) error { case user.EdgeGroups: m.ResetGroups() return nil + case user.EdgeFriends: + m.ResetFriends() + return nil + case user.EdgeFriendships: + m.ResetFriendships() + return nil } return fmt.Errorf("unknown User edge %s", name) } diff --git a/entc/integration/multischema/ent/predicate/predicate.go b/entc/integration/multischema/ent/predicate/predicate.go index 211124fe4..62ec0bbad 100644 --- a/entc/integration/multischema/ent/predicate/predicate.go +++ b/entc/integration/multischema/ent/predicate/predicate.go @@ -10,6 +10,9 @@ import ( "entgo.io/ent/dialect/sql" ) +// Friendship is the predicate function for friendship builders. +type Friendship func(*sql.Selector) + // Group is the predicate function for group builders. type Group func(*sql.Selector) diff --git a/entc/integration/multischema/ent/runtime.go b/entc/integration/multischema/ent/runtime.go index 5d073093e..2a1fc8c0f 100644 --- a/entc/integration/multischema/ent/runtime.go +++ b/entc/integration/multischema/ent/runtime.go @@ -7,6 +7,9 @@ package ent import ( + "time" + + "entgo.io/ent/entc/integration/multischema/ent/friendship" "entgo.io/ent/entc/integration/multischema/ent/group" "entgo.io/ent/entc/integration/multischema/ent/pet" "entgo.io/ent/entc/integration/multischema/ent/schema" @@ -17,6 +20,16 @@ import ( // (default values, validators, hooks and policies) and stitches it // to their package variables. func init() { + friendshipFields := schema.Friendship{}.Fields() + _ = friendshipFields + // friendshipDescWeight is the schema descriptor for weight field. + friendshipDescWeight := friendshipFields[0].Descriptor() + // friendship.DefaultWeight holds the default value on creation for the weight field. + friendship.DefaultWeight = friendshipDescWeight.Default.(int) + // friendshipDescCreatedAt is the schema descriptor for created_at field. + friendshipDescCreatedAt := friendshipFields[1].Descriptor() + // friendship.DefaultCreatedAt holds the default value on creation for the created_at field. + friendship.DefaultCreatedAt = friendshipDescCreatedAt.Default.(func() time.Time) groupFields := schema.Group{}.Fields() _ = groupFields // groupDescName is the schema descriptor for name field. diff --git a/entc/integration/multischema/ent/schema/friendship.go b/entc/integration/multischema/ent/schema/friendship.go new file mode 100644 index 000000000..0a788983c --- /dev/null +++ b/entc/integration/multischema/ent/schema/friendship.go @@ -0,0 +1,56 @@ +// Copyright 2019-present Facebook Inc. All rights reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +package schema + +import ( + "time" + + "entgo.io/ent" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + "entgo.io/ent/schema/index" +) + +// Friendship holds the edge schema definition of the Friendship relationship. +type Friendship struct { + ent.Schema +} + +// Fields of the Friendship. +func (Friendship) Fields() []ent.Field { + return []ent.Field{ + field.Int("weight"). + Default(1), + field.Time("created_at"). + Default(time.Now), + field.Int("user_id"). + Immutable(), + field.Int("friend_id"). + Immutable(), + } +} + +// Edges of the Friendship. +func (Friendship) Edges() []ent.Edge { + return []ent.Edge{ + edge.To("user", User.Type). + Unique(). + Required(). + Immutable(). + Field("user_id"), + edge.To("friend", User.Type). + Unique(). + Required(). + Immutable(). + Field("friend_id"), + } +} + +// Indexes of the Friendship. +func (Friendship) Indexes() []ent.Index { + return []ent.Index{ + index.Fields("created_at"), + } +} diff --git a/entc/integration/multischema/ent/schema/user.go b/entc/integration/multischema/ent/schema/user.go index 6e81f0bcc..842b7ecff 100644 --- a/entc/integration/multischema/ent/schema/user.go +++ b/entc/integration/multischema/ent/schema/user.go @@ -29,5 +29,7 @@ func (User) Edges() []ent.Edge { edge.To("pets", Pet.Type), edge.From("groups", Group.Type). Ref("users"), + edge.To("friends", User.Type). + Through("friendships", Friendship.Type), } } diff --git a/entc/integration/multischema/ent/tx.go b/entc/integration/multischema/ent/tx.go index ae65fd9a8..094af0255 100644 --- a/entc/integration/multischema/ent/tx.go +++ b/entc/integration/multischema/ent/tx.go @@ -16,6 +16,8 @@ import ( // Tx is a transactional client that is created by calling Client.Tx(). type Tx struct { config + // Friendship is the client for interacting with the Friendship builders. + Friendship *FriendshipClient // Group is the client for interacting with the Group builders. Group *GroupClient // Pet is the client for interacting with the Pet builders. @@ -153,6 +155,7 @@ func (tx *Tx) Client() *Client { } func (tx *Tx) init() { + tx.Friendship = NewFriendshipClient(tx.config) tx.Group = NewGroupClient(tx.config) tx.Pet = NewPetClient(tx.config) tx.User = NewUserClient(tx.config) @@ -165,7 +168,7 @@ func (tx *Tx) init() { // of them in order to commit or rollback the transaction. // // If a closed transaction is embedded in one of the generated entities, and the entity -// applies a query, for example: Group.QueryXXX(), the query will be executed +// applies a query, for example: Friendship.QueryXXX(), the query will be executed // through the driver which created this transaction. // // Note that txDriver is not goroutine safe. diff --git a/entc/integration/multischema/ent/user.go b/entc/integration/multischema/ent/user.go index f726a1828..f2f14f662 100644 --- a/entc/integration/multischema/ent/user.go +++ b/entc/integration/multischema/ent/user.go @@ -32,9 +32,13 @@ type UserEdges struct { Pets []*Pet `json:"pets,omitempty"` // Groups holds the value of the groups edge. Groups []*Group `json:"groups,omitempty"` + // Friends holds the value of the friends edge. + Friends []*User `json:"friends,omitempty"` + // Friendships holds the value of the friendships edge. + Friendships []*Friendship `json:"friendships,omitempty"` // loadedTypes holds the information for reporting if a // type was loaded (or requested) in eager-loading or not. - loadedTypes [2]bool + loadedTypes [4]bool } // PetsOrErr returns the Pets value or an error if the edge @@ -55,6 +59,24 @@ func (e UserEdges) GroupsOrErr() ([]*Group, error) { return nil, &NotLoadedError{edge: "groups"} } +// FriendsOrErr returns the Friends value or an error if the edge +// was not loaded in eager-loading. +func (e UserEdges) FriendsOrErr() ([]*User, error) { + if e.loadedTypes[2] { + return e.Friends, nil + } + return nil, &NotLoadedError{edge: "friends"} +} + +// FriendshipsOrErr returns the Friendships value or an error if the edge +// was not loaded in eager-loading. +func (e UserEdges) FriendshipsOrErr() ([]*Friendship, error) { + if e.loadedTypes[3] { + return e.Friendships, nil + } + return nil, &NotLoadedError{edge: "friendships"} +} + // scanValues returns the types for scanning values from sql.Rows. func (*User) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) @@ -106,6 +128,16 @@ func (u *User) QueryGroups() *GroupQuery { return (&UserClient{config: u.config}).QueryGroups(u) } +// QueryFriends queries the "friends" edge of the User entity. +func (u *User) QueryFriends() *UserQuery { + return (&UserClient{config: u.config}).QueryFriends(u) +} + +// QueryFriendships queries the "friendships" edge of the User entity. +func (u *User) QueryFriendships() *FriendshipQuery { + return (&UserClient{config: u.config}).QueryFriendships(u) +} + // Update returns a builder for updating this User. // Note that you need to call User.Unwrap() before calling this method if this User // was returned from a transaction, and the transaction was committed or rolled back. diff --git a/entc/integration/multischema/ent/user/user.go b/entc/integration/multischema/ent/user/user.go index 0cf0d89d4..7d839a046 100644 --- a/entc/integration/multischema/ent/user/user.go +++ b/entc/integration/multischema/ent/user/user.go @@ -17,6 +17,10 @@ const ( EdgePets = "pets" // EdgeGroups holds the string denoting the groups edge name in mutations. EdgeGroups = "groups" + // EdgeFriends holds the string denoting the friends edge name in mutations. + EdgeFriends = "friends" + // EdgeFriendships holds the string denoting the friendships edge name in mutations. + EdgeFriendships = "friendships" // Table holds the table name of the user in the database. Table = "users" // PetsTable is the table that holds the pets relation/edge. @@ -31,6 +35,15 @@ const ( // GroupsInverseTable is the table name for the Group entity. // It exists in this package in order to avoid circular dependency with the "group" package. GroupsInverseTable = "groups" + // FriendsTable is the table that holds the friends relation/edge. The primary key declared below. + FriendsTable = "friendships" + // FriendshipsTable is the table that holds the friendships relation/edge. + FriendshipsTable = "friendships" + // FriendshipsInverseTable is the table name for the Friendship entity. + // It exists in this package in order to avoid circular dependency with the "friendship" package. + FriendshipsInverseTable = "friendships" + // FriendshipsColumn is the table column denoting the friendships relation/edge. + FriendshipsColumn = "user_id" ) // Columns holds all SQL columns for user fields. @@ -43,6 +56,9 @@ var ( // GroupsPrimaryKey and GroupsColumn2 are the table columns denoting the // primary key for the groups relation (M2M). GroupsPrimaryKey = []string{"group_id", "user_id"} + // FriendsPrimaryKey and FriendsColumn2 are the table columns denoting the + // primary key for the friends relation (M2M). + FriendsPrimaryKey = []string{"user_id", "friend_id"} ) // ValidColumn reports if the column name is valid (part of the table columns). diff --git a/entc/integration/multischema/ent/user/where.go b/entc/integration/multischema/ent/user/where.go index 0956ead9c..6dcd17e7f 100644 --- a/entc/integration/multischema/ent/user/where.go +++ b/entc/integration/multischema/ent/user/where.go @@ -258,6 +258,74 @@ func HasGroupsWith(preds ...predicate.Group) predicate.User { }) } +// HasFriends applies the HasEdge predicate on the "friends" edge. +func HasFriends() predicate.User { + return predicate.User(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(FriendsTable, FieldID), + sqlgraph.Edge(sqlgraph.M2M, false, FriendsTable, FriendsPrimaryKey...), + ) + schemaConfig := internal.SchemaConfigFromContext(s.Context()) + step.To.Schema = schemaConfig.User + step.Edge.Schema = schemaConfig.Friendship + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasFriendsWith applies the HasEdge predicate on the "friends" edge with a given conditions (other predicates). +func HasFriendsWith(preds ...predicate.User) predicate.User { + return predicate.User(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2M, false, FriendsTable, FriendsPrimaryKey...), + ) + schemaConfig := internal.SchemaConfigFromContext(s.Context()) + step.To.Schema = schemaConfig.User + step.Edge.Schema = schemaConfig.Friendship + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// HasFriendships applies the HasEdge predicate on the "friendships" edge. +func HasFriendships() predicate.User { + return predicate.User(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(FriendshipsTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, FriendshipsTable, FriendshipsColumn), + ) + schemaConfig := internal.SchemaConfigFromContext(s.Context()) + step.To.Schema = schemaConfig.Friendship + step.Edge.Schema = schemaConfig.Friendship + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasFriendshipsWith applies the HasEdge predicate on the "friendships" edge with a given conditions (other predicates). +func HasFriendshipsWith(preds ...predicate.Friendship) predicate.User { + return predicate.User(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(FriendshipsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, FriendshipsTable, FriendshipsColumn), + ) + schemaConfig := internal.SchemaConfigFromContext(s.Context()) + step.To.Schema = schemaConfig.Friendship + step.Edge.Schema = schemaConfig.Friendship + 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.User) predicate.User { return predicate.User(func(s *sql.Selector) { diff --git a/entc/integration/multischema/ent/user_create.go b/entc/integration/multischema/ent/user_create.go index e49ec028e..af95a074e 100644 --- a/entc/integration/multischema/ent/user_create.go +++ b/entc/integration/multischema/ent/user_create.go @@ -12,6 +12,7 @@ import ( "fmt" "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/entc/integration/multischema/ent/friendship" "entgo.io/ent/entc/integration/multischema/ent/group" "entgo.io/ent/entc/integration/multischema/ent/pet" "entgo.io/ent/entc/integration/multischema/ent/user" @@ -69,6 +70,36 @@ func (uc *UserCreate) AddGroups(g ...*Group) *UserCreate { return uc.AddGroupIDs(ids...) } +// AddFriendIDs adds the "friends" edge to the User entity by IDs. +func (uc *UserCreate) AddFriendIDs(ids ...int) *UserCreate { + uc.mutation.AddFriendIDs(ids...) + return uc +} + +// AddFriends adds the "friends" edges to the User entity. +func (uc *UserCreate) AddFriends(u ...*User) *UserCreate { + ids := make([]int, len(u)) + for i := range u { + ids[i] = u[i].ID + } + return uc.AddFriendIDs(ids...) +} + +// AddFriendshipIDs adds the "friendships" edge to the Friendship entity by IDs. +func (uc *UserCreate) AddFriendshipIDs(ids ...int) *UserCreate { + uc.mutation.AddFriendshipIDs(ids...) + return uc +} + +// AddFriendships adds the "friendships" edges to the Friendship entity. +func (uc *UserCreate) AddFriendships(f ...*Friendship) *UserCreate { + ids := make([]int, len(f)) + for i := range f { + ids[i] = f[i].ID + } + return uc.AddFriendshipIDs(ids...) +} + // Mutation returns the UserMutation object of the builder. func (uc *UserCreate) Mutation() *UserMutation { return uc.mutation @@ -229,6 +260,50 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { } _spec.Edges = append(_spec.Edges, edge) } + if nodes := uc.mutation.FriendsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2M, + Inverse: false, + Table: user.FriendsTable, + Columns: user.FriendsPrimaryKey, + Bidi: true, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: user.FieldID, + }, + }, + } + edge.Schema = uc.schemaConfig.Friendship + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + createE := &FriendshipCreate{config: uc.config, mutation: newFriendshipMutation(uc.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields + _spec.Edges = append(_spec.Edges, edge) + } + if nodes := uc.mutation.FriendshipsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: user.FriendshipsTable, + Columns: []string{user.FriendshipsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: friendship.FieldID, + }, + }, + } + edge.Schema = uc.schemaConfig.Friendship + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges = append(_spec.Edges, edge) + } return _node, _spec } diff --git a/entc/integration/multischema/ent/user_query.go b/entc/integration/multischema/ent/user_query.go index 1c138c3db..d4fb977e7 100644 --- a/entc/integration/multischema/ent/user_query.go +++ b/entc/integration/multischema/ent/user_query.go @@ -14,6 +14,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/entc/integration/multischema/ent/friendship" "entgo.io/ent/entc/integration/multischema/ent/group" "entgo.io/ent/entc/integration/multischema/ent/internal" "entgo.io/ent/entc/integration/multischema/ent/pet" @@ -25,15 +26,17 @@ import ( // UserQuery is the builder for querying User entities. type UserQuery struct { config - limit *int - offset *int - unique *bool - order []OrderFunc - fields []string - predicates []predicate.User - withPets *PetQuery - withGroups *GroupQuery - modifiers []func(*sql.Selector) + limit *int + offset *int + unique *bool + order []OrderFunc + fields []string + predicates []predicate.User + withPets *PetQuery + withGroups *GroupQuery + withFriends *UserQuery + withFriendships *FriendshipQuery + modifiers []func(*sql.Selector) // intermediate query (i.e. traversal path). sql *sql.Selector path func(context.Context) (*sql.Selector, error) @@ -120,6 +123,56 @@ func (uq *UserQuery) QueryGroups() *GroupQuery { return query } +// QueryFriends chains the current query on the "friends" edge. +func (uq *UserQuery) QueryFriends() *UserQuery { + query := &UserQuery{config: uq.config} + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := uq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := uq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(user.Table, user.FieldID, selector), + sqlgraph.To(user.Table, user.FieldID), + sqlgraph.Edge(sqlgraph.M2M, false, user.FriendsTable, user.FriendsPrimaryKey...), + ) + schemaConfig := uq.schemaConfig + step.To.Schema = schemaConfig.User + step.Edge.Schema = schemaConfig.Friendship + fromU = sqlgraph.SetNeighbors(uq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// QueryFriendships chains the current query on the "friendships" edge. +func (uq *UserQuery) QueryFriendships() *FriendshipQuery { + query := &FriendshipQuery{config: uq.config} + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := uq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := uq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(user.Table, user.FieldID, selector), + sqlgraph.To(friendship.Table, friendship.FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, user.FriendshipsTable, user.FriendshipsColumn), + ) + schemaConfig := uq.schemaConfig + step.To.Schema = schemaConfig.Friendship + step.Edge.Schema = schemaConfig.Friendship + fromU = sqlgraph.SetNeighbors(uq.driver.Dialect(), step) + return fromU, nil + } + return query +} + // First returns the first User entity from the query. // Returns a *NotFoundError when no User was found. func (uq *UserQuery) First(ctx context.Context) (*User, error) { @@ -296,13 +349,15 @@ func (uq *UserQuery) Clone() *UserQuery { return nil } return &UserQuery{ - config: uq.config, - limit: uq.limit, - offset: uq.offset, - order: append([]OrderFunc{}, uq.order...), - predicates: append([]predicate.User{}, uq.predicates...), - withPets: uq.withPets.Clone(), - withGroups: uq.withGroups.Clone(), + config: uq.config, + limit: uq.limit, + offset: uq.offset, + order: append([]OrderFunc{}, uq.order...), + predicates: append([]predicate.User{}, uq.predicates...), + withPets: uq.withPets.Clone(), + withGroups: uq.withGroups.Clone(), + withFriends: uq.withFriends.Clone(), + withFriendships: uq.withFriendships.Clone(), // clone intermediate query. sql: uq.sql.Clone(), path: uq.path, @@ -332,6 +387,28 @@ func (uq *UserQuery) WithGroups(opts ...func(*GroupQuery)) *UserQuery { return uq } +// WithFriends tells the query-builder to eager-load the nodes that are connected to +// the "friends" edge. The optional arguments are 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 +} + +// WithFriendships tells the query-builder to eager-load the nodes that are connected to +// the "friendships" edge. The optional arguments are used to configure the query builder of the edge. +func (uq *UserQuery) WithFriendships(opts ...func(*FriendshipQuery)) *UserQuery { + query := &FriendshipQuery{config: uq.config} + for _, opt := range opts { + opt(query) + } + uq.withFriendships = query + return uq +} + // 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. // @@ -405,9 +482,11 @@ func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e var ( nodes = []*User{} _spec = uq.querySpec() - loadedTypes = [2]bool{ + loadedTypes = [4]bool{ uq.withPets != nil, uq.withGroups != nil, + uq.withFriends != nil, + uq.withFriendships != nil, } ) _spec.ScanValues = func(columns []string) ([]any, error) { @@ -447,6 +526,20 @@ func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e return nil, err } } + if query := uq.withFriends; query != nil { + if err := uq.loadFriends(ctx, query, nodes, + func(n *User) { n.Edges.Friends = []*User{} }, + func(n *User, e *User) { n.Edges.Friends = append(n.Edges.Friends, e) }); err != nil { + return nil, err + } + } + if query := uq.withFriendships; query != nil { + if err := uq.loadFriendships(ctx, query, nodes, + func(n *User) { n.Edges.Friendships = []*Friendship{} }, + func(n *User, e *Friendship) { n.Edges.Friendships = append(n.Edges.Friendships, e) }); err != nil { + return nil, err + } + } return nodes, nil } @@ -490,6 +583,7 @@ func (uq *UserQuery) loadGroups(ctx context.Context, query *GroupQuery, nodes [] } query.Where(func(s *sql.Selector) { joinT := sql.Table(user.GroupsTable) + joinT.Schema(uq.schemaConfig.GroupUsers) s.Join(joinT).On(s.C(group.FieldID), joinT.C(user.GroupsPrimaryKey[0])) s.Where(sql.InValues(joinT.C(user.GroupsPrimaryKey[1]), edgeIDs...)) columns := s.SelectedColumns() @@ -535,6 +629,92 @@ func (uq *UserQuery) loadGroups(ctx context.Context, query *GroupQuery, nodes [] } return nil } +func (uq *UserQuery) loadFriends(ctx context.Context, query *UserQuery, nodes []*User, init func(*User), assign func(*User, *User)) error { + edgeIDs := make([]driver.Value, len(nodes)) + byID := make(map[int]*User) + nids := make(map[int]map[*User]struct{}) + for i, node := range nodes { + edgeIDs[i] = node.ID + byID[node.ID] = node + if init != nil { + init(node) + } + } + query.Where(func(s *sql.Selector) { + joinT := sql.Table(user.FriendsTable) + joinT.Schema(uq.schemaConfig.Friendship) + s.Join(joinT).On(s.C(user.FieldID), joinT.C(user.FriendsPrimaryKey[1])) + s.Where(sql.InValues(joinT.C(user.FriendsPrimaryKey[0]), edgeIDs...)) + columns := s.SelectedColumns() + s.Select(joinT.C(user.FriendsPrimaryKey[0])) + s.AppendSelect(columns...) + s.SetDistinct(false) + }) + if err := query.prepareQuery(ctx); err != nil { + return err + } + neighbors, err := query.sqlAll(ctx, func(_ context.Context, spec *sqlgraph.QuerySpec) { + assign := spec.Assign + values := spec.ScanValues + spec.ScanValues = func(columns []string) ([]any, error) { + values, err := values(columns[1:]) + if err != nil { + return nil, err + } + return append([]any{new(sql.NullInt64)}, values...), nil + } + spec.Assign = func(columns []string, values []any) error { + outValue := int(values[0].(*sql.NullInt64).Int64) + inValue := int(values[1].(*sql.NullInt64).Int64) + if nids[inValue] == nil { + nids[inValue] = map[*User]struct{}{byID[outValue]: {}} + return assign(columns[1:], values[1:]) + } + nids[inValue][byID[outValue]] = struct{}{} + return nil + } + }) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nids[n.ID] + if !ok { + return fmt.Errorf(`unexpected "friends" node returned %v`, n.ID) + } + for kn := range nodes { + assign(kn, n) + } + } + return nil +} +func (uq *UserQuery) loadFriendships(ctx context.Context, query *FriendshipQuery, nodes []*User, init func(*User), assign func(*User, *Friendship)) error { + 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] + if init != nil { + init(nodes[i]) + } + } + query.Where(predicate.Friendship(func(s *sql.Selector) { + s.Where(sql.InValues(user.FriendshipsColumn, fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + fk := n.UserID + node, ok := nodeids[fk] + if !ok { + return fmt.Errorf(`unexpected foreign-key "user_id" returned %v for node %v`, fk, n.ID) + } + assign(node, n) + } + return nil +} func (uq *UserQuery) sqlCount(ctx context.Context) (int, error) { _spec := uq.querySpec() diff --git a/entc/integration/multischema/ent/user_update.go b/entc/integration/multischema/ent/user_update.go index e80b79b8e..2a45fcb71 100644 --- a/entc/integration/multischema/ent/user_update.go +++ b/entc/integration/multischema/ent/user_update.go @@ -13,6 +13,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/entc/integration/multischema/ent/friendship" "entgo.io/ent/entc/integration/multischema/ent/group" "entgo.io/ent/entc/integration/multischema/ent/internal" "entgo.io/ent/entc/integration/multischema/ent/pet" @@ -79,6 +80,36 @@ func (uu *UserUpdate) AddGroups(g ...*Group) *UserUpdate { return uu.AddGroupIDs(ids...) } +// AddFriendIDs adds the "friends" edge to the User entity by IDs. +func (uu *UserUpdate) AddFriendIDs(ids ...int) *UserUpdate { + uu.mutation.AddFriendIDs(ids...) + return uu +} + +// AddFriends adds the "friends" edges to the User entity. +func (uu *UserUpdate) AddFriends(u ...*User) *UserUpdate { + ids := make([]int, len(u)) + for i := range u { + ids[i] = u[i].ID + } + return uu.AddFriendIDs(ids...) +} + +// AddFriendshipIDs adds the "friendships" edge to the Friendship entity by IDs. +func (uu *UserUpdate) AddFriendshipIDs(ids ...int) *UserUpdate { + uu.mutation.AddFriendshipIDs(ids...) + return uu +} + +// AddFriendships adds the "friendships" edges to the Friendship entity. +func (uu *UserUpdate) AddFriendships(f ...*Friendship) *UserUpdate { + ids := make([]int, len(f)) + for i := range f { + ids[i] = f[i].ID + } + return uu.AddFriendshipIDs(ids...) +} + // Mutation returns the UserMutation object of the builder. func (uu *UserUpdate) Mutation() *UserMutation { return uu.mutation @@ -126,6 +157,48 @@ func (uu *UserUpdate) RemoveGroups(g ...*Group) *UserUpdate { return uu.RemoveGroupIDs(ids...) } +// ClearFriends clears all "friends" edges to the User entity. +func (uu *UserUpdate) ClearFriends() *UserUpdate { + uu.mutation.ClearFriends() + return uu +} + +// RemoveFriendIDs removes the "friends" edge to User entities by IDs. +func (uu *UserUpdate) RemoveFriendIDs(ids ...int) *UserUpdate { + uu.mutation.RemoveFriendIDs(ids...) + return uu +} + +// RemoveFriends removes "friends" edges to User entities. +func (uu *UserUpdate) RemoveFriends(u ...*User) *UserUpdate { + ids := make([]int, len(u)) + for i := range u { + ids[i] = u[i].ID + } + return uu.RemoveFriendIDs(ids...) +} + +// ClearFriendships clears all "friendships" edges to the Friendship entity. +func (uu *UserUpdate) ClearFriendships() *UserUpdate { + uu.mutation.ClearFriendships() + return uu +} + +// RemoveFriendshipIDs removes the "friendships" edge to Friendship entities by IDs. +func (uu *UserUpdate) RemoveFriendshipIDs(ids ...int) *UserUpdate { + uu.mutation.RemoveFriendshipIDs(ids...) + return uu +} + +// RemoveFriendships removes "friendships" edges to Friendship entities. +func (uu *UserUpdate) RemoveFriendships(f ...*Friendship) *UserUpdate { + ids := make([]int, len(f)) + for i := range f { + ids[i] = f[i].ID + } + return uu.RemoveFriendshipIDs(ids...) +} + // Save executes the query and returns the number of nodes affected by the update operation. func (uu *UserUpdate) Save(ctx context.Context) (int, error) { var ( @@ -321,6 +394,132 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) { } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if uu.mutation.FriendsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2M, + Inverse: false, + Table: user.FriendsTable, + Columns: user.FriendsPrimaryKey, + Bidi: true, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: user.FieldID, + }, + }, + } + edge.Schema = uu.schemaConfig.Friendship + createE := &FriendshipCreate{config: uu.config, mutation: newFriendshipMutation(uu.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := uu.mutation.RemovedFriendsIDs(); len(nodes) > 0 && !uu.mutation.FriendsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2M, + Inverse: false, + Table: user.FriendsTable, + Columns: user.FriendsPrimaryKey, + Bidi: true, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: user.FieldID, + }, + }, + } + edge.Schema = uu.schemaConfig.Friendship + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + createE := &FriendshipCreate{config: uu.config, mutation: newFriendshipMutation(uu.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := uu.mutation.FriendsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2M, + Inverse: false, + Table: user.FriendsTable, + Columns: user.FriendsPrimaryKey, + Bidi: true, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: user.FieldID, + }, + }, + } + edge.Schema = uu.schemaConfig.Friendship + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + createE := &FriendshipCreate{config: uu.config, mutation: newFriendshipMutation(uu.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if uu.mutation.FriendshipsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: user.FriendshipsTable, + Columns: []string{user.FriendshipsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: friendship.FieldID, + }, + }, + } + edge.Schema = uu.schemaConfig.Friendship + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := uu.mutation.RemovedFriendshipsIDs(); len(nodes) > 0 && !uu.mutation.FriendshipsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: user.FriendshipsTable, + Columns: []string{user.FriendshipsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: friendship.FieldID, + }, + }, + } + edge.Schema = uu.schemaConfig.Friendship + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := uu.mutation.FriendshipsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: user.FriendshipsTable, + Columns: []string{user.FriendshipsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: friendship.FieldID, + }, + }, + } + edge.Schema = uu.schemaConfig.Friendship + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } _spec.Node.Schema = uu.schemaConfig.User ctx = internal.NewSchemaConfigContext(ctx, uu.schemaConfig) _spec.AddModifiers(uu.modifiers...) @@ -388,6 +587,36 @@ func (uuo *UserUpdateOne) AddGroups(g ...*Group) *UserUpdateOne { return uuo.AddGroupIDs(ids...) } +// AddFriendIDs adds the "friends" edge to the User entity by IDs. +func (uuo *UserUpdateOne) AddFriendIDs(ids ...int) *UserUpdateOne { + uuo.mutation.AddFriendIDs(ids...) + return uuo +} + +// AddFriends adds the "friends" edges to the User entity. +func (uuo *UserUpdateOne) AddFriends(u ...*User) *UserUpdateOne { + ids := make([]int, len(u)) + for i := range u { + ids[i] = u[i].ID + } + return uuo.AddFriendIDs(ids...) +} + +// AddFriendshipIDs adds the "friendships" edge to the Friendship entity by IDs. +func (uuo *UserUpdateOne) AddFriendshipIDs(ids ...int) *UserUpdateOne { + uuo.mutation.AddFriendshipIDs(ids...) + return uuo +} + +// AddFriendships adds the "friendships" edges to the Friendship entity. +func (uuo *UserUpdateOne) AddFriendships(f ...*Friendship) *UserUpdateOne { + ids := make([]int, len(f)) + for i := range f { + ids[i] = f[i].ID + } + return uuo.AddFriendshipIDs(ids...) +} + // Mutation returns the UserMutation object of the builder. func (uuo *UserUpdateOne) Mutation() *UserMutation { return uuo.mutation @@ -435,6 +664,48 @@ func (uuo *UserUpdateOne) RemoveGroups(g ...*Group) *UserUpdateOne { return uuo.RemoveGroupIDs(ids...) } +// ClearFriends clears all "friends" edges to the User entity. +func (uuo *UserUpdateOne) ClearFriends() *UserUpdateOne { + uuo.mutation.ClearFriends() + return uuo +} + +// RemoveFriendIDs removes the "friends" edge to User entities by IDs. +func (uuo *UserUpdateOne) RemoveFriendIDs(ids ...int) *UserUpdateOne { + uuo.mutation.RemoveFriendIDs(ids...) + return uuo +} + +// RemoveFriends removes "friends" edges to User entities. +func (uuo *UserUpdateOne) RemoveFriends(u ...*User) *UserUpdateOne { + ids := make([]int, len(u)) + for i := range u { + ids[i] = u[i].ID + } + return uuo.RemoveFriendIDs(ids...) +} + +// ClearFriendships clears all "friendships" edges to the Friendship entity. +func (uuo *UserUpdateOne) ClearFriendships() *UserUpdateOne { + uuo.mutation.ClearFriendships() + return uuo +} + +// RemoveFriendshipIDs removes the "friendships" edge to Friendship entities by IDs. +func (uuo *UserUpdateOne) RemoveFriendshipIDs(ids ...int) *UserUpdateOne { + uuo.mutation.RemoveFriendshipIDs(ids...) + return uuo +} + +// RemoveFriendships removes "friendships" edges to Friendship entities. +func (uuo *UserUpdateOne) RemoveFriendships(f ...*Friendship) *UserUpdateOne { + ids := make([]int, len(f)) + for i := range f { + ids[i] = f[i].ID + } + return uuo.RemoveFriendshipIDs(ids...) +} + // Select allows selecting one or more fields (columns) of the returned entity. // The default is selecting all fields defined in the entity schema. func (uuo *UserUpdateOne) Select(field string, fields ...string) *UserUpdateOne { @@ -660,6 +931,132 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if uuo.mutation.FriendsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2M, + Inverse: false, + Table: user.FriendsTable, + Columns: user.FriendsPrimaryKey, + Bidi: true, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: user.FieldID, + }, + }, + } + edge.Schema = uuo.schemaConfig.Friendship + createE := &FriendshipCreate{config: uuo.config, mutation: newFriendshipMutation(uuo.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := uuo.mutation.RemovedFriendsIDs(); len(nodes) > 0 && !uuo.mutation.FriendsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2M, + Inverse: false, + Table: user.FriendsTable, + Columns: user.FriendsPrimaryKey, + Bidi: true, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: user.FieldID, + }, + }, + } + edge.Schema = uuo.schemaConfig.Friendship + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + createE := &FriendshipCreate{config: uuo.config, mutation: newFriendshipMutation(uuo.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := uuo.mutation.FriendsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2M, + Inverse: false, + Table: user.FriendsTable, + Columns: user.FriendsPrimaryKey, + Bidi: true, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: user.FieldID, + }, + }, + } + edge.Schema = uuo.schemaConfig.Friendship + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + createE := &FriendshipCreate{config: uuo.config, mutation: newFriendshipMutation(uuo.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if uuo.mutation.FriendshipsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: user.FriendshipsTable, + Columns: []string{user.FriendshipsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: friendship.FieldID, + }, + }, + } + edge.Schema = uuo.schemaConfig.Friendship + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := uuo.mutation.RemovedFriendshipsIDs(); len(nodes) > 0 && !uuo.mutation.FriendshipsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: user.FriendshipsTable, + Columns: []string{user.FriendshipsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: friendship.FieldID, + }, + }, + } + edge.Schema = uuo.schemaConfig.Friendship + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := uuo.mutation.FriendshipsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: user.FriendshipsTable, + Columns: []string{user.FriendshipsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeInt, + Column: friendship.FieldID, + }, + }, + } + edge.Schema = uuo.schemaConfig.Friendship + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } _spec.Node.Schema = uuo.schemaConfig.User ctx = internal.NewSchemaConfigContext(ctx, uuo.schemaConfig) _spec.AddModifiers(uuo.modifiers...) diff --git a/entc/integration/multischema/multischema_test.go b/entc/integration/multischema/multischema_test.go index bbe9b6b3a..b9d58607d 100644 --- a/entc/integration/multischema/multischema_test.go +++ b/entc/integration/multischema/multischema_test.go @@ -11,6 +11,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/schema" "entgo.io/ent/entc/integration/multischema/ent" + "entgo.io/ent/entc/integration/multischema/ent/friendship" "entgo.io/ent/entc/integration/multischema/ent/group" "entgo.io/ent/entc/integration/multischema/ent/migrate" "entgo.io/ent/entc/integration/multischema/ent/pet" @@ -22,7 +23,7 @@ import ( ) func TestMySQL(t *testing.T) { - db, err := sql.Open("mysql", "root:pass@tcp(localhost:3308)/") + db, err := sql.Open("mysql", "root:pass@tcp(localhost:3308)/?parseTime=true") require.NoError(t, err) defer db.Close() ctx := context.Background() @@ -34,7 +35,7 @@ func TestMySQL(t *testing.T) { defer db.ExecContext(ctx, "DROP DATABASE IF EXISTS db2") // Default schema for the connection is db1. - db1, err := sql.Open("mysql", "root:pass@tcp(localhost:3308)/db1") + db1, err := sql.Open("mysql", "root:pass@tcp(localhost:3308)/db1?parseTime=true") require.NoError(t, err) defer db1.Close() @@ -47,9 +48,11 @@ func TestMySQL(t *testing.T) { // Pet: "db1", // User: "db1", - // The "groups" and "group_users" reside in external schema (db2). + // The "groups", "group_users" and "friendship" reside in external schema (db2). Group: "db2", GroupUsers: "db2", + // An edge with the "Through" definition is set on its edge-schema. + Friendship: "db2", } client := ent.NewClient(ent.Driver(db1), ent.AlternateSchema(cfg)) setupSchema(t, client, cfg) @@ -58,7 +61,7 @@ func TestMySQL(t *testing.T) { client.Group.Create().SetName("GitHub"), client.Group.Create().SetName("GitLab"), ).SaveX(ctx) - usr := client.User.Create().SetName("a8m").AddPets(pedro).AddGroups(groups...).SaveX(ctx) + a8m := client.User.Create().SetName("a8m").AddPets(pedro).AddGroups(groups...).SaveX(ctx) // Custom modifier with schema config. var names []struct { @@ -83,7 +86,7 @@ func TestMySQL(t *testing.T) { require.Equal(t, "Pedro", names[0].Pet) id := client.Group.Query(). - Where(group.HasUsersWith(user.ID(usr.ID))). + Where(group.HasUsersWith(user.ID(a8m.ID))). Limit(1). QueryUsers(). QueryPets(). @@ -118,6 +121,18 @@ func TestMySQL(t *testing.T) { require.Equal(t, client.User.Query().CountX(ctx), len(client.User.Query().AllX(ctx))) require.Equal(t, client.Pet.Query().CountX(ctx), len(client.Pet.Query().AllX(ctx))) + + nat := client.User.Create().SetName("nati").AddFriends(a8m).SaveX(ctx) + users := client.User.Query().WithFriends().WithFriendships().WithGroups().Order(ent.Asc(user.FieldName)).AllX(ctx) + require.Len(t, users, 2) + require.Equal(t, users[0].Name, a8m.Name) + require.Equal(t, users[1].Name, nat.Name) + require.Len(t, users[0].Edges.Groups, 1) + require.Len(t, users[1].Edges.Groups, 0) + require.Len(t, users[0].Edges.Friends, 1) + require.Len(t, users[1].Edges.Friends, 1) + require.Len(t, users[0].Edges.Friendships, 1) + require.Len(t, users[1].Edges.Friendships, 1) } func setupSchema(t *testing.T, client *ent.Client, cfg ent.SchemaConfig) { @@ -126,7 +141,7 @@ func setupSchema(t *testing.T, client *ent.Client, cfg ent.SchemaConfig) { migrate.WithForeignKeys(false), schema.WithDiffHook(func(next schema.Differ) schema.Differ { return schema.DiffFunc(func(current, desired *atlas.Schema) ([]atlas.Change, error) { - for tt, s := range map[string]string{group.Table: cfg.Group, group.UsersTable: cfg.GroupUsers} { + for tt, s := range map[string]string{group.Table: cfg.Group, group.UsersTable: cfg.GroupUsers, friendship.Table: cfg.Friendship} { t1, ok := desired.Table(tt) require.True(t, ok) t1.SetSchema(atlas.New(s))